Olá estive lendo alguns tópicos daqui e me deparei com um trecho que me ajudou bastante no desenvolvimento de uma rotina que trabalha com imagens…
A minha rotina seria o seguinte…
Tenho uma determinada imagem e presciso que o programa localize , por exemplo todos os tons de cinza e branco e substitua por uma outra cor qualquer…verde por exemplo…
o código que me ajudou me exclareceu algumas dúvidas seria este…
try {
// obtenho uma BufferedImage de um arquivo de imagem...
BufferedImage img = ImageIO.read(new File("C:\\Users\\leopoldo\\Desktop\\dente48Lado.png"));
// capturo o Raster da imagem num objeto do tipo WritableRaster (que permite alteração do Raster)...
WritableRaster r = img.getRaster();
// crio um vetor que conterá os pixels varridos pelo Raster...
int pixels[] = new int[img.getWidth() * img.getHeight()];
// calculo a matriz de pixels da imagem com base na largura x altura...
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
// gravo os pixels do eixo x,y no vetor...
r.getPixel(x, y, pixels);
// comparo os pixels desse eixo com as cores RGB que eu quiser substituir...
if (pixels[0] == 255 && pixels[1] == 255 && pixels[2] == 255) {
// substituo os cores RGB da comparação por outras que eu quiser...
pixels[0] = 142;
pixels[1] = 252;
pixels[2] = 0;
r.setPixel(x, y, pixels);
}
}
}
// e, por fim, atualizo a imagem com o Raster modificado...
img.setData(r);
ImageIO.write(img, "png", new File("C:\\Users\\leopoldo\\Desktop\\imagemFinal.png"));
} catch (Exception ex) {
ex.printStackTrace();
}
O problema é que presciso não somente substituir a cor branca, que está no exemplo, e sim todas as variações dele e de cinza também… se eu fosse informar todas as variações segundo os código de cores rgb, eu iria preencher umas 1000 linhas de variações de cinza diferentes…
Teria alguma maneira de pegar esses tons que presciso especificando uma espécie de intervalo de cores ou sei lá…teria como saber se tal codificação rgb seria cinza forte ou escuro?
Os tons de cinza tem os valores R, G e B próximos (o cinza mesmo tem os três valores iguais, portanto, existem apenas 255 tons de cinza “puro”).
Quanto mais altos forem os valores de R,G e B, mais escuro é o cinza.
Só uma correção do comment anterior. Quanto mais altos os valores de R, G e B, mais claro é o cinza. Basta lembrar que 0,0,0 é preto e 255,255,255 é branco.
Para determinar se é cinza, você primeiro deve definir uma tolerância máxima que você permite que um dos componentes tenha sozinho.
Por exemplo:
A cor: R: 200 G: 200 B: 210.
É cinza? Ou é um azul acinzentado?
Se para você isso é cinza, sua variação é maior que 10.
Definido isso, basta então testar os componentes por essa variação. Teste a variação entre cada valor (R com G, G com B, R com B), se for maior que sua tolerância, então não é cinza.
Depois, para determinar o quão escuro é esse cinza, crie uma escala baseada no fato de que, quanto mais baixos os valores, mais escuro é o cinza.
Sim…eu entendi a sua idéia… pegando faixas de números…eu pensei nisso também quando estava implementando… o problema é que por exemplo eu estou com uma imagem aqui de exemplo para testes…nestas imagens a cor R por exemplo nos tons de cinza variam de 137 até 210 (nesta imagem) com valores variáveis no G e no B… o problema é que se eu fizer um if para substituir todas as cores no intervalo de 137 até 210 ele vai substituir não somente todos os tons de cinza, mas sim outras cores da imagem, pois o RGB 137,137,137 seria um cinza (não puro) mas o 137,137,245 já seria um azul (azul sem vontade he he he he )… então eu teria que fazer assim…
se R = 137, G = de X até Y e B = de K até Z então …bla bla bla… e assim por diante seguinto o R de 137 até 210…
Uma cor é cinza se R quase igual a G e quase igual a B. O “quase igual” é algo que você terá de determinar - por exemplo, você pode dizer que se a média desses valores for 100, então se R estiver entre 90 e 110, G estiver entre 90 e 110 e B estiver entre 90 e 110, então a cor é cinza.
E aí você pode fazer seu if com base na média de R, G e B em vez de fazer com base nos valores individuais de R, G e B.
Minha idéia não envolve substituir diretamente um valor. Você deve sempre olhar um canal em relação aos outros. Se qualquer comparação estiver fora da tolerância, a cor não é cinza.
Seria um método mais ou menos assim:
public boolean isCinza(int r, int g, int b, int tolerancia) {
return Math.abs(r - b) <= tolerancia &&
Math.abs(r - g) <= tolerancia &&
Math.abs(b - g) <= tolerancia;
}
Isso é quase equivalente à média, que o entanglement comentou.
Agora, a tolerância é vc que tem que definir.
Aí galera… testei aqui e deu certinho… agora eu entendi a idéia… e não tinha me tocado deste detalhe de que a variação de cinza sempre ou quase sempre tem valores iguais entre R,G e B… … então trabalhando com a média dos valores e a tolerância como o viniGodoy e o entanglement comentaram a rotina para localizar tons de cinza funcionou certinho… adaptei isso no meu código aqui, substituindo aquele if da linha 14… Obrigado pelo esclarecimento…