Domanda

Devo implementare la riduzione dell'effetto occhi rossi per un'applicazione su cui sto lavorando.

Google offre principalmente collegamenti a prodotti commerciali per utenti finali.

Conosci un buon algoritmo di riduzione dell'effetto occhi rossi, che potrebbe essere utilizzato in un'applicazione GPL?

È stato utile?

Soluzione

Sono in ritardo alla festa qui, ma per i futuri ricercatori ho usato il seguente algoritmo per un'app personale che ho scritto.

Prima di tutto, la regione da ridurre viene selezionata dall'utente e passata al metodo di riduzione degli occhi rossi come punto centrale e raggio. Il metodo scorre attraverso ogni pixel all'interno del raggio ed esegue il seguente calcolo:

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

Mi piacciono molto i risultati perché mantengono l'intensità del colore, il che significa che il riflesso della luce dell'occhio non è ridotto. (Questo significa che gli occhi mantengono il loro aspetto "vivo")

Altri suggerimenti

una grande biblioteca per trovare gli occhi è openCV . è molto ricco di funzioni di elaborazione delle immagini. vedi anche questo documento con il titolo " Rilevamento automatico occhi rossi " da Ilia V. Safonov.

Per prima cosa devi trovare gli occhi! Il modo standard sarebbe quello di eseguire un rilevatore di bordi e quindi una trasformazione di Hough per trovare due cerchi della stessa dimensione, ma potrebbero esserci algoritmi più semplici per trovare semplicemente gruppi di pixel rossi.

Quindi devi decidere con cosa sostituirli, supponendo che ci siano abbastanza dati verde / blu nell'immagine che potresti semplicemente ignorare il canale rosso.

OpenCV è un'ottima libreria gratuita per l'elaborazione delle immagini, potrebbe essere eccessiva per quello che vuoi - ma ha molti esempi e una comunità molto attiva. Puoi anche cercare algoritmi di tracciamento degli oggetti, il tracciamento di un oggetto colorato in una scena è un problema molto simile e comune.

Se nessun altro fornisce una risposta più diretta, puoi sempre scaricare il codice sorgente di GIMP e guarda come lo fanno.

L'algoritmo più semplice, e comunque molto efficace, sarebbe di azzerare la R della tripla RGB per la regione di interesse.

Il rosso scompare, ma gli altri colori vengono conservati.

Un'ulteriore estensione di questo algoritmo potrebbe comportare l'azzeramento del valore R solo per le triple il cui colore dominante è il rosso (R > G e R > B).

Puoi provare imagemagick - alcuni suggerimenti su questa pagina per come farlo

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

cerca l'effetto occhi rossi sulla pagina

Il progetto open source Paint.NET ha un'implementazione in C #.

Ecco la soluzione di implementazione 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());
            }


        }
    }
}

Essendo i parametri recuperati da due rettangoli rilevati da un'applicazione come open cv (questo dovrebbe essere un rettangolo che coinvolge la posizione dell'occhio)

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

Questa è un'implementazione più completa della risposta fornita da 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;
  }

Leggi questo blog, c'è una bella spiegazione per quanto riguarda il rilevamento e la correzione dell'effetto occhi rossi. Correzione dell'effetto occhi rossi con OpenCV e python

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top