2009-12-09 19 views
9

Estoy escaneando documentos a imágenes JPG. El escáner debe escanear todas las páginas en color o todas las páginas en blanco y negro. Como muchas de mis páginas son de color, debo escanear todas las páginas como color. Después de completar el escaneo, me gustaría examinar las imágenes con .Net y tratar de detectar qué imágenes son en blanco y negro para que pueda convertir esas imágenes a escala de grises y ahorrar en almacenamiento.Detectando imágenes en escala de grises con .Net

¿Alguien sabe cómo detectar una imagen en escala de grises con .Net?

Háganme saber.

+1

La comprobación del tipo de imagen no va a cortar, ya que se configurará para 24 o 32 bits (ya que está escaneando en color). Probablemente tendrá que verificar cada píxel; si R == G == B en todos los píxeles, se trata de una imagen en escala de grises; de lo contrario, probablemente sea el color. –

+1

Una idea: a pesar de que el escáner en teoría proporciona R == G == B, ¿es posible que durante la compresión JPEG haya algunos píxeles en los que eso sea casi cierto? Considere, JPEG es un algoritmo de compresión con pérdida. Quizás JPEG se tome algunas libertades con los colores de píxel cercanos. Pero lo confieso, no soy un experto en JPEG. Pero me gustaría saber cómo funcionó antes de confiar en R == G == B. –

+0

Sí, odiaría confiar exactamente en r == g == b, porque incluso si jpg no hace ningún truco (y apuesto a que sí), su escáner y original también deberían ser perfectos, lo que me parece poco probable en muchos casos. – Beska

Respuesta

5

Un algoritmo simple para probar el color: recorra la imagen píxel por píxel en un bucle anidado (ancho y alto) y pruebe para ver si los valores RGB del píxel son iguales. Si no lo están, la imagen tiene información de color. Si recorre todos los píxeles sin encontrar esta condición, entonces tiene una imagen en escala de grises.

Revisión con un algoritmo más complejo:

En el primer rev de este post me propuso un algoritmo simple que asume que los píxeles son escala de grises si RGB de cada píxel son valores son iguales. Por lo tanto, los valores RGB de 0,0,0 o 128,128,128 o 230,230,230 serían todos de color gris, mientras que 123,90,78 no. Sencillo.

Aquí hay un fragmento de código que prueba una variación del gris. Los dos métodos son una pequeña subsección de un proceso más complejo pero deberían proporcionar suficiente código sin formato para ayudar con la pregunta original.

/// <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

Algunos escáneres introducirán un poco de color en las imágenes en blanco y negro. Debe permitir un pequeño umbral para que los colores no sean exactamente iguales. – Andres

+0

¿No se consideraría una imagen con valores RGB de 128,128,128 en TODOS los píxeles como una imagen rectangular gris (de un solo color)? – chrischu

+0

@crischu: Bueno, creo que fue solo un ejemplo de cómo todos los valores serían iguales. – Beska

14

Si no puede encontrar una biblioteca de esto, se podría tratar de agarrar un gran número (o todos) de los píxeles de una imagen y ver si sus R, G, y B son los valores dentro de un cierto umbral (que puede establecer empíricamente, o tener como configuración) el uno del otro. Si lo son, la imagen es en escala de grises.

sin duda haría el umbral para una prueba un poco más grande que 0, aunque ... así que no pondría a prueba r = g, por ejemplo, pero (abs (rg) < e) donde e es el umbral . De esa manera puede mantener sus falsos positivos de color ... ya que sospecho que de lo contrario obtendrá un número decente, a menos que su imagen original y técnicas de escaneo den precisamente en escala de grises.

+0

+1, especialmente para la sugerencia de umbral. –

+0

Alguien lo rechazó injustamente sin hacer comentarios. Tsk tsk. –

+0

Sí ... sucede. Triste, pero * encogimiento de hombros *. – Beska

0

Como JPEG tiene soporte para metadatos, primero debe comprobar si el software del escáner coloca algunos datos especiales en las imágenes guardadas y si puede confiar en esa información.

+0

Esto no tiene sentido para mí. El software del escáner, si escribe metadatos en el archivo, escribirá que la imagen es una imagen en color si se escanea como color (lo cual es), incluso si la imagen solo contiene contenido en escala de grises. – Beska

+0

Fue una idea y señalé validar estos datos hipotéticos, beska. De todos modos, ty para tu comentario. –

0

El answer I posted in the python section puede ser útil. Imágenes que encuentras, p. en la web que un ser humano consideraría escala de grises a menudo no tienen valores R, G, B idénticos. Necesita algún cálculo de la varianza y algún tipo de proceso de muestreo para que no tenga que verificar un millón de píxeles. La solución que dio Paul se basa en la diferencia máxima, por lo que un único artefacto de píxel rojo de un escáner podría convertir una imagen en escala de grises en una escala no en escala de grises. La solución que publiqué obtuvo un 99.1% de precisión y un 92.5% de recuperación en 13,000 imágenes.

1

Una versión más rápida. Prueba con un umbral de 8. Trabajar bien para mi uso

:

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

¿Tiene una más rápida?

+0

¿Está tratando de responder o hacer una pregunta? Por favor, claro! – Samer

0

Creo que este enfoque debe requerir el menor código, se ha probado en jpegs. bLa imagen siguiente es una matriz de bytes.

MemoryStream ms = new MemoryStream(bImage); 
System.Drawing.Image returnImage = System.Drawing.Image.FromStream(ms); 
if (returnImage.Palette.Flags == 2) 
{ 
     System.Diagnostics.Debug.WriteLine("Image is greyscale"); 
} 
Cuestiones relacionadas