Mudar cores em Imagem

Olá, galera!
Implementei um JPanel para visualizar a imagem de um boné, no formato .png…
O problema é que preciso modificar as cores de cada parte do boné, conforme o usuário for definindo…
Tipo, o usuário define a cor da toca do boné de Vermelho e então o bonezinho desenhado no JPanel fica com a toca em Vermelho… O usuário define a cor da toca para Azul e no mesmo desenho é pintada a aba em Azul, e assim por diante…
Pensei em criar vários desenhos de bonés, um para cada cor disponível e para cada parte que poderá ser modificada a cor, deixando as outras partes transparentes para então adicionar a imagem com a cor correta ao JPanel em cima da(s) outra(s) já definida(s), formando assim, ao final, o boné com várias imagens definindo as cores e o modelo… Mas, da forma que eu pinto a imagem no JPanel não consigo colocar uma por cima da outra…
Pensei também em criar isso em Flash para que eu pudesse gerar a imagem e guarda-la no banco, porém não imagino como vou guardar também as informações sobre os atributos definidos separados nos outros campos do banco de dados e nem como integrar isso ao swing…
E então pensei em Pintar apenas os pixels da região que estiver modificando a cor (seria a melhor opção para mim, porque não precisaria ficar desenhando centenas de imagens com todas as possibilidades de cores e modelos requeridos pelo usuário final)…
Mas eu não sei como fazer isso!
Alguém sabe como pintar uma determinada área da imagem (tipo BufferedImage) com as cores que eu quiser???
Se sim, sabe também se tem como definir a área respeitando exatamente os limites das partes do boné?
E ainda, alguém sabe outras formas para solucionar o meu problema?

Aguardo respostas.
Grato.

O ideal é criar várias imagens, uma para cada parte do boné, e então junta-las.

Você cria uma série de imagens de abas, com fundo transparente, uma de cada cor.
Depois cria uma série de imagens da parte de cima do boné, com fundo transparente.

E então, monta uma bufferedImage que nada mais é do que as duas combinadas. Essa imagem final você exibe no seu painel.

Há ainda uma forma de mudar para qualquer cor.

Ainda com 2 imagens separadas:

Crie uma imagem da parte de cima do boné, mas ponha a cor dele com uma cor conhecida, como verde (0,255,0). Certifique-se que só a área que será pintada tem essa cor.
Faça o mesmo para aba.

Essas imagens serão sua matriz.

Faça um método que, dado uma imagem, uma cor de origem e uma cor de destino, substitua todas as ocorrências da cor de origem pela cor de destino. Assim você pode pintar as áreas verdes da cor que quiser. Para isso, você vai ter que percorrer a imagem original com um raster:
http://javaboutique.internet.com/tutorials/rasters/
http://javaboutique.internet.com/tutorials/rasters2/

Finalmente, aplique essa função tanto para a aba, quanto para o boné em si. Depois junte as duas imagens numa só e exiba para seu usuário. :wink:

Aí, brother…
Sabia que iria me ajudar, rsrsrsr… Agradeço muito!

[quote]ViniGodoy disse: “O ideal é criar várias imagens, uma para cada parte do boné, e então junta-las.
Você cria uma série de imagens de abas, com fundo transparente, uma de cada cor.
Depois cria uma série de imagens da parte de cima do boné, com fundo transparente.
E então, monta uma bufferedImage que nada mais é do que as duas combinadas. Essa imagem final você exibe no seu painel.”[/quote]
Estive calculando por alto quantas imagens eu teria que criar para satisfazer todas as possibilidades que deveriam ser cedidas com essa forma de implementação e o resultado é estonteante! Isso, porque tenho que dar a possibilidade de modificar as cores de cada gomo que formam a toca do boné, do botão que fica na parte superior, da parte superior da aba, bem como da inferior, do sutache da aba (quando tiver), da cor da fivela (para cada modelo de fivela), da cor do suador; além de ter que mostrar o bonezinho em 5 ângulos diferentes para todos os modelos, respeitando todas as cores definidas! Assim, dá pra imaginar a quantidade de imagens que teria que criar com cada cor…

[quote]ViniGodoy disse: Faça um método que, dado uma imagem, uma cor de origem e uma cor de destino, substitua todas as ocorrências da cor de origem pela cor de destino. Assim você pode pintar as áreas verdes da cor que quiser. Para isso, você vai ter que percorrer a imagem original com um raster(…)
Finalmente, aplique essa função tanto para a aba, quanto para o boné em si. Depois junte as duas imagens numa só e exiba para seu usuário.[/quote]
Essa seria, pelo meu ver, a solução mais viável! Assim eu poderia criar um método que aceite qualquer cor RGB obtida por um JColorChoose, por exemplo, sem me limitar a uma determinada lista de imagens, e sem a trabalheira de ter que criar esse tanto de imagens… Seria perfeito! Eu poderia atribuir cores mais “singulares” para cada componente do boné e reservá-las, utilizando-as para todos os ângulos; assim eu teria que criar apenas uma imagem para cada ângulo de visão e para cada modelo, e apenas modificar as cores reservadas de origem pelas de destino que o usário selecionar através do JColorChooser, criando uma BufferedImage com as cores reservadas e modificando essa bufferedImage com as cores selecionadas… Não é mesmo? Mas eu não entendi como trabalhar com raster (apanho muito por ser iniciante); não conseguir visualizar como vou pegar a cor de referência e substituir pela nova cor…
Você sabe mexer com raster? Pode me dar uma força???

Posso sim, não é tão difícil quanto parece. Basicamente é só usar os gets e sets que ele fornece.
Leia os tutoriais ali em cima e qualquer dúvida posta aqui.

Então, brother…
Sei que parece apelação, mas eu não consegui usar esses geters e seters para o que preciso…
Tentei assim:

int red, green, blue; WritableRaster raster = img.getRaster(); int pixels[] = new int[4]; raster.getPixels(0, 0, img.getWidth(), img.getHeight(), pixels); red = pixels[0]; green = pixels[1]; blue = pixels[2]; System.out.println("R: "+red+" G: "+green+" B: "+blue);
Mas dá erro no método getPixels()…
Como pode ver, não sakei muito isso não…
Como eu vou fazer para comparar as cores dos pixels da imagem com uma determinada cor???
E como vou mudar essa cor?

Eu lí os tutorias que me passou, mas não consegui extrair direito como vou fazer isso…
Helpe-me, please!!!

Que erro dá?

Use o método sem a altura e a largura da imagem.

Caso contrário, você estará tentando pegar os dados de todos os pixels da imagem inteira… o que exige um array gigantesco. É mais fácil e mais prático trabalhar pixel a pixel.

Brother… Não tinha visto suas últimas dicas, mas fiz exatamente o que você disse (eu acho) usando Raster ao invés de WritableRaster, depois de ler com mais detalhes os tutoriais… Bom, consegui reconhecer as cores da imagem, e até comparar, porém não consegui mudar essas cores para a BufferedImage…
Dê uma olhada no que fiz e diz se está certo…

int red, green, blue; Raster raster = img.getRaster(); int pixels[] = new int[5]; raster2.getPixel(0, 0, pixels); for (int i = 0; i < img.getWidth(); i++) { for (int ii = 0; ii < img.getHeight(); ii++) { raster.getPixel(i, ii, pixels); red = pixels[0]; green = pixels[1]; blue = pixels[2]; System.out.println("R: "+red+" G: "+green+" B: "+blue); if (pixels[0] == 255 && pixels[1] == 255 && pixels[2] == 255) { img.setRGB(50, 100, 150, 0, pixels, i, ii); } } }
Estou usando setRGB() para atribuir as cores mas não estou conseguindo mudar a cor…
Na saída no terminal consigo visualizar as cores dos pixels como implementei com System.out.println(), mas a cor não muda e não acontece nada, nenhum erro, e a velocidade está bem lenta…
Como vou mudar as cores?
Sabe me dizer?

O system.out deve estar deixando lento.

Depois de alterar a imagem, você chamou o invalidate no painel para ele repinta-la?

Fera, acho que a saída com System.out.println() não tem nada haver não… Creio que o problema está no método setRGB da classe BufferedImage, porque quando desabilito essa linha o processamento é quase instantâneo… Não estou sabendo usar esse método… Como pôde perceber, varri a imagem inteira para comparar os pixels, mas não estou conseguindo mudar a cor na BufferedImage…
Faz ideia do que estou fazendo de errado e de como deve ser???
Acho que até aqui já foi um grande avanço, mas não posso desistir…
Aguardo…

Ah, e tudo isso eu faço antes de pintar a imagem no JPanel…

img = ImageIO.read(new File(fc.getSelectedFile().getAbsolutePath())); Raster raster = img.getRaster(); int pixels[] = new int[5]; for (int i = 0; i < img.getWidth(); i++) { for (int ii = 0; ii < img.getHeight(); ii++) { raster.getPixel(i, ii, pixels); if (pixels[0] == 255 && pixels[1] == 255 && pixels[2] == 255) { img.setRGB(50, 100, 150); } } } if (quadroImagem == null) quadroImagem = new ImagePanel(img); quadroImagem.setImage(img); painelImagem.add(quadroImagem); painelImagem.repaint(); painelImagem.validate();

Você deve usar o método setPixel do Raster, não o setRGB do BufferedImage.
Mas o caminho é esse mesmo.

Então, nesse caso eu crio um WritableRaster ao invés de Raster, porque o Raster não me permite o método setPixel()… Mas quais informações eu devo passar como parâmetros para o método… Sim, porque ví na doc que é (X, Y, Largura, Altura, arrayRGB, Offset, scansize), mas não sei o que é esse Offset, nem esse scansize…
O que é?
Como eu completo esse código?

Então, esses parametros que mencionei eram da BufferedImage, mas do Raster é parecido…
Fiz assim, mas sem sucesso…

img = ImageIO.read(new File(fc.getSelectedFile().getAbsolutePath())); WritableRaster r = img.getRaster(); int pixels[] = new int[5]; for (int i = 0; i < img.getWidth(); i++) { for (int ii = 0; ii < img.getHeight(); ii++) { r.getPixel(i, ii, pixels); if (pixels[0] == 255 && pixels[1] == 255 && pixels[2] == 255) { r.setPixels(i, ii, img.getWidth(), img.getHeight(), pixels); img.setData(r); } } }O que pode estar errado:?

Hehehehehe…
Conseguiiiiiiiiiiiiii!!!
Mais uma vez você me ajudou muito ViniGodoy!!! Tenho aprendido muito com as suas dicas, mesmo as que vejo nos post’s de outos colegas onde você ajuda! Valeu mesmo, mais uma vez!
Como você disse no início, não é tão dificil como parece, e bastou dar umas lidas nas doc’s, orientando-me pelas suas dicas…
Segue como eu fiz…

// obtenho uma BufferedImage de um arquivo de imagem... BufferedImage img = ImageIO.read(new File(fc.getSelectedFile().getAbsolutePath())); // 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] == 0 && pixels[2] == 0) { // substituo os cores RGB da comparação por outras que eu quiser... pixels[0] = 150; pixels[1] = 100; pixels[2] = 50; // escrevo no WritableRaster novamente a matriz de pixels desse eixo... r.setPixel(x, y, pixels); } } } // e, por fim, atualizo a imagem com o Raster modificado... img.setData(r);
Note que se você colocar essa última linha dentro do laço ‘for’, o processamento será bem lento, porque a imagem será atualizada eixo a eixo…
Funcionou como uma luva! Porém, quando se modifica um tipo de imagem com compressão, como PNG (apesar de ser menos), JPG, GIF, por exemplo, é possível que fique alguns pixelsinhos nas bordas da área pintada com a cor antiga, porque essa borda apresenta uma pequena distorção nas cores RGB, não entendo direito; comigo foi assim; mas nada que não se possa dar um jeito, rsrsrs…
Um abraço! Espero que a solução dessa problemática venha ajudar alguém!
E, mais uma vez, obrigado, mestre ViniGodoy!

É verdade. Isso por que os algoritmos de lossy compression, como jpg, gif e mp3, descartam parte dos dados que, a princípio, não seriam perceptíveis aos seres humanos. Isso permite obter maiores taxas de compressão.

Do contrário, os algoritmos de compressão lossless não sofrem esse problema. Isso inclui o LZW, o png e o tiff.

Outra coisa que pode estar acontecendo é que sua ferramenta de desenho (gimp, corel, sei lá) deve estar suavizando a borda durante a exportação. Ela faz isso misturando parte dos pixels da borda com a cor do fundo. Isso dá um efeito visual muito melhor e várias ferramentas fazem isso por padrão. Entretanto, isso confunde o software. Veja se não existe a opção de não suavizar bordas na ferramenta e use-a.

Primeiramente, olá a todos :smiley:
Sou novo no forum e gostei muito daqui!
Me desculpem por reviver esse topico mas estou com um problema que provavelmente posso resolver de forma semelhante ao que o Linkel resolveu o dele…

Meu problema é o seguinte, ao carregar uma imagem na tela eu gostaria de dar uma opção ao usuário de mudar a cor da imagem, ele poderá fazer isso arrastando um JSlider (não lembro se é esse mesmo o componente) fazendo com que a imagem vá mudando de cor conforme ele vai movendo a barrinha

Eu pensei em fazer semelhante ao que o Linkel fez… mas não sei como eu faria para varrer completamente a imagem e mudar todas as cores por igual.

Será que poderiam me ajudar com esse problema? Realmente não tenho a mínima idéia de como fazer isso :cry:

[quote=Sairon]Primeiramente, olá a todos :smiley:
Sou novo no forum e gostei muito daqui!
Me desculpem por reviver esse topico mas estou com um problema que provavelmente posso resolver de forma semelhante ao que o Linkel resolveu o dele…

Meu problema é o seguinte, ao carregar uma imagem na tela eu gostaria de dar uma opção ao usuário de mudar a cor da imagem, ele poderá fazer isso arrastando um JSlider (não lembro se é esse mesmo o componente) fazendo com que a imagem vá mudando de cor conforme ele vai movendo a barrinha

Eu pensei em fazer semelhante ao que o Linkel fez… mas não sei como eu faria para varrer completamente a imagem e mudar todas as cores por igual.

Será que poderiam me ajudar com esse problema? Realmente não tenho a mínima idéia de como fazer isso :cry:[/quote]

Você precisa varrer a imagem com um laço na altura e largura, porque a imagem é uma matriz de bytes.
usando o código acima, que o vini godoy mostrou:

pixels[0] é o canal vermelho, pixels[1] é o verde, e pixels[2] é o azul.

todos eles tem a capacidade de um byte, ou seja, sua imagem possui 24bits/cor. Em java, esses valores podem varias de -128 a 127.

Pode usar 3 sliders e passar os respectivos valores para os bytes, assim você estará implementando um mecanismo de matização, e dependendo dos valores, vai conseguir a tonalidade que quiser.