2008-09-25 9 views
40

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

Google proporciona en su mayoría enlaces a productos comerciales para el usuario final.

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

Respuesta

43

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

Primero que nada, la región a reducir es seleccionada por el usuario y pasada al método de reducción de ojos rojos como punto central y radio. El método de bucle a través de cada píxel dentro del radio y hace 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)); 
} 

me gusta mucho los resultados de este, ya que mantener la intensidad del color, lo que significa que la reflexión de la luz del ojo no se reduce. (Esto significa que los ojos mantienen su aspecto "vivo").)

+0

También puede usar una herramienta de selección de "varita mágica" en el punto de clic con un radio máximo proporcionado por el usuario. – rafaelcastrocouto

3

El algoritmo más simple, y aún uno que es muy efectivo sería poner a cero la R del triple 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).

4

Si nadie más viene con una respuesta más directa, siempre puede descargar the source code for GIMP y ver cómo lo hacen.

6

En primer lugar es necesario encontrar los ojos! La forma estándar sería ejecutar un detector de bordes y luego una transformada Hough para encontrar dos círculos del mismo tamaño, pero podría haber algoritmos más simples para encontrar simplemente grupos de píxeles rojos.

Luego debe decidir con qué reemplazarlos, suponiendo que hay suficientes datos verdes/azules en la imagen, simplemente podría ignorar el canal rojo.

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

3

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

+0

No creo que la fuente sea alcanzable más. –

7

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

2

Aquí está la solución de aplicación 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 (esto debería ser un rectángulo que implica la posición de los ojos)

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); 
1

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; 
    } 
Cuestiones relacionadas