Diagrama de cores de 24 bits e diagrama de escala de cinza de 8 bits
Primeiro, vamos introduzir uma imagem colorida de 24 bits. Em uma imagem colorida de 24 bits, cada pixel é representado por três bytes, geralmente expressos como RGB. Geralmente, muitas imagens coloridas de 24 bits são armazenadas como imagens de 32 bits, e o excesso de bytes por pixels são armazenados como um valor alpha , mostrando informações especiais sobre influência [1].
No modelo RGB, se r = g = b, a cor representa uma cor em escala de cinza, onde o valor de r = g = b é chamado de valor em escala de cinza. Portanto, cada pixel da imagem em escala de cinza requer apenas um byte para armazenar o valor em escala de cinza (também conhecido como valor de intensidade e valor de brilho), e o intervalo de escala de cinza é 0-255 [2]. Isso oferece uma imagem em escala de cinza da imagem.
Vários métodos de escala de cinza
1. Método do componente: Use um dos três componentes RGB como o valor em escala de cinza do mapa em escala de cinza.
2. Método da maioria do valor: use o valor máximo ou mínimo dos três componentes RGB como o valor em escala de cinza do mapa em escala de cinza.
3. Método médio: use o valor médio dos três componentes RGB como o valor em escala de cinza do gráfico em escala de cinza.
4. Método de ponderação: Devido à diferente sensibilidade da cor dos olhos humanos, a média ponderada dos três componentes RGB pode obter uma imagem de escala de cinza mais razoável. A situação geral é a seguinte: y = 0,30r + 0,59g + 0,11b.
[Nota] O método de ponderação realmente assume o valor de brilho de uma imagem como valor em escala de cinza para calcular e usa o modelo YUV. Em [3], você descobrirá que o autor usou y = 0,21 * r + 0,71 * g + 0,07 * b para calcular o valor em escala de cinza (obviamente a soma dos três pesos não é igual a 1, que pode ser o erro do autor?). De fato, essa diferença deve estar relacionada a se a correção gama é usada [1].
Um método para implementar cinza em Java
Se você procurar "Java implementa a escala de cinza", a maioria deles é um método (código):
public void GrayImage () lança IoException {arquivo file = new File (System.getProperty ("user.dir")+"/test.jpg"); BufferImage imagem = imageio.read (arquivo); int width = image.getWidth (); int height = image.getHeight (); BufferImage GrayImage = new bufferImage (largura, altura, bufferImage.type_byte_gray); for (int i = 0; i <largura; i ++) {for (int j = 0; j <altura; j ++) {int rgb = image.getRgb (i, j); GrayImage.SetRGB (i, j, rgb); }} Arquivo newFile = new File (System.getProperty ("user.dir")+"/method1.jpg"); Imageio.write (GrayImage, "jpg", newfile); }A imagem original do test.jpg é:
O diagrama de escala de cinza obtido usando o método acima:
Ver essa imagem em escala de cinza parece ser viável, mas se usarmos opencv para obter escala de cinza ou usar o PIL (Python), você descobrirá que os efeitos variam muito:
img = cv2.imread ('test.jpg', cv2.imread_color) Gray = cv2.cvtcolor (img, cv2.color_bgr2gray) cv2.imwrite ('pythonmethod.jpg', cinza) Pode -se ver claramente que o gráfico em escala de cinza obtido usando opencv (o mesmo é verdadeiro para PIL) é muito melhor do que o método obtido pelo método Java acima, e muitos detalhes podem ser vistos. Isso mostra que esse método popular na Internet sempre teve algum problema, mas foi ignorado.
Como alcançar a escala de cinza no OpenCV
Se você leu livros ou códigos relacionados ao opencv , provavelmente poderá saber que opencv Graycale usa o método de ponderação. O motivo é aproximadamente porque não sabemos por que as imagens de escala de cinza opencv são tão boas. Existem outros detalhes de processamento que ignoramos?
Verificar nosso palpite é muito simples. Basta verificar as alterações antes e depois que o valor do pixel está acinzentado. Você pode testá -lo da seguinte maneira:
img = cv2.Imread ('test.jpg', cv2.imread_color) h, w = img.shape [: 2] cinza = cv2.cvtcolor (img, cv2.color_bgr2gray) para j em range (w): para i in range (h): str (i) + "" " IMG [H-1] [W-1] [0: 3]É difícil para nós julgar tantos pixels abaixo, mas precisamos apenas prestar atenção ao último ponto de pixel e podemos encontrar pistas: o valor RGB do último ponto de pixel na imagem original é de 44, 67, 89 e o valor após o cinza é 71. Ele apenas se encaixa no valor da escala de cinza calculada pelo método de ponderação. Se você verificar os valores de pixel da imagem que estava acinzentada em Java antes, você descobrirá que não apenas os valores de pixel não atendem a essa fórmula, mas também estão longe um do outro.
Neste ponto, achamos que o OpenCV (incluindo o PIL) é uma implementação em escala de cinza usando o método de ponderação.
Java implementa o método ponderado em escala de cinza
Se esse método popular na Internet não funcionar, como devemos usar o Java para alcançar a escala de cinza? De fato, [3] alcançou com sucesso (vários métodos) em escala de cinza (amigos estrangeiros ainda são muito poderosos em tecnologia) e apenas o código necessário é extraído aqui:
private static int colortorgb (int alpha, int vermelho, int verde, int azul) {int newPixel = 0; newpixel += alfa; newpixel = newPixel << 8; newpixel += vermelho; newpixel = newPixel << 8; newpixel += verde; newpixel = newPixel << 8; newpixel += azul; retornar newpixel; } public static void main (string [] args) lança IoException {bufferImage bufferImage = imageio.read (novo arquivo (system.getProperty ("user.dir" + "/test.jpg"); bufferiMage grayImage = newredImage (bufferImage.GeRDEg (); bufferImageMage. (int i = 0; i <bufferImage.getwidth (); i ++) {for (int j = 0; (0,3 * r + 0,59 * g + 0,11 * b);; "/ok.jpg"); O código acima imprimirá os valores de pixel em escala acinzentada. Se você os comparar com o código Python acima, descobrirá que os valores de pixels são completamente correspondentes. O método colorToRGB lida com o diagrama de cores exatamente 4 bytes, um dos quais é o parâmetro alpha (como mencionado anteriormente). A figura a seguir é a imagem em escala de cinza deste código:
Para outros métodos, o mesmo pode ser obtido por sua vez.
Resumir
O motivo deste artigo é usar o Java para implementar várias operações em escala de cinza e usar o OpenCV para verificar o direito ou o errado da conversão. No entanto, alguns problemas foram encontrados em testes reais (existem diferenças nas imagens convertidas e como gerar imagens em escala de cinza com base nos valores de escala de cinza após a conversão), e alguns pensamentos e verificações foram feitos sobre isso. Deve-se notar aqui que alguns artigos na Internet têm mais ou menos pensamentos adicionais (e muitos deles são copiados, especialmente artigos domésticos) e, para essas questões práticas, a implementação e a verificação práticas são um método muito importante. Espero que o conteúdo deste artigo seja útil para todos. Se você tiver alguma dúvida, deixe uma mensagem para discutir.