比较 2 个图像并用矩形标记差异

问题描述 投票:0回答:1

编辑:更新了代码,下面的代码现在可以正确地围绕多个形状绘制矩形,但仍然存在一个小问题,即有时会在一个形状上创建多个矩形。

我有 2 个图像,我将它们逐像素进行比较,并且我希望我的程序在差异区域周围创建矩形(具有多个差异实例的多个矩形)。到目前为止,我设法用一个矩形来做到这一点,所以如果我有多个“实例”,它们都会在一个大矩形中。现在我试图让程序创建多个矩形,但遇到了 IndexOutOfBoundsException。

程序本身覆盖与不透明度进行比较的 2 个图像,并将生成的覆盖图像与矩形一起输出到新文件中。被比较的两个图像具有一致的相等宽度和高度。

我在代码中将要绘制的矩形称为“区域”。 在比较过程中,区域列表会不断更新。

我问自己的第一个问题是,什么时候差异点(像素差异)属于一个区域? 我的尝试是定义一个“容差”,因此只要被比较的像素在最后发现的差异点的容差范围内,它就属于同一区域。我很快意识到,当我的图像上有一个巨大的 U 形形状时,这不起作用,并且顶点之间的距离足够远,不在公差范围内。现在我有点陷入困境,因为我觉得我走错了路。

下面是我到目前为止的代码:

private void compareImages() throws IOException{
    BufferedImage img1;
    BufferedImage img2;
    try {
        img1 = ImageIO.read(new File(path_to_img1));
        img2 = ImageIO.read(new File(path_to_img2));
    } catch (Throwable e) {
        System.out.println("Unable to load the Images!");
        return;
    }
    BufferedImage dest = new BufferedImage(img1.getWidth(), img1.getHeight(), BufferedImage.TYPE_INT_ARGB);
    Graphics2D gfx = dest.createGraphics();
    gfx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.65f));

    //Compare Images pixel by pixel
    int sX = 9999; //Start X
    int sY = 9999; //Start Y
    int eX = 0; //End X
    int eY = 0; //End Y
    boolean isDrawable = false;
    boolean loadedRegion = false;
    List<Rectangle> regions = new ArrayList<>();
    List<Rectangle> check_regions = new ArrayList<>();
    Rectangle tmp_comparison;
    int regionID = 0;
    int tolerance = 25;

    for (int i = 0; i < img1.getHeight(); i++) {
        for (int j = 0; j < img1.getWidth(); j++) {
            loadedRegion = false;
            regionID = 0;
            sX = 9999;
            sY = 9999;
            eX = 0;
            eY = 0;
            if ( img1.getRGB(j, i) != img2.getRGB(j, i) ){
                isDrawable = true;
                if (regions.size() != 0){
                    //Attempting to locate a matching existing Region
                    tmp_comparison = new Rectangle(j, i, 1, 1);
                    for (int trID = 0; trID<regions.size(); trID++){
                        if (tmp_comparison.intersects(check_regions.get(trID).getBounds()) == true) {
                            // Region found
                            sX = (int) regions.get(trID).getX();
                            sY = (int) regions.get(trID).getY();
                            eX = (int) regions.get(trID).getWidth();
                            eY = (int) regions.get(trID).getHeight();
                            regionID = trID;
                            loadedRegion = true;
                            break;
                        }
                    }
                }
                //Update Region Dimension
                if (j<sX){
                    sX = j;
                }
                if (j>eX){
                    eX = j;
                }
                if (i<sY){
                    sY = i;
                }
                if (i>eY){
                    eY = i;
                }
                if (regions.size() == 0 || loadedRegion == false){
                    regions.add(new Rectangle(sX, sY, eX, eY));
                    check_regions.add(new Rectangle(sX-tolerance, sY-tolerance, eX-sX+(tolerance*2), eY-sY+(tolerance*2)));
                } else {
                    regions.set(regionID, new Rectangle(sX, sY, eX, eY));
                    check_regions.set(regionID, new Rectangle(sX-tolerance, sY-tolerance, eX-sX+(tolerance*2), eY-sY+(tolerance*2)));
                }
            }
        }
    }
    // If there are any differences, draw the Regions
    // Regions are 10px bigger in all directions as compared to the actual rectangles of difference
    if (isDrawable == true){
        gfx.setPaint(Color.red);
        for (int i = 0; i<regions.size(); i++) {
            int dsX = 0;
            int dsY = 0;
            int deX = 0;
            int deY = 0;
            sX = (int) regions.get(i).getX();
            sY = (int) regions.get(i).getY();
            eX = (int) regions.get(i).getWidth();
            eY = (int) regions.get(i).getHeight();
            if (sX>=10){dsX = sX-10;}
            if (eX<=img1.getWidth()-10){deX = eX-sX+20;}
            if (sY>=10){dsY = sY-10;}
            if (eY<=img1.getHeight()-10){deY = eY-sY+20;}
            gfx.draw(new Rectangle2D.Double(dsX, dsY, deX, deY));
        }
    }
    gfx.drawImage(img1, 0, 0, null);
    gfx.drawImage(img2, 0, 0, null);
    gfx.dispose();
    File out = new File("C:\\output.png");
    ImageIO.write(dest, "PNG", out);
}

下面的代码围绕正在比较的图像中发现的所有差异创建一个大矩形。

private void oneRectangle() throws IOException{
    BufferedImage img1;
    BufferedImage img2;
    try {
        img1 = ImageIO.read(new File(path_to_img1));
        img2 = ImageIO.read(new File(path_to_img2));
    } catch (Throwable e) {
        System.out.println("Unable to load the Images!");
        return;
    }
    BufferedImage dest = new BufferedImage(img1.getWidth(), img1.getHeight(), BufferedImage.TYPE_INT_ARGB);
    Graphics2D gfx = dest.createGraphics();
    gfx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.65f));

    //Compare Images pixel by pixel
    boolean isDrawable = false;
    int sX = 9999;
    int sY = 9999;
    int eX = 0;
    int eY = 0;

    for (int i = 0; i < img1.getHeight(); i++) {
        for (int j = 0; j < img1.getWidth(); j++) {
            if ( img1.getRGB(j, i) != img2.getRGB(j, i) ){
                isDrawable = true;                      
                if (j<sX){
                    sX = j;
                }
                if (j>eX){
                    eX = j;
                }
                if (i<sY){
                    sY = i;
                }
                if (i>eY){
                    eY = i;
                }
            }
        }
    }
    // Draw rectangle if there are any differences
    if (isDrawable == true){
        gfx.setPaint(Color.red);
        int dsX = 0;
        int dsY = 0;
        int deX = 0;
        int deY = 0;
        if (sX>=10){dsX = sX-10;}
        if (eX<=img1.getWidth()-10){deX = eX-sX+20;}
        if (sY>=10){dsY = sY-10;}
        if (eY<=img1.getHeight()-10){deY = eY-sY+20;}
        gfx.fill(new Rectangle2D.Double(dsX, dsY, deX, deY));
    }
    gfx.drawImage(img1, 0, 0, null);
    gfx.drawImage(img2, 0, 0, null);
    gfx.dispose();
    File out = new File("C:\\output.png");
    ImageIO.write(dest, "PNG", out);
}
java image image-processing
1个回答
0
投票

感谢您提供示例代码。我发现多个矩形的问题取决于如何发现差异。基本上,最初会有两个点不够接近而无法加入,但在某个时刻,其中一个盒子会变得足够大,以至于它们可以加入。我发现管理此问题的最简单方法是清理最后的所有相交边界。我还发现,通过水平扫描而不是垂直扫描,我得到的这些伪像更少,因为我正在比较人类文本。

//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;
            }
        }
    }
}

我修改了原始代码以简化一点。

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();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.