Thanks for the example code. I found the issue with the multiple rectangles depends on how the differences are found. Basically there will be two points initially that aren't close enough to join but at some point one of the boxes will grow large enough that they could have. I found the easiest way to manage this is by cleaning up any intersecting boundaries at the end. I also found that I had less of these artifacts by scanning horizontally instead of vertically because I was comparing human text.
//Reduce intersecting rectangles
boolean fixed = true;
while(fixed) {
fixed = false;
for(int i = 0; i < regions.size(); i++){
for(int j = i+1; j < regions.size(); j++){
if(regions.get(i).intersects(regions.get(j))) {
regions.get(j).add(regions.get(i));
regions.remove(i--);
fixed = true;
break;
}
}
}
}
I modified the original code to simplify it a bit.
public static void compareImages() throws IOException {
BufferedImage img1 = ImageIO.read(new File(path_to_img1));
BufferedImage img2 = ImageIO.read(new File(path_to_img2));
BufferedImage dest = new BufferedImage(img1.getWidth(), img1.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D gfx = dest.createGraphics();
try {
gfx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.65f));
//Compare Images pixel by pixel
List<Rectangle> regions = new ArrayList<>();
int tolerance = 20;
for (int j = 0; j < img1.getWidth(); j++) {
pixelLoop: for (int i = 0; i < img1.getHeight(); i++) {
int img1rgb = img1.getRGB(j, i);
int img2rgb = img2.getRGB(j, i);
if(img1rgb != img2rgb) {
for(Rectangle region : regions){
//Attempting to locate a matching existing Region
Rectangle tmp_comparison = new Rectangle(j-tolerance, i-tolerance, 2*tolerance, 2*tolerance);
if (tmp_comparison.intersects(region)) {
region.add(new Rectangle(j, i, 1, 1));
continue pixelLoop;
}
}
regions.add(new Rectangle(j, i, 1, 1));
}
}
}
//Reduce intersecting rectangles
boolean fixed = true;
while(fixed) {
fixed = false;
for(int i = 0; i < regions.size(); i++){
for(int j = i+1; j < regions.size(); j++){
if(regions.get(i).intersects(regions.get(j))) {
regions.get(j).add(regions.get(i));
regions.remove(i--);
fixed = true;
break;
}
}
}
}
gfx.drawImage(img1, 0, 0, null);
gfx.drawImage(img2, 0, 0, null);
gfx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f));
gfx.setPaint(Color.red);
if(!regions.isEmpty()) {
// If there are any differences, draw the Regions
// Regions are 10px bigger in all directions as compared to the actual rectangles of difference
for (Rectangle region : regions) {
region.add(new Rectangle2D.Double(region.getX()-10, region.getY()-10, region.getWidth()+20, region.getHeight()+20));
gfx.draw(new Rectangle2D.Double(region.getX() >= 0 ? region.getX() : 0, region.getY() >= 0 ? region.getY() : 0, Math.min(img1.getWidth(), region.getWidth()), Math.min(img1.getHeight(), region.getHeight())));
}
File out = new File("C:\\output.png");
ImageIO.write(dest, "PNG", out);
}
} finally {
gfx.dispose();
}
}