Subtração de imagens binárias

Olá! Eu preciso desenvolver um programa que receba 2 imagens e realize a subtração delas. Segue as imagens a seguir:

Foi indicado que pegasse os pixels da imagem, transformasse em uma matriz e subtraísse elas. Como posso fazer isso? Segue o código que possuo através de pesquisas aqui no próprio fórum (realizei algumas modificações e testes com System.out.println a fim de fazer ter resultado com minhas imagens, mas o resultado gerado é bem errôneo ainda [resultado final gera uma imagem completamente preta :confused: ]).

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileNameExtensionFilter;
/**
 *
 * @author Admin
 */
public class ExemploSubtracao {
    public int subtract(int color1, int color2) {
        System.out.println("---- entrei no subtract ----");

        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_BYTE_BINARY);
        System.out.println("entrei no subtract do buffered");
        
        for (int y = 0; y < img1.getHeight(); y++)
            for (int x = 0; x < img1.getWidth(); x++)
                out.setRGB(x, y, subtract(img1.getRGB(x, y), img2.getRGB(x, y)));

        return out;
    }

    void doIt() throws IOException {
        File arquivo = null;
        File arquivo2 = null;
        JFileChooser chooser = new JFileChooser();  //Cria uma instância do JFileChooser 
        JFileChooser chooser2 = new JFileChooser();  //Cria uma instância do JFileChooser  
        FileNameExtensionFilter filter = new FileNameExtensionFilter("JPG, PNG & GIF Images", "jpg", "gif", "png");  //Cria um filtro  
        chooser.setFileFilter(filter);  //Altera o filtro do JFileChooser 
        chooser2.setFileFilter(filter);  //Altera o filtro do JFileChooser  
        int returnVal = chooser.showOpenDialog(null); //Abre o diálogo JFileChooser  
        int returnVal2 = chooser.showOpenDialog(null); //Abre o diálogo JFileChooser  
        if(returnVal == JFileChooser.APPROVE_OPTION && returnVal2 == JFileChooser.APPROVE_OPTION) {  //Verifica se o usuário clicou no botão OK  
            arquivo = chooser.getSelectedFile();
            arquivo2 = chooser.getSelectedFile();
            System.out.println("OK, selecionei 2 imagens");
        }else {
            JOptionPane.showMessageDialog(null,"Abertura de arquivo cancelada!\n",""
                +"Cancelar", JOptionPane.INFORMATION_MESSAGE);
            return;//corrrige o erro gerados a não escolher um arquivo
        }
        
        BufferedImage img1 = ImageIO.read(arquivo);
        BufferedImage img2 = ImageIO.read(arquivo2);
        
        System.out.println("dps dos buffered");
        // Filtra o que existe na imagem2 mas não na imagem1.
        ImageIO.write(subtract(img2, img1), "png", new File("Imagem_Subtracao1.png"));
        JOptionPane.showMessageDialog(null, "Finalizado com sucesso!!!");
    }

    public static void main(String[] args) throws Exception {
        new ExemploSubtracao().doIt();
    }
    
}

Então… Como posso fazer com que pegue os pixels dessas imagens que recebo para uma matriz e depois subtrair? Desde já obrigada a todos que puderem ajudar!

O ideal, é antes de fazer a codificação, entender o que ela tem que fazer.

1 - as imagens devem ter a mesma largura e a mesma altura, pois a subtração será em pares.
2 - Basicamente o que vai ter que fazer é matriciar as duas imagens e DEPOIS realizar a subtração pixel por pixel.
3 - Cada cor esta associada a um número inteiro, assim, você pode usar duas matrizes bidimensionais de números inteiros;

Ex.:
int[][] img1 = new int[largura da imagem 1][ altura da imagem 1];
int[][] img2 = new int[largura da imagem 2][altura da imagem 2];
Se as áreas das duas forem diferentes elas não podem ser subtraídas nos parâmetros especificados.
A imagem é justamente isto, uma matriz bidimensional, portanto, você pode percorrer ela com um for para a linha e outro para a coluna, uma vez para cada imagem e armazenando o valor inteiro em cada matriz correspondente.
Por fim, use outra matriz bidimensional para armazenar o resultado da subtração e se quiser ver o resultado imprima esta ultima matriz usando a ferramenta graphics.

A segunda folha utilizou o método subtract, que vc informou, entretanto, removi a implementação pois o correto é fornecer créditos ao autor e eu não tenho a referência.
A primeira folha foi conseguida com a codificação a seguir:

package crisis;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;

public abstract class Imagem {

    public static Image compor(Image imagem1, Image imagem2) {
        int largura = (imagem1.getWidth(null) == imagem2.getWidth(null) ? imagem1.getWidth(null) : 0),
                altura = (imagem1.getHeight(null) == imagem2.getHeight(null) ? imagem1.getHeight(null) : 0);

        if (altura * largura > 0) {
            int[][][] composicao = new int[2][largura][altura];
            matriciar(composicao[0], imagem1);
            matriciar(composicao[1], imagem2);
            return Imagem.compor(composicao, largura, altura);
        } else {
            return null;
        }

    }

    private static void matriciar(int[][] composicao, Image imagem) {
        BufferedImage img = new BufferedImage(imagem.getWidth(null), imagem.getHeight(null), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = img.createGraphics();
        g.drawImage(imagem, 0, 0, null);
        for (int linha = 0; linha < composicao.length; linha++) {
            for (int coluna = 0; coluna < composicao[linha].length; coluna++) {
                composicao[linha][coluna] = img.getRGB(linha, coluna);
            }
        }
        g.dispose();
    }

    private static BufferedImage compor(int[][][] composicao, int largura, int altura) {
        BufferedImage compor = new BufferedImage(largura, altura, BufferedImage.TYPE_INT_ARGB),
                composicaoReduzida = new BufferedImage(largura/4, altura/4, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = compor.createGraphics();
        for (int i = 0; i < largura; i++) {
            for (int j = 0; j < altura; j++) {
                //se quiser pode usar o método subtract que vc mostrou alterando a linha a seguir
                g.setColor(new Color(composicao[0][i][j] - composicao[1][i][j]));
                g.drawLine(j, j, i, j);
            }
        }
        
        g.dispose();
        g = composicaoReduzida.createGraphics();
        //reduzi o tamanho da imagem para poder visualisar na tela
        g.drawImage(compor, 0, 0, largura/4, altura/4, null);
        return composicaoReduzida;
    }
}

Como dito, o importante é entender.
Para seu aprendizado, procure entender o funcionamento.
Foi legalzin essa codificação.

1 curtida

Essa subtração me parece equivocava, pois se você pegar preto (0) e tentar subtrair qualquer outra cor ( > 0), vai resultar somente em preto.

Vê se assim não resolve:

int r = diferenca(c1.getRed(),   c2.getRed());
int g = diferenca(c1.getGreen(), c2.getGreen());
int b = diferenca(c1.getBlue(),  c2.getBlue());

int diferenca(int a, int b) {
    int delta = a - b;
    return delta < 0
            ? 0xFF + delta
            : delta;
}