Diagrama de color de 24 bits y diagrama de escala de grises de 8 bits
Primero, presentemos una imagen de color de 24 bits. En una imagen de color de 24 bits, cada píxel está representado por tres bytes, generalmente expresados como RGB. En general, muchas imágenes de color de 24 bits se almacenan como imágenes de 32 bits, y los bytes excesivos por píxel se almacenan como un valor alpha , que muestra información de influencia especial [1].
En el modelo RGB, si r = g = b, el color representa un color en escala de grises, donde el valor de r = g = b se llama valor en escala de grises. Por lo tanto, cada píxel de la imagen de la escala de grises requiere solo un byte para almacenar el valor de la escala de grises (también conocido como valor de intensidad y valor de brillo), y el rango de escala de grises es 0-255 [2]. Esto te da una imagen de la escala de grises de la imagen.
Varios métodos de escala de grises
1. Método de componentes: use uno de los tres componentes RGB como el valor de la escala de grises del mapa de escala de grises.
2. Método de mayor valor: use el valor máximo o mínimo de los tres componentes RGB como el valor de escala de grises del mapa de escala de grises.
3. Método medio: use el valor promedio de los tres componentes RGB como el valor de la escala de grises del gráfico en escala de grises.
4. Método de ponderación: debido a la diferente sensibilidad de color de los ojos humanos, el promedio ponderado de RGB tres componentes puede obtener una imagen de escala de grises más razonable. La situación general es la siguiente: y = 0.30R + 0.59g + 0.11b.
[Nota] El método de ponderación en realidad toma el valor de brillo de una imagen como el valor de la escala de grises para calcular, y usa el modelo YUV. En [3], encontrará que el autor usó y = 0.21 * r + 0.71 * g + 0.07 * b para calcular el valor de la escala de grises (obviamente, la suma de los tres pesos no es igual a 1, ¿cuál puede ser el error del autor?). De hecho, esta diferencia debe estar relacionada con si se usa la corrección de gamma [1].
Un método para implementar la escala de grises en Java
Si busca "Java implementa la escala de grises", la mayoría de ellos son un método (código):
public void grayImage () lanza IOException {archivo de archivo = nuevo archivo (system.getProperty ("user.dir")+"/test.jpg"); BufferedImage image = imageIO.read (archivo); int width = image.getWidth (); int hight = image.getheight (); BufferedImage GrayImage = new BufferedImage (ancho, altura, bufferedimage.type_byte_gray); for (int i = 0; i <width; i ++) {for (int j = 0; j <height; j ++) {int rgb = image.getRgb (i, j); GrayImage.SetRGB (I, J, RGB); }} Archivo newfile = new File (System.getProperty ("user.dir")+"/método1.jpg"); ImageIO.Write (GrayImage, "JPG", Newfile); }La imagen original de test.jpg es:
El diagrama de escala de grises obtenida utilizando el método anterior:
Ver esta imagen en escala de grises parece ser factible, pero si usamos opencv para lograr la escala de grises o usar PIL (Python), encontrará que los efectos varían mucho:
img = cv2.imread ('test.jpg', cv2.imread_color) gray = cv2.cvtcolor (img, cv2.color_bgr2gray) cv2.imwrite ('pythonmethod.jpg', gris) Se puede ver claramente que el gráfico de escala de grises obtenido usando opencv (lo mismo es cierto para PIL) es mucho mejor que el método obtenido por el método Java anterior, y se pueden ver muchos detalles. Esto muestra que este método popular en Internet siempre ha tenido algún problema, pero ha sido ignorado.
Cómo lograr la escala de grises en OpenCV
Si ha leído libros o códigos relacionados con opencv , probablemente pueda saber que opencv Grayscale utiliza el método de ponderación. La razón es que es más o menos porque no sabemos por qué las imágenes de escala de grises opencv son tan buenas. ¿Hay otros detalles de procesamiento que ignoremos?
Verificar nuestra suposición es muy simple. Simplemente verifique los cambios antes y después de que el valor de píxel esté atenuado. Puedes probarlo de la siguiente manera:
img = cv2.imread ('test.jpg', cv2.imread_color) h, w = img.shape [: 2] gray = cv2.cvtcolor (img, cv2.color_bgr2gray) para j en rango (w): para i en rango (h): imprim IMG [H-1] [W-1] [0: 3]Es difícil para nosotros juzgar tantos píxeles a continuación, pero solo necesitamos prestar atención al último punto de píxel y podemos encontrar pistas: el valor RGB del último punto de píxel en la imagen original es 44, 67, 89, y el valor después del aturdimiento es 71. Simplemente se ajusta al valor de escala de gris calculado por el método de ponderación. Si verifica los valores de píxeles de la imagen que estaba atenuada en Java antes, encontrará que no solo los valores de píxeles no cumplen con esta fórmula, sino que incluso están lejos de la otra.
En este punto, suponemos que OpenCV (incluida PIL) es una implementación de la escala de grises utilizando el método de ponderación.
Java implementa el método ponderado en escala de grises
Si ese método popular en Internet no funciona, ¿cómo debemos usar Java para lograr la escala de grises? De hecho, [3] ha logrado con éxito (múltiples métodos) a escala de grises (los amigos extranjeros siguen siendo muy poderosos en tecnología), y solo se extrae el código necesario aquí:
privado estático int colortorgb (int alfa, int rojo, int verde, int blue) {int newpixel = 0; newpixel += alfa; newpixel = newpixel << 8; newpixel += rojo; newpixel = newpixel << 8; newpixel += verde; newpixel = newpixel << 8; newpixel += azul; devolver Newpixel; } public static void main (string [] args) lanza IOException {bufferedImage bufferedImage = imageIO.read (nuevo archivo (system.getProperty ("user.dir" + "/test.jpg"); bufferedImage GrayImage = new BufferEdimage (bufferedImage.getWidTh (), buffedeMage); (int i = 0; i <bufferedImage.getWidth (); i ++) {para (int j = 0; j <bufferedImage.gethEdight (); j ++) {final int color = bufferedImage.getRgb (i, j) (0.3 * R + 0.59 * G + 0.11 * b); "/ok.jpg"); El código anterior imprimirá los valores de píxeles a escala de grises. Si los compara con el código Python anterior, encontrará que los valores de píxeles son completamente correspondientes. El método colorToRGB maneja el diagrama de color exactamente 4 bytes, uno de los cuales es el parámetro alpha (como se mencionó anteriormente). La siguiente figura es la imagen en escala de grises de este código:
Para otros métodos, se puede obtener a su vez lo mismo.
Resumir
La razón de este artículo es usar Java para implementar varias operaciones en escala de grises y usar OpenCV para verificar lo correcto o incorrecto de la conversión. Sin embargo, se encontraron algunos problemas en las pruebas reales (hay diferencias en las imágenes convertidas y cómo generar imágenes en escala de grises basadas en los valores de la escala de grises después de la conversión), y se hicieron algunos pensamientos y verificaciones sobre esto. Cabe señalar aquí que algunos artículos en Internet han hecho más o menos pensando más (y muchos de ellos incluso se copian, especialmente artículos nacionales), y para estos problemas prácticos, la implementación práctica y la verificación son un método muy importante. Espero que el contenido de este artículo sea útil para todos. Si tiene alguna pregunta, deje un mensaje para discutir.