2008-09-25 8 views
40

Je dois appliquer la réduction des yeux rouges pour une application sur laquelle je travaille. Googling fournit principalement des liens vers des produits commerciaux pour les utilisateurs finaux.Algorithme de réduction des yeux rouges

Connaissez-vous un bon algorithme de réduction des yeux rouges, qui pourrait être utilisé dans une application GPL?

Répondre

43

Je suis très en retard à la fête ici, mais pour les futurs chercheurs, j'ai utilisé l'algorithme suivant pour une application personnelle que j'ai écrite. Tout d'abord, la zone à réduire est sélectionnée par l'utilisateur et transmise à la méthode de réduction des yeux rouges en tant que point central et rayon. La méthode des boucles à travers chaque pixel dans le rayon et fait le calcul suivant:

//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)); 
} 

Je aime vraiment les résultats de cela parce qu'ils gardent l'intensité des couleurs, ce qui signifie que la réflexion de la lumière de l'œil ne se réduit pas. (Cela signifie que les yeux gardent leur apparence «vivante».)

+0

Vous pouvez également utiliser un outil de sélection "baguette magique" au point de clic avec un rayon maximum fourni par l'utilisateur. – rafaelcastrocouto

3

L'algorithme le plus simple, et encore celui qui est très efficace serait de mettre à zéro le R du triplet RGB pour la région d'intérêt.

Le rouge disparaît, mais les autres couleurs sont conservées.

Une autre extension de cet algorithme pourrait impliquer la mise à zéro de la valeur R pour seulement les triplets où le rouge est la couleur dominante (R> G et R> B).

4

Si personne d'autre ne trouve une réponse plus directe, vous pouvez toujours télécharger the source code for GIMP et voir comment ils le font.

6

Tout d'abord vous devez trouver les yeux! La méthode standard serait d'exécuter un détecteur de bord et ensuite une transformation de Hough pour trouver deux cercles de la même taille, mais il pourrait y avoir des algorithmes plus simples pour trouver simplement des groupes de pixels rouges.

Ensuite, vous devez décider avec quoi les remplacer, en supposant qu'il y ait suffisamment de données vert/bleu dans l'image, vous pouvez simplement ignorer le canal rouge. OpenCV est une très bonne bibliothèque gratuite pour le traitement d'image, elle est peut-être exagérée pour ce que vous voulez - mais elle a beaucoup d'exemples et une communauté très active. Vous pouvez également rechercher des algorithmes de suivi d'objet, le suivi d'un objet coloré dans une scène est un problème très similaire et commun.

3

Le projet open source Paint.NET a une implémentation en C#.

+0

Je ne pense pas que la source soit plus accessible. –

7

une grande bibliothèque pour trouver des yeux est openCV. il est très riche avec les fonctions de traitement d'image. voir aussi this papier avec le titre "Détection automatique des yeux rouges" de Ilia V. Safonov.

2

Voici la solution d'implémentation 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()); 
      } 


     } 
    } 
} 

étant les paramètres récupérés à partir de deux rectangles détectés par une application comme cv ouvert (ce qui devrait être un rectangle impliquant la position des yeux)

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

Ceci est une implémentation plus complète de la réponse fournie par 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; 
    }