Processamento Digital de Imagens (PDI) com Java

Tratar imagens digitalmente é uma coisa cada vez mais comum, seja para fazer correções de luz, cor, retirar imperfeições ou tratá-las para uma determinada finalidade, como identificar elementos na imagem de forma automática (ex: identificar uma placa de carro em uma imagem).

Para tal, é necessária a utilização de um ou de vários filtros para que o objetivo seja alcançado. A seguir, uma lista com alguns dos filtros mais usados e uma breve explicação sobre eles:

 

  • Desaturação (escala de cinza): deixa uma imagem em escala de cinza, ou seja, uma imagem colorida terá apenas pixels brancos, pretos ou cinzas;
  • Binarização (Threshold): consiste em deixar uma imagem em preto e branco, cada pixel da imagem original se transforma em um pixel totalmente branco (RGB #FFFFFF) ou totalmente preto (RGB #000000). Para determinar se um pixel da imagem original se tornará preto ou branco é usado um limiar, um valor que determina a partir de qual ponto um pixel se tornará preto ou se tornará branco. A imagem tratada por este filtro não contém pixel cinza, apenas preto e/ou branco, diferente da desaturação;
  • Negativo: este filtro faz com que a cor de cada pixel da imagem original se transforme na cor inversa (ex: pixel branco se transforma em pixel preto). A cor inversa é o valor da subtração entre 255 e o valor RGB. Ex: para um amarelo com valor RGB 255, 240, 0, sua cor inversa é o RGB 0, 15, 255.
  • Mediana: filtro usado para eliminar ruídos da imagem. O algoritmo faz um cálculo da média de cores de uma certa região de pixels e determina a cor média daquele trecho da imagem. Se houver um pixel preto (ruído) em meio há vários pixels brancos a aplicação do filtro eliminará este pixel preto, tirando o ruído da imagem.

Saiba mais sobre tratamento digital de imagens: PDI

Conheça os principais filtros do Adobe Photoshop: Filtros Photoshop

Bom, agora vamos ao que interessa: criar os filtros utilizando a linguagem JAVA!

Vou criar uma classe chamada App1 que simplesmente vai aplicar o filtro para deixar uma imagem em escala de cinza, e outra classe chamada Filtro que conterá os algoritmos dos filtros. A classe Exibicao servirá apenas para exibir as imagens utilizadas em um componente JFrame, nada muito funcional, apenas para deixar o exemplo mais “bonitinho”.

App1.java

public class App1 {

	public static void main(String[] args) throws IOException {

		try {
			//carrega nova imagem
			BufferedImage imagem1 = ImageIO.read(new File("images/imagem1.jpg"));
			//instancia um filtro e aplica a escala de cinza
			Filtro filtro = new Filtro();
			filtro.escalaDeCinza(imagem1);
			//gera uma nova imagem a partir da imagem1
			ImageIO.write(imagem1,"jpg",new File("images/imagem2.jpg"));

			//aqui apenas para demonstração,
			//carreguei novamente as duas imagens para exibi-las dentro de um JFrame
			imagem1 = ImageIO.read(new File("images/imagem1.jpg"));
			BufferedImage imagem2 = ImageIO.read(new File("images/imagem2.jpg"));
			Exibicao show = new Exibicao();
			show.exibirImagem(imagem1, imagem2);
			System.out.println("Filtro aplicado com sucesso!");
		}
		catch(IOException e){
			System.out.println("Erro! Verifique se o arquivo especificado existe e tente novamente.");
		}
		catch(Exception e){
			System.out.println("Erro! " + e.getMessage());
		}
	}

}

Filtro.java

public class Filtro {

	//método de aplicação do filtro escala de cinza
	//recebe como parâmetro uma imagem
	public static BufferedImage escalaDeCinza(BufferedImage imagem) {
		//pegar largura e altura da imagem
		int width = imagem.getWidth();
		int height = imagem.getHeight();

		int media = 0;
		//laço para varrer a matriz de pixels da imagem
		for (int i = 0; i < width; i++) {
			for (int j = 0; j < height; j++) { 				//rgb recebe o valor RGB do pixel em questão 				int rgb = imagem.getRGB(i, j); 				int r = (int)((rgb&0x00FF0000)>>>16); //R
				int g = (int)((rgb&0x0000FF00)>>>8);  //G
				int b = (int) (rgb&0x000000FF);       //B

				//media dos valores do RGB
				//será o valor do pixel na nova imagem
				media = (r + g + b) / 3;

				//criar uma instância de Color
				Color color = new Color(media, media, media);
				//setar o valor do pixel com a nova cor
				imagem.setRGB(i, j, color.getRGB());
			}
		}
		return imagem;
	}

	public static BufferedImage negativo(BufferedImage image) {
		int width = image.getWidth();
		int height = image.getHeight();
		for (int i = 0; i < width; i++) {
			for (int j = 0; j < height; j++) { 				int rgb = image.getRGB(i, j); 				//a cor inversa é dado por 255 menos o valor da cor 				int r = 255 - (int)((rgb&0x00FF0000)>>>16);
				int g = 255 - (int)((rgb&0x0000FF00)>>>8);
				int b = 255 - (int) (rgb&0x000000FF);
				Color color = new Color(r, g, b);
				image.setRGB(i, j, color.getRGB());
			}
		}
		return image;
	}

	public static BufferedImage threshold(BufferedImage image, int limiar) {
		int width = image.getWidth();
		int height = image.getHeight();
		for (int i = 0; i < width; i++) {
			for (int j = 0; j < height; j++) { 				int rgb = image.getRGB(i, j); 				int r = (int)((rgb&0x00FF0000)>>>16);
				int g = (int)((rgb&0x0000FF00)>>>8);
				int b = (int) (rgb&0x000000FF);
				int media = (r + g + b) / 3;
				Color white = new Color(255, 255, 255);
				Color black = new Color(0, 0, 0);
				//como explicado no artigo, no threshold definimos um limiar,
				//que é um valor "divisor de águas"
				//pixels com valor ABAIXO do limiar viram pixels PRETOS,
				//pixels com valor ACIMA do limiar viram pixels BRANCOS
				if (media < limiar)
					image.setRGB(i, j, black.getRGB());
				else
					image.setRGB(i, j, white.getRGB());
			}
		}
		return image;
	}

Exibicao.java

public class Exibicao {

	public static void exibirImagem(BufferedImage image) {
		ImageIcon icon = new ImageIcon(image);
		JLabel imageLabel = new JLabel(icon);
		JFrame frame = new JFrame();
		Container contentPane = frame.getContentPane();
		contentPane.setLayout(new GridLayout());
		contentPane.add(new JScrollPane(imageLabel));
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(800, 600);
		frame.setVisible(true);
	}

	public static void exibirImagem(BufferedImage image, BufferedImage image2) {
		ImageIcon icon = new ImageIcon(image);
		JLabel imageLabel = new JLabel(icon);
		ImageIcon icon2 = new ImageIcon(image2);
		JLabel imageLabel2 = new JLabel(icon2);
		JFrame frame = new JFrame();
		Container contentPane = frame.getContentPane();
		contentPane.setLayout(new GridLayout());
		contentPane.add(new JScrollPane(imageLabel));
		contentPane.add(new JScrollPane(imageLabel2));
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(1100, 680);
		frame.setVisible(true);
	}
}

Na classe Filtro acima só tem três filtros, depois tentarei publicar os códigos de mais filtros e mais materiais sobre o assunto (espero encontrar tempo para isso xD).
Inté mais!

3 comments so far

  1. ricardo on

    esses metodos me ajudaram bastante

  2. Nathan on

    Muito obrigado pelo pontapé inicial. Já ajuda bastante.

  3. Glayson Junio on

    Republicou isso em Glayson Junio.


Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: