Algoritmo di riduzione degli occhi rossi
-
02-07-2019 - |
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?
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
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