Get cor de pixel em um Jpanel com BufferedImage

7 respostas
gustavofernandes

Pessoal, bão demais!!
Meu primeiro post no fórum. Tô pesquisando isso tem muitos dias(inclusive aqui no fórum). Não achei uma possível ajuda, mas acho que estou fazendo confusão de algumas coisas. É o seguinte:
Estou com um JPanel e desenho pequenos quadrados utilizando o Graphics e BufferedImage. Preciso depois varrer a tela e pegar os pixels da cor que eu os desenhei. O método paint está assim:

public void paintComponent(Graphics g) {
  
  bI = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
  Graphics2D g2d = (Graphics2D)bI.createGraphics();
  
  g2d.setColor(Color.black);
  g2d.drawImage(bI, x, y, 4, 4, null);
  g2d.dispose();

}

Não desenha nada. Eu entendi que pego o contexto do jpanel utilizando o graphic g que tenho como parâmetro(já que estou sobrescrevendo o método paintComponent). Daí era só fazer
Graphics2D g2d = (Graphics2D)g . Mas eu preciso do BufferedImage para usar o bI.getRGB() e coletar a cor do pixel na posição x, y. Acho que estou fazendo muita confusão com o BufferedImage cujo é quem eu preciso para pegar a cor de um pixel. Os valores de width, height, x e y eu já tenho. Então, que confusão eu estou fazendo com a dupla Graphics2D e BufferedImage?? E outra pergunta, tem como eu desenhar no jpanel direto e depois pegar a cor dos pixels desenhados??

7 Respostas

ViniGodoy

Não é possível.

Nesse caso, é melhor desenhar tudo num BufferedImage do tamanho do seu painel, manipular os pixels nesse bufferedImage e, só ao final, jogar o resultado para o painel.

gustavofernandes

ViniGodoy:
Não é possível.

Nesse caso, é melhor desenhar tudo num BufferedImage do tamanho do seu painel, manipular os pixels nesse bufferedImage e, só ao final, jogar o resultado para o painel.


Pois é, eu já esperava que não, pois não encontrei nehum método para buscar um pixel pelo jpanel diretamente.

Eu também já percebi um pouquinho da confusão que estou fazendo. Quando eu crio o objeto BufferedImage (bI = BufferedImage…) e depois o Graphics através dele (g2d = (Graphics)bi.CreateGraphics()) eu criei um Graphic para desenhar sobre a imagem. Daí eu precisaria desenhar sobre o jpanel fazendo algo do tipo: g.drawImage(bI, 0, 0, null). Daí o código ficaria algo como:

public void paintComponent(Graphics g) {  
        
       bI = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);  
       Graphics2D g2d = (Graphics2D)bI.createGraphics();  //Desenho sobre a Imagem
        
       g2d.setColor(Color.black);
       g2d.fillOval(x, y, 4, 4);
  
       g.drawImage(bI, 0, 0, null);  //Desenho sobre o jpanel
       g2d.dispose();  
      
    }

Mas ainda tem coisa errada, pois não está criando os "pontos"…Se alguém souber…

ViniGodoy

E o que ele está desenhando?

PS: É melhor fazer o g2d.dispose() antes de fazer o draw. Troque a linha 09 com a 10 de lugar.

gustavofernandes

ViniGodoy:
E o que ele está desenhando?

PS: É melhor fazer o g2d.dispose() antes de fazer o draw. Troque a linha 09 com a 10 de lugar.

Cara, agora deu certo! Quero dizer, quase…todos os pixels estão vindo como se estivessem com a cor preta…Mas eu coloquei o fundo do panel para branco(talvez o erro seja aqui. Ainda estou olhando). Deixa eu colocar o código todo, daí explico.

public class DrawLetter extends JPanel implements MouseMotionListener, MouseListener {
	
	private static final long serialVersionUID = 1L;
	public int x = -10;
	public int y = -10;
	public static int width;
	public static int height;
	BufferedImage bI;
	Graphics2D g2d;
	public static DrawLetter panel;

	public DrawLetter() {
	   addMouseMotionListener(this);
	   addMouseListener(this);
	   setBackground(Color.white);
	}

	@Override
	public void mouseClicked(MouseEvent e) {
		x = e.getX();
		y = e.getY();
		System.out.println("Mouse clicked at position X = " + x + " Y = " + y);
		repaint();
	}
	@Override
	public void mouseEntered(MouseEvent e) {
	}
	@Override
	public void mouseExited(MouseEvent e) {
	}
	@Override
	public void mousePressed(MouseEvent e) {
	}
	@Override
	public void mouseReleased(MouseEvent e) {
	}
	@Override
	public void mouseDragged(MouseEvent e) {
	}
	@Override
	public void mouseMoved(MouseEvent e) {
	} 
	 @Override
	public void paintComponent(Graphics g) {
		//super.paintComponent(g);
		 
		bI = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
		g2d = (Graphics2D)bI.createGraphics(); //Desenha sobre a imagem
		
		g2d.setColor(Color.black);		
		g2d.fillOval(x,y,4,4);

		g2d.dispose();
		
		g.drawImage(bI, 0, 0, null); //Desenha sobre o jpanel
	}
	
	public void printPanel() {
		for(int l = 0; l < width; l++) {
			for(int c = 0; c < height; c++) {
				int pixelClicked = bI.getRGB(l, c);
				
				int red = (pixelClicked & 0x00FF0000) >> 16;
				int green = (pixelClicked & 0x0000FF00) >> 8;
				int blue = pixelClicked & 0x000000FF;
				
				Color colorPixelClicked = new Color(red, green, blue);
				Color colorBlack = new Color(0, 0, 0);
				
				if (colorPixelClicked.equals(colorBlack)) {
					System.out.println("DEBUG - " + l + " and Y = " + c + " Color = " + pixelClicked);
			        }
			}
		}
	}
	
	public static void main(String[] args) {
		
	   JFrame.setDefaultLookAndFeelDecorated(true);
	   JFrame frame = new JFrame("My Window");
	   JButton button = new JButton("Get Pixel Clicked");
	   panel = new DrawLetter();
		
	    frame.getContentPane().setLayout(new BorderLayout());
	    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	    frame.setPreferredSize(new Dimension(500, 300));
	    frame.getContentPane().setBackground(Color.white);
	    frame.getContentPane().add(panel, BorderLayout.CENTER);
	    frame.getContentPane().add(button, BorderLayout.SOUTH);
	    
	    frame.setResizable(false);  
	    frame.pack();
	    frame.setVisible(true);
	    
	    width = panel.getWidth();
	    height = panel.getHeight();
	    
	    button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent a) {
				panel.printPanel();
			}
		});
	}
}

Na verdade vou fazer um OCR. Vou desenhar uma letra, varrer a tela e identificar a forma da letra pela mudança de cor dos pixels. Ou seja, o fundo está branco e depois que desenhar os pequenos cículos(fillOval()), vou buscar onde houve mudança de cor(BufferedImage.getRGB()) - onde está preto(que foi a cor que deixei para os pixels que serão pintados). Posso ter problemas, pois tenho que ver a questão de transparência…mas de qualquer forma estou tendo um erro, pois TODOS os pixels estão sendo indentificados como pretos…É alguma coisa com o BufferedImage que estou deixando passar batido…Se alguém souber…mas estou pesquisando…se conseguir, deixo a solução aqui!

ViniGodoy

Tente assim:

public void printPanel() {  
        for(int l = 0; l < width; l++) {  
            for(int c = 0; c < height; c++) {  
                int pixelClicked = bI.getRGB(l, c) & 0x00FFFFFF;  
                  
                if (pixelClicked == 0) {  
                    System.out.println("DEBUG - " + l + " and Y = " + c + " Color = " + pixelClicked);  
                }  
            }  
        }  
    }

Outra coisa, assuma imagens RGB e descarte informação de transparência.
Na verdade, não seria melhor você trabalhar com escalas de cinza? Ou até mesmo usar um filtro de OTSU para binarizar sua imagem?

Caso contrário, pode ser difícil definir com exatidão o que é "preto". (ex: a color (1,1,1) não seria preta?)

gustavofernandes
ViniGodoy:
Tente assim:
public void printPanel() {  
        for(int l = 0; l < width; l++) {  
            for(int c = 0; c < height; c++) {  
                int pixelClicked = bI.getRGB(l, c) & 0x00FFFFFF;  
                  
                if (pixelClicked == 0) {  
                    System.out.println("DEBUG - " + l + " and Y = " + c + " Color = " + pixelClicked);  
                }  
            }  
        }  
    }

Outra coisa, assuma imagens RGB e descarte informação de transparência.
Na verdade, não seria melhor você trabalhar com escalas de cinza? Ou até mesmo usar um filtro de OTSU para binarizar sua imagem?

Caso contrário, pode ser difícil definir com exatidão o que é "preto". (ex: a color (1,1,1) não seria preta?)

Pois é Vini, esse é o "problema" para resolver....mas acho que entendi uma coisinha. Quando eu defino o BufferedImage.TYPE_INT_ARGB que nesse caso está com transparência, não consigo ver a cor de fundo da imagem...daí aparece o fundo do panel que é branco. Quando troco o tipo do BufferedImage para BufferedImage.TYPE_INT_RGB, tiro a transparência e consigo visualizar o fundo da imagem, ques está totalmente preta. É por isso que os pixels estão todos sendo identificados como pretos. Vou ver uma forma de criar um quadrado do tamanho do buffer e deixá-lo com fundo branco. Daí toda vez que pintar a imagem apenas tenho que deixar a mesma instância desse quadrado sempre de fundo senão fico apagando os pixels anteriores. Vou ir testando aqui e logo logo, acho que encontro a solução. SObre usar esse filtro que falou, tenho que ler na API o que seria ideal para fazer isse tipo de coisa....a ideia de usar o BufferedImage foi porque encontrei nmuita gente usando para algo parecido...nem cheguei a ler a API direito...rsrsrs...Enfim, se eu resolver alguma coisa, posto aqui, pois talvez ajude muita gente.

gustavofernandes

Deu certo cara!! Valeu pela ajuda!!! :smiley: :smiley:
Usei o que você recomendou e troquei o BufferedImage.TYPE_INT_RGB mantendo um “fundo” branco para ele. MAS, agora é tratar os vários pixels selecionados. Vou ver o esquema de binarizar a imagem que você propôs. Mas para a solução do tópico, foi resolvido o problema de pegar pixels pela cor do BufferedImage. Pode colocar como tópico solucionado. Valeu!!

Criado 19 de abril de 2012
Ultima resposta 20 de abr. de 2012
Respostas 7
Participantes 2