2009-12-09 19 views
9

Sto analizzando i documenti in immagini JPG. Lo scanner deve eseguire la scansione di tutte le pagine come colore o tutte le pagine in bianco e nero. Poiché molte delle mie pagine sono a colori, devo eseguire la scansione di tutte le pagine come colore. Una volta completata la scansione, vorrei esaminare le immagini con .Net e provare a rilevare quali immagini sono in bianco e nero in modo da poter convertire tali immagini in scala di grigi e salvare in memoria.Rilevamento delle immagini in scala di grigi con .Net

Qualcuno sa come rilevare un'immagine in scala di grigi con .Net?

Per favore fatemi sapere.

+1

Il controllo del tipo di immagine non ha intenzione di tagliarlo poiché sarà impostato su 24 o 32 bit (poiché la scansione è a colori). Probabilmente dovrai controllare ciascun pixel; se R == G == B in tutti i pixel, è un'immagine in scala di grigi, altrimenti è probabilmente il colore. –

+1

Un pensiero: anche se lo scanner in teoria sta fornendo R == G == B, è possibile che durante la compressione JPEG ci possono essere alcuni pixel in cui questo è solo quasi vero? Considerare, JPEG è un algoritmo di compressione con perdita. Forse JPEG prende alcune libertà con i colori dei pixel nelle vicinanze. Ma confesso, non sono un esperto di JPEG. Ma io vorrei sapere come funzionava prima che mi sono affidato a R == == G B. –

+0

Sì, non vorrei contare su esattamente r == g == b perché anche se jpg non fa alcuna fudging (e scommetto che lo faccia), lo scanner e l'originale dovrebbero essere perfetti, il che mi sembra improbabile in molti casi. – Beska

risposta

5

Un semplice algoritmo per verificare il colore: Cammina l'immagine pixel per pixel in un ciclo annidato per larghezza e altezza e verifica se i valori RGB del pixel sono uguali. Se non lo sono, l'immagine ha informazioni sul colore. Se lo fai completamente attraverso tutti i pixel senza incontrare questa condizione, allora hai un'immagine in scala di grigi.

Revisione con un algoritmo più complesso:

Nel primo giro di questo post ho proposto un semplice algoritmo che presuppone che i pixel sono scala di grigi se RGB di ciascun pixel sono valori sono uguali. Quindi RGBs di 0,0,0 o 128,128,128 o 230,230,230 verrebbero tutti testati come grigio mentre 123,90,78 non lo farebbero. Semplice.

Ecco uno snippet di codice che verifica una varianza dal grigio. I due metodi sono una piccola sottosezione di un processo più complesso ma dovrebbero fornire abbastanza codice raw per aiutare con la domanda originale.

/// <summary> 
/// This function accepts a bitmap and then performs a delta 
/// comparison on all the pixels to find the highest delta 
/// color in the image. This calculation only works for images 
/// which have a field of similar color and some grayscale or 
/// near-grayscale outlines. The result ought to be that the 
/// calculated color is a sample of the "field". From this we 
/// can infer which color in the image actualy represents a 
/// contiguous field in which we're interested. 
/// See the documentation of GetRgbDelta for more information. 
/// </summary> 
/// <param name="bmp">A bitmap for sampling</param> 
/// <returns>The highest delta color</returns> 
public static Color CalculateColorKey(Bitmap bmp) 
{ 
    Color keyColor = Color.Empty; 
    int highestRgbDelta = 0; 

    for (int x = 0; x < bmp.Width; x++) 
    { 
     for (int y = 0; y < bmp.Height; y++) 
     { 
      if (GetRgbDelta(bmp.GetPixel(x, y)) <= highestRgbDelta) continue; 

      highestRgbDelta = GetRgbDelta(bmp.GetPixel(x, y)); 
      keyColor = bmp.GetPixel(x, y); 
     } 
    } 

    return keyColor; 
} 

/// <summary> 
/// Utility method that encapsulates the RGB Delta calculation: 
/// delta = abs(R-G) + abs(G-B) + abs(B-R) 
/// So, between the color RGB(50,100,50) and RGB(128,128,128) 
/// The first would be the higher delta with a value of 100 as compared 
/// to the secong color which, being grayscale, would have a delta of 0 
/// </summary> 
/// <param name="color">The color for which to calculate the delta</param> 
/// <returns>An integer in the range 0 to 510 indicating the difference 
/// in the RGB values that comprise the color</returns> 
private static int GetRgbDelta(Color color) 
{ 
    return 
     Math.Abs(color.R - color.G) + 
     Math.Abs(color.G - color.B) + 
     Math.Abs(color.B - color.R); 
} 
+0

Alcuni scanner introdurranno un po 'di colore in immagini altrimenti in bianco e nero. Si dovrebbe consentire una soglia piccola per i colori non essere abbastanza uguale. – Andres

+0

Un'immagine con i valori RGB di 128,128,128 su TUTTI i pixel non dovrebbe essere considerata solo un'immagine rettangolare (a un colore) rettangolare? – chrischu

+0

@crischu: Beh, penso che sia stato solo un esempio di mostrare come tutti i valori sarebbero uguali. – Beska

14

Se non riesci a trovare una libreria per questo, si potrebbe provare afferrare un gran numero (o tutti) dei pixel per l'immagine e vedere se le loro R, G, B e valori sono entro un certo soglia (che potresti impostare empiricamente o avere come impostazione) l'una dell'altra. Se lo sono, l'immagine è in scala di grigi.

Definirei la soglia per un test un po 'più grande di 0, anche se ... quindi non testerei r = g, ad esempio, ma (abs (rg) < e) dove e è la soglia . In questo modo puoi mantenere bassi i tuoi falsi positivi di colore ... come sospetto che altrimenti otterrai un numero decente, a meno che l'immagine originale e le tecniche di scansione non diano esattamente in scala di grigi allo .

+0

+1, soprattutto per il suggerimento di soglia. –

+0

Qualcuno ha ingiustamente svalutato senza commentare. Tsk tsk. –

+0

Sì ... succede. Triste, ma * scrollando le spalle *. – Beska

0

Poiché JPEG supporta i metadati, è necessario innanzitutto verificare se il software dello scanner inserisce alcuni dati speciali sulle immagini salvate e se è possibile fare affidamento su tali informazioni.

+0

Questo non ha senso per me. Il software dello scanner, se scrive i metadati nel file, scriverà che l'immagine è un'immagine a colori se viene scansionata come colore (che è), anche se l'immagine contiene solo contenuto in scala di grigi. – Beska

+0

Era un'idea e ho fatto notare per convalidare questi dati ipotetici, beska. Comunque, per il tuo commento. –

0

Il answer I posted in the python section potrebbe essere utile. Immagini che trovi ad es. sul web che un essere umano considererebbe la scala di grigi spesso non hanno valori R, G, B identici. Hai bisogno di un calcolo della varianza e qualche tipo di processo di campionamento in modo da non dover controllare un milione di pixel. La soluzione fornita da Paul si basa sulla massima differenza, quindi un singolo artefatto di pixel rossi da uno scanner potrebbe trasformare un'immagine in scala di grigi in non-scala di grigi. La soluzione che ho postato ha ottenuto una precisione del 99,1% e un richiamo del 92,5% su 13.000 immagini.

1

Una versione più veloce. Prova con una soglia di 8. funzionare bene per il mio

Usa:

bool grayScale; 
Bitmap bmp = new Bitmap(strPath + "\\temp.png"); 
grayScale = TestGrayScale(bmp, 8); 
if (grayScale) 
    MessageBox.Show("Grayscale image"); 


/// <summary>Test a image is in grayscale</summary> 
/// <param name="bmp">The bmp to test</param> 
/// <param name="threshold">The threshold for maximun color difference</param> 
/// <returns>True if is grayscale. False if is color image</returns> 
public bool TestGrayScale(Bitmap bmp, int threshold) 
{ 
    Color pixelColor = Color.Empty; 
    int rgbDelta; 

    for (int x = 0; x < bmp.Width; x++) 
    { 
     for (int y = 0; y < bmp.Height; y++) 
     { 
      pixelColor = bmp.GetPixel(x, y); 
      rgbDelta = Math.Abs(pixelColor.R - pixelColor.G) + Math.Abs(pixelColor.G - pixelColor.B) + Math.Abs(pixelColor.B - pixelColor.R); 
      if (rgbDelta > threshold) return false; 
     } 
    } 
    return true; 
} 

Hai un uno più veloce?

+0

Stai cercando di rispondere o fare una domanda. Per favore sii chiaro! – Samer

0

Penso che questo approccio dovrebbe richiedere il codice minimo, è stato testato su jpegs. bImmagine sotto è una matrice di byte.

Problemi correlati