Pregunta

Necesito implementar la reducción de ojos rojos para una aplicación en la que estoy trabajando.

El uso de Google en su mayoría proporciona enlaces a productos comerciales para usuarios finales.

¿Conoces un buen algoritmo de reducción de ojos rojos, que podría usarse en una aplicación GPL?

¿Fue útil?

Solución

Llego tarde a la fiesta aquí, pero para los futuros buscadores he usado el siguiente algoritmo para una aplicación personal que escribí.

En primer lugar, el usuario selecciona la región a reducir y la pasa al método de reducción de ojos rojos como punto central y radio. El método recorre cada píxel dentro del radio y realiza el siguiente cálculo:

//Value of red divided by average of blue and green:
Pixel pixel = image.getPixel(x,y);
float redIntensity = ((float)pixel.R / ((pixel.G + pixel.B) / 2));
if (redIntensity > 1.5f)  // 1.5 because it gives the best results
{
    // reduce red to the average of blue and green
    bm.SetPixel(i, j, Color.FromArgb((pixel.G + pixel.B) / 2, pixel.G, pixel.B));
}

Realmente me gustan los resultados de esto porque mantienen la intensidad del color, lo que significa que el reflejo de la luz del ojo no se reduce. (Esto significa que los ojos mantienen su aspecto "vivo").

Otros consejos

una gran biblioteca para encontrar ojos es openCV . Es muy rico en funciones de procesamiento de imágenes. vea también este papel con el título " Detección automática de ojos rojos " de Ilia V. Safonov.

¡Primero necesitas encontrar los ojos! La forma estándar sería ejecutar un detector de bordes y luego una transformación de Hough para encontrar dos círculos del mismo tamaño, pero podría haber algoritmos más sencillos para encontrar simplemente grupos de píxeles rojos.

Luego debes decidir con qué reemplazarlos, asumiendo que hay suficientes datos en verde / azul en la imagen, simplemente puedes ignorar el canal rojo.

OpenCV es una muy buena biblioteca gratuita para el procesamiento de imágenes, podría ser una exageración para lo que quieres, pero tiene muchos ejemplos y una comunidad muy activa. También puede buscar algoritmos de seguimiento de objetos, el seguimiento de un objeto de color en una escena es un problema muy similar y común.

Si a nadie más se le ocurre una respuesta más directa, siempre puede descargar el código fuente de GIMP y vea cómo lo hacen.

El algoritmo más simple, y aún uno que es muy efectivo, sería poner a cero la R del triple de RGB para la región de interés.

El rojo desaparece, pero los otros colores se conservan.

Una extensión adicional de este algoritmo podría implicar poner a cero el valor R solo para los triples donde el rojo es el color dominante (R > G y R > B).

Puedes probar imagemagick: algunos consejos en esta página sobre cómo hacerlo

http://www.cit.gu. edu.au/~anthony/info/graphics/imagemagick.hints

busca los ojos rojos en la página

El proyecto de código abierto Paint.NET tiene una implementación en C #.

Aquí está la solución de implementación de Java

public void corrigirRedEye(int posStartX, int maxX, int posStartY, int maxY, BufferedImage image) {
    for(int x = posStartX; x < maxX; x++) {
        for(int y = posStartY; y < maxY; y++) {

            int c = image.getRGB(x,y);
            int  red = (c & 0x00ff0000) >> 16;
            int  green = (c & 0x0000ff00) >> 8;
            int  blue = c & 0x000000ff;

            float redIntensity = ((float)red / ((green + blue) / 2));
            if (redIntensity > 2.2) {
                Color newColor = new Color(90, green, blue);
                image.setRGB(x, y, newColor.getRGB());
            }


        }
    }
}

Siendo los parámetros recuperados de dos rectángulos detectados por una aplicación como cv abierto (debería ser un rectángulo que involucra la posición del ojo)

int posStartY = (int) leftEye.getY();

    int maxX = (int) (leftEye.getX() + leftEye.getWidth());
    int maxY = (int) (leftEye.getY() + leftEye.getHeight());

    this.corrigirRedEye(posStartX, maxX, posStartY, maxY, image);

    // right eye

    posStartX = (int) rightEye.getX();
    posStartY = (int) rightEye.getY();

    maxX = (int) (rightEye.getX() + rightEye.getWidth());
    maxY = (int) (rightEye.getY() + rightEye.getHeight());

    this.corrigirRedEye(posStartX, maxX, posStartY, maxY, image);

Esta es una implementación más completa de la respuesta proporcionada por Benry:

  using SD = System.Drawing;

  public static SD.Image ReduceRedEye(SD.Image img, SD.Rectangle eyesRect)
  {
     if (   (eyesRect.Height > 0)
         && (eyesRect.Width > 0)) {
        SD.Bitmap bmpImage = new SD.Bitmap(img);
        for (int x=eyesRect.X;x<(eyesRect.X+eyesRect.Width);x++) {
           for (int y=eyesRect.Y;y<(eyesRect.Y+eyesRect.Height);y++) {
              //Value of red divided by average of blue and green:
              SD.Color pixel = bmpImage.GetPixel(x,y);
              float redIntensity = ((float)pixel.R / ((pixel.G + pixel.B) / 2));
              if (redIntensity > 2.2f)
              {
                 // reduce red to the average of blue and green
                 bmpImage.SetPixel(x, y, SD.Color.FromArgb((pixel.G + pixel.B) / 2, pixel.G, pixel.B));
                 pixel = bmpImage.GetPixel(x,y); // for debug
              }
           }
        }
        return (SD.Image)(bmpImage);
     }
     return null;
  }

Lea este blog, hay una buena explicación sobre la detección y corrección de ojos rojos. Corrección de ojos rojos con OpenCV y python

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top