Comparador de imagens

44 respostas
Z

Boa tarde pessoal. Estou com um projeto novo, mas ainda não sei nem por onde começar e nem se quer a viabilidade de realizar o mesmo.
Um tempo atraz li numa revista sobre um programa que analizava fotos das cidades, localizava um padrão nas ruas e identificava qual era aquela cidade.
O que pretendo fazer não é de tamanha complexidade.
Preciso comprar duas fotos e dizer o que tem de novo na segunda. Essas imagens tem pontos, somente isso e gostaria de identificar qual desses pontinhos são novos.
É pocivel fazer isso? Poderia me dizer o que eu precisaria estar estudando para realizar esse projeto? De já agradeço.
Peço humildemente a ajuda de vcs.

44 Respostas

J

A - B = s diferença entre elas

http://homepages.inf.ed.ac.uk/rbf/HIPR2/pixsub.htm

=

Z

São pontos azuis, e então na terceira imagem preciso que ela carregue os dados da primeira compare a segunda e marque em vermelho na tercera os novos pontos.

Z

Já me recomendaram estudar sobre processamento de imagem, e a API JAI alguém conhece que possa me elucidar melhor sobre esse assunto?

J

A solução está no link postado acima e possui até código fonte. Não leu?

Z

Não li por completo. Mas já que está ally vou lá. Grato.

Z

Desculpe mas não encontrei nada falando como programar isso.

Z

Pessoal não consigo baixar a API JAI
alguém tem um linke ou ela mesmo que possa me passar?

J

Está me zoando né!? Só pode.

Z

Não, e desculpe minha ignorância, só vi conceitos sobre imagens, mas nada como programar.
De qualquer forma preciso mesmo fazer esse projeto.

V

Acho que ele tá sim. Em 2 minutos navegando pela página achei isso aqui:
http://homepages.inf.ed.ac.uk/rbf/HIPR2/flatjavasrc/ImageDifference.java

E um applet que demonstra como isso funciona:
http://homepages.inf.ed.ac.uk/rbf/HIPR2/subdemo.htm

J

ViniGodoy:
Acho que ele tá sim. Em 2 minutos navegando pela página achei isso aqui:
http://homepages.inf.ed.ac.uk/rbf/HIPR2/flatjavasrc/ImageDifference.java

E um applet que demonstra como isso funciona:
http://homepages.inf.ed.ac.uk/rbf/HIPR2/subdemo.htm

Para cada artigo lá tem um demo em applet e o código fonte: “clique aqui para ver como funciona” bem grande lá.

Z
ViniGodoy:
Acho que ele tá sim. Em 2 minutos navegando pela página achei isso aqui: http://homepages.inf.ed.ac.uk/rbf/HIPR2/flatjavasrc/ImageDifference.java

E um applet que demonstra como isso funciona:
http://homepages.inf.ed.ac.uk/rbf/HIPR2/subdemo.htm

Não estou zoando ninguém, e porq estaria se preciso do conteúdo? Vim pedir a ajuda de vcs humildemente, não há necessidade de zombares de mim.
A applet eu avia encontrado, o código fonte não. Não sei nada de inglês, e para entender uso do tradutor da pagina que é falho.
De qualquer forma agradeço.

Se me ajudassem a encontrar o seguinte erro, eu agradeceria muito tambem.

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Coordinate out of bounds!
at java.awt.image.ComponentSampleModel.getPixel(Unknown Source)
at java.awt.image.Raster.getPixel(Unknown Source)
at test1.main(test1.java:45)

Segue aqui meu fonte.

int[] cor2 = new int[] { 166, 210, 255 };
		File f = new File("src/checkerboard1.png");
		BufferedImage imagem = ImageIO.read(f);
		@SuppressWarnings("unused")
		Raster raster1 = imagem.getRaster();
		WritableRaster raster2 = imagem.getRaster();
		int[] pixel = new int[3];
		for (int h = 0; h < imagem.getHeight(); h++)
			for (int w = 0; w < imagem.getWidth(); w++) {
				raster2.setPixel(w, h, cor2);
				 raster1.getPixel(h,w,pixel);
				if ((pixel[0] == 75) && (pixel[1] == 82) && (pixel[2] == 93)) {

					raster2.setPixel(w,h,cor2);
				}
			}
		
		ImageIO.write(imagem, "PNG", new File("src/checkerboard2.png"));
		String infoImagem = "Dimensões: " + imagem.getWidth() + "x"
				+ imagem.getHeight() + " Bandas: "
				+ imagem.getRaster().getNumBands();
		System.out.println(infoImagem);
Para imagens geradas no próprio Java funciona normalmente, mas quando carrego uma imagem externa aparece esse erro ai. Se quiserem testar aki está o fonte da classe completa. Talves conseguindo fazer essa pequena manipulação dos pixeis eu consiga sair um pouco do chão com o que pretendo desenvolver.
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class test1 {

	/**
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException {
		
		 int width = 256;
		 int height = 256;
		 BufferedImage image = new
		 BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
		 WritableRaster raster = image.getRaster();
		 int[] cor1 = new int[]{255,255,255};
		 int[] cor2 = new int[]{166,210,255};
		 @SuppressWarnings("unused")
		 int cont=0;
		 for(int h=0;h<height;h++)
		 for(int w=0;w<width;w++)
		 {
		 if ((((w/32)+(h/32)) % 2) == 0) raster.setPixel(w,h,cor1);
		 else raster.setPixel(w,h,cor2);
		 }
		
		 ImageIO.write(image,"PNG", new File("src/checkerboard.png"));

		File f = new File("src/checkerboard.png");
		BufferedImage imagem = ImageIO.read(f);
		@SuppressWarnings("unused")
		Raster raster1 = imagem.getRaster();
		WritableRaster raster2 = imagem.getRaster();
		int[] pixel = new int[3];
		for (int h = 0; h < imagem.getHeight(); h++)
			for (int w = 0; w < imagem.getWidth(); w++) {
				raster2.setPixel(w, h, cor2);
				 raster1.getPixel(h,w,pixel);
				if ((pixel[0] == 75) && (pixel[1] == 82) && (pixel[2] == 93)) {

					raster2.setPixel(w,h,cor2);
				}
			}
		
		ImageIO.write(imagem, "PNG", new File("src/checkerboard2.png"));
		String infoImagem = "Dimensões: " + imagem.getWidth() + "x"
				+ imagem.getHeight() + " Bandas: "
				+ imagem.getRaster().getNumBands();
		System.out.println(infoImagem);
	}
}
V

Não é pq na linha 11 você fez:

raster1.getPixel(h,w,pixel);

No lugar de:

raster1.getPixel(w,h,pixel);

?

Z

Não continua lançando…

Exception in thread main java.lang.ArrayIndexOutOfBoundsException: 3

at java.awt.image.ComponentSampleModel.getPixel(Unknown Source)

at java.awt.image.Raster.getPixel(Unknown Source)

at test1.main(test1.java:51)
Z

Consegui identificar o RGB, mas tive que usar outro método o qual é muito trabalhoso, e só consegui devido ao Photo painte da suite Corel.
Bema imagem que tenho para ser processada é está.

Esses são os pontos que mudarão de lugar. Uns irão sumir outros irão aparecer. E gostaria de localizar esses novos pontos se possível.

J

Ziru:
Consegui identificar o RGB, mas tive que usar outro método o qual é muito trabalhoso, e só consegui devido ao Photo painte da suite Corel.
Bema imagem que tenho para ser processada é está.

Esses são os pontos que mudarão de lugar. Uns irão sumir outros irão aparecer. E gostaria de localizar esses novos pontos se possível.

Olha, deixa eu te falar uma coisa. Você precisa subtrair uma imagem de outra para achar a diferença de maneira consistente entre duas imagens. Não é pela cor que vai resolver isso, mas pela disposição dos pixels específicos.

  1. Se não sabe inglês, se vira e usa um tradutor como fez agora.
  2. Está conseguindo exceções, depura o programa e acha o problema
  3. É nas dificuldades que aprendemos alguma coisa de valor e não no contrário. Se quer sombra e água fresca é melhor ganhar na megasena.

Sem mais.

Z

Aprendo programação atualmente sonsinho, e com algumas vidio-aulas. Nunca pedi código pronto. Eu precisava achar a cor dos pixels para alterar sim, porque esse fundo era quase transparente, podendo ter sempre variações no mesmo o que acarretaria em diversas coisas diferentes na outra imagem (devido ao fundo) gerando algo poluído. Como consegui achar e modificar o RGB, consegui deixar o fundo exatamente com os mesmos pixels em todos os pontos. Melhor assim não?
E ainda tem mais um problema que essas imagens serão geradas através de prints sendo assim, não ficaram todas do mesmo tamanho, e ainda não sei como resolver isso. Pois na hora que fizer a subtração da imagem dará erro mostrando coisas desnecessárias ou não?

V

Se as imagens não serão do mesmo tamanho, você tem um problemão. Como você sabe que os pixels mexeram, ou que as duas imagens não estão simplemente desalinhadas?

E

“As imagens serão geradas a partir de prints” quer dizer que você tem o problema de “registro”, que não é trivial de resolver (já não é trivial tirar a subtração de duas imagens se elas foram capturadas pelo mesmo dispositivo, só em instantes diferentes :frowning:

O problema de “registro” (no mesmo sentido em que se usa em artes gráficas) é não-trivial e depende do que você quer fazer.

É melhor postar as suas imagens originais, para termos uma idéia do tamanho da encrenca.

Z

Bem estou a pensar em algo que não sei se é possível. Mas planejo em definir um tamanho para ser cortada a imagem antes de ser subtraída, assim ficarão do mesmo tamanho.
Talvez isso resolva, mas só fazendo pra saber como fazer.

Aqui estão as imagens em tamanho original, a segunda está feita o primeiro processamento pra deixar o fundo uniforme. E usei o Photo Painte pra deixar os pontos em vermelho os que são novos, e é exatamente assim que quero deixar processando ela, o resultado final deverá ser semelhante a esse ai.

E

Quanto a “tamanho” o Vinicius Godoy não está se referindo a “todas as imagens são 1024 x 768 pixels”.
Ele está pensando em "você tem várias imagens do mesmo conjunto de objetos, mas que podem ter sido capturadas com ampliações ligeiramente diferentes, ou então em posições ligeiramente diferentes.
Pense em 2 fotos do mesmo conjunto de objetos, tiradas com a mesma máquina fotográfica, mas onde o tripé se desalinhou 1 mm para a esquerda ou 1 mm para a frente.
Nem estou imaginando se elas foram tiradas com iluminação ligeiramente diferente :frowning:
Quando você for comparar as duas fotos fazendo uma subtração simples, vai ter uma surpresa - vai ver não somente que elas estão “desregistradas” (ou seja, desalinhadas) como também que os objetos têm tamanhos ligeiramente diferentes.

Z

E ainda resta um terceiro problema, pois estes pontos alem de aparecerem eles também desaparecem. Então o lugar onde desaparecer um, será apontado como novo.
Mas se na subtração eu conseguir obter o RGB, do local onde está dando divergência então consigo resolver esse terceiro problema. Pois quando desaparecer um ponto, no primeiro processamento irá deixar com a cor uniforme do fundo então basta validar se o local onde deu diferença for igual o RGB do fundo eu modifico. Acredito que isso seja o bastante.
Bem, eu tenho em mente tudo que deve ser feito pela aplicação, só não sei como passar isso pro JAVA ainda. Mas de já agradeço pela vossa ajuda, que já está me dando um norte.

Z

entanglement:
Quanto a “tamanho” o Vinicius Godoy não está se referindo a “todas as imagens são 1024 x 768 pixels”.
Ele está pensando em "você tem várias imagens do mesmo conjunto de objetos, mas que podem ter sido capturadas com ampliações ligeiramente diferentes, ou então em posições ligeiramente diferentes.
Pense em 2 fotos do mesmo conjunto de objetos, tiradas com a mesma máquina fotográfica, mas onde o tripé se desalinhou 1 mm para a esquerda ou 1 mm para a frente.
Nem estou imaginando se elas foram tiradas com iluminação ligeiramente diferente :frowning:
Quando você for comparar as duas fotos fazendo uma subtração simples, vai ter uma surpresa - vai ver não somente que elas estão “desregistradas” (ou seja, desalinhadas) como também que os objetos têm tamanhos ligeiramente diferentes.

Bem, todas as imagens serão tiradas por um único aplicativo de print. Acredito que a unica divergência será mesmo no tamanho dela.

Z

Encontrei esse codigo, procurando o tema subtração de imagem.
Não sei se faz exatamente o que o applet da outra pagina faz, mas vou testar e ver o resultado.
http://code.google.com/p/livecamanalyze/source/browse/trunk/SocketJava/src/com/barnabe/filters/Subtracao.java?spec=svn61&r=61

V

Se as duas imagens tiverem o mesmo tamanho, subtraí-las é uma tarefa trivial.

Considerando que img1 e img2 são duas BufferedImages, você tem que fazer mais ou menos isso:

public int subtract(int color1, int color2) {
   Color c1 = new Color(color1);
   Color c2 = new Color(color2);

   int r = Math.max(0, c1.getRed() - c2.getRed());   
   int g = Math.max(0, c1.getGreen() - c2.getGreen());   
   int b = Math.max(0, c1.getBlue() - c2.getBlue());
   return new Color(r, g, b).getRGB();
}   

public BufferedImage subtract(BufferedImage img1, BufferedImage img2) {
    BufferedImage out = new BufferedImage(img1.getWidth(), img1.getHeight(), BufferedImage.TYPE_INT_RGB);

    for (int y = 0; y &lt; img1.getHeight(); y++)
        for (int x = 0; x &lt; img1.getWidth(); x++)
             out.setRGB(x, y subtract(img1.getRGB(x, y), img2.getRGB(x, y));

    return out;
}
V

Só uma dúvida. Isso é um game? E se for, qual é?

Z

Sim é um game, eu já fiz um aplicativo pra ser usado externamente pelo meninos do game. Agora quero fazer otro antes que eu deixe de jogar.
Eu não ganho nada com isso, só faço por gostar do game e de programar mesmo.
Chama-se Imperia Online

J

entanglement:
Quanto a “tamanho” o Vinicius Godoy não está se referindo a “todas as imagens são 1024 x 768 pixels”.
Ele está pensando em "você tem várias imagens do mesmo conjunto de objetos, mas que podem ter sido capturadas com ampliações ligeiramente diferentes, ou então em posições ligeiramente diferentes.
Pense em 2 fotos do mesmo conjunto de objetos, tiradas com a mesma máquina fotográfica, mas onde o tripé se desalinhou 1 mm para a esquerda ou 1 mm para a frente.
Nem estou imaginando se elas foram tiradas com iluminação ligeiramente diferente :frowning:
Quando você for comparar as duas fotos fazendo uma subtração simples, vai ter uma surpresa - vai ver não somente que elas estão “desregistradas” (ou seja, desalinhadas) como também que os objetos têm tamanhos ligeiramente diferentes.

Ruído causado por iluminação, ou algum tipo de movimento você consegue tirar “limiarizando” a imagem e aplicando a “erosão”. Pequenos pontos menores que a informação vão desaparecer.
A subtração é algo simples de se conseguir. Para isto basta:

pixelA(x,y) - pixelB(x,y) = pixelC(x,y)

Monta uma nova imagem com esses pixels. O link da hipr lá em cima dá um ótimo artigo(que é o principal para se saber como fazer), um laboratório para ver como funciona e código fonte. Não sei porquê esse tópico está se estendendo tanto

Z
juliocbq:
entanglement:
Quanto a "tamanho" o Vinicius Godoy não está se referindo a "todas as imagens são 1024 x 768 pixels". Ele está pensando em "você tem várias imagens do mesmo conjunto de objetos, mas que podem ter sido capturadas com ampliações ligeiramente diferentes, ou então em posições ligeiramente diferentes. Pense em 2 fotos do mesmo conjunto de objetos, tiradas com a mesma máquina fotográfica, mas onde o tripé se desalinhou 1 mm para a esquerda ou 1 mm para a frente. Nem estou imaginando se elas foram tiradas com iluminação ligeiramente diferente :( Quando você for comparar as duas fotos fazendo uma subtração simples, vai ter uma surpresa - vai ver não somente que elas estão "desregistradas" (ou seja, desalinhadas) como também que os objetos têm tamanhos ligeiramente diferentes.

Ruído causado por iluminação, ou algum tipo de movimento você consegue tirar "limiarizando" a imagem e aplicando a "erosão". Pequenos pontos menores que a informação vão desaparecer.
A subtração é algo simples de se conseguir. Para isto basta:

pixelA(x,y) - pixelB(x,y) = pixelC(x,y)

Monta uma nova imagem com esses pixels. O link da hipr lá em cima dá um ótimo artigo(que é o principal para se saber como fazer), um laboratório para ver como funciona e código fonte. Não sei porquê esse tópico está se estendendo tanto

O codigo fonte de lá é horrivel de se entender.
Já que entendes do assunto, sabes me dizer se este faz o mesmo procedimento?

package com.barnabe.filters;

import java.awt.image.BufferedImage;

/* @author Arthur F. Zanona */

public class Subtracao {
    public static BufferedImage executar ( BufferedImage imagem , BufferedImage imagemDois ) {
        // redeclarando para tornar-se mais claro
        int alturaUm = imagem.getRaster().getHeight() ,
            larguraUm = imagem.getRaster().getWidth(),
            alturaDois = imagem.getRaster().getHeight(),
            larguraDois = imagem.getRaster().getWidth();

        // ajustando para nao estourar os indices..
        int alturaControle = alturaUm > alturaDois ? alturaDois : alturaUm;
        int larguraControle = larguraUm > larguraDois ? larguraDois : larguraUm;

         for ( int i = 0 ; i < larguraControle ; i++  ) {
            for ( int j = 0 ; j < alturaControle ; j++ ) {
                int[] rgbUm = new int[3],
                      rgbDois = new int[3];
                imagem.getRaster().getPixel(i, j, rgbUm);
                imagem.getRaster().getPixel(i, j, rgbDois);
                // somando a area em comum
                rgbUm[0] -= rgbDois[0];
                rgbUm[1] -= rgbDois[1];
                rgbUm[2] -= rgbDois[2];
                imagem.getRaster().setPixel(i, j, rgbUm);
            }
         }
        return imagem;
    }

    public static Integer diferencaEntre ( BufferedImage imagem , BufferedImage imagemDois , Integer inicioWidth , Integer inicioHeight , Integer fimWidth , Integer fimHeight ) {
        int resultado[] = new int[3];
        int[] rgbUm = new int[3],
              rgbDois = new int[3];

         for ( int i = inicioWidth ; i < fimWidth ; i++  ) {
            for ( int j = inicioHeight ; j < fimHeight ; j++ ) {
                imagem.getRaster().getPixel(i, j, rgbUm);
                imagemDois.getRaster().getPixel(i, j, rgbDois);
                resultado[0] += (rgbUm[0]) - (rgbDois[0]);
                resultado[1] += (rgbUm[1]) - (rgbDois[1]);
                resultado[2] += (rgbUm[2]) - (rgbDois[2]);

            }
         }
        return (resultado[0] + resultado[1] + resultado[2] ) / 3;
    }

}
Z

E também porq raios continua a lançar essa exceção.

Exception in thread main java.lang.ArrayIndexOutOfBoundsException: 3

at java.awt.image.ComponentSampleModel.getPixel(Unknown Source)

at java.awt.image.Raster.getPixel(Unknown Source)

at Subtracao.executar(Subtracao.java:21)

at test1.main(test1.java:80)
E

Como é que você sabe que getPixel requer um array de cores, e que elas irão vir na ordem R, G e B? Não achei isso na documentação :slight_smile:

Na verdade, depende um pouco do modo do seu “raster”. Pode ser, por exemplo, que venha na ordem “A”, “R”, “G” e “B”, por exemplo (onde A é o canal alpha, que indica a transparência). Se for isso, vão aparecer 4 inteiros, não 3 como você está supondo.

V

entanglement:
Como é que você sabe que getPixel requer um array de cores, e que elas irão vir na ordem R, G e B? Não achei isso na documentação :slight_smile:

Na verdade, depende um pouco do modo do seu “raster”. Pode ser, por exemplo, que venha na ordem “A”, “R”, “G” e “B”, por exemplo (onde A é o canal alpha, que indica a transparência). Se for isso, vão aparecer 4 inteiros, não 3 como você está supondo.

O método que postei trata isso automaticamente.

Z

ViniGodoy:
entanglement:
Como é que você sabe que getPixel requer um array de cores, e que elas irão vir na ordem R, G e B? Não achei isso na documentação :slight_smile:

Na verdade, depende um pouco do modo do seu “raster”. Pode ser, por exemplo, que venha na ordem “A”, “R”, “G” e “B”, por exemplo (onde A é o canal alpha, que indica a transparência). Se for isso, vão aparecer 4 inteiros, não 3 como você está supondo.

O método que postei trata isso automaticamente.

O método que me passaste gera erro de compilação na linha 16.

Z

Lendo a doc da API JAI lá tem um metodo para subtração de imagens, só que não consigo baixar essa API. Um de vcs não teria ela que possa me passar?

V

Corrigi o método lá. É que o nome é setRGB, e não setPixel, como eu tinha escrito.

Da próxima vez, diz qual erro gera, ao invés de só dizer que “dá erro”. Ou tenta você mesmo corrigir.

Z

ViniGodoy:
Corrigi o método lá. É que o nome é setRGB, e não setPixel, como eu tinha escrito.

Da próxima vez, diz qual erro gera, ao invés de só dizer que “dá erro”. Ou tenta você mesmo corrigir.


Certo. E eu até tentaria arranjar meu amigo, porem desconheço o assunto.

Z

Não entendi onde vou usar esse método.

public int subtract(int color1, int color2) {  
    	   Color c1 = new Color(color1);  
    	   Color c2 = new Color(color2);  
    	  
    	   int r = Math.max(0, c1.getRed() - c2.getRed());     
    	   int g = Math.max(0, c1.getGreen() - c2.getGreen());     
    	   int b = Math.max(0, c1.getBlue() - c2.getBlue());  
    	   return new Color(r, g, b).getRGB();  
    	}

Não é somente o segundo que faz a subtração?

Z

Perdão a ignorância. Já vi onde está sendo utilizado.

Z

Está gerando uma imagem totalmente preta.

J

Ziru:
Está gerando uma imagem totalmente preta.
O pessoal já te deu a coisa mastigada na maior boa vontade. Agora só resta pensar um pouco.

Z

Acredite eu sou muito grato e estou tentando arranjar. Não precisa vim com 4 pedras na mão.

J

Acredite eu sou muito grato e estou tentando arranjar. Não precisa vim com 4 pedras na mão.

Não é vir com quatro pedras. Eu só queria que você entendesse o artigo porque somente com ele você terá condição de entender e produzir o que precisa. Ele é mais importante que código fonte.
Mas você nem sequer se deu ao luxo de ler 3 linhas dele.

Z

Eu li sim o artigo meu caro. A parte que você me passou li por completa e estou procurando mais sobre o assunto.
Não havia encontrado o código fonte, mas mesmo assim aquelo fonte está impossível de se fazer se que um teste de mesa.
E irei ler novamente sem duvidas, se houver 1% de chance de fazer o que pretendo irei fazer. :slight_smile:
Estou tentando arranjar o código que o ViniGodoy passou porque atualmente somente aplica uma mascara vermelha na imagem.
Mas arranjar um BUG sem conhecer muito do assunto é osso.

Z

Nem que eu tenha que engavetar a aplicação e esperar pra daqui 4 anos pra faze-la. Que vai ser quando terei terminado minha graduação em Sistemas.

Criado 17 de janeiro de 2013
Ultima resposta 21 de jan. de 2013
Respostas 44
Participantes 4