【问题标题】:Replace all occurrences of one image inside another image替换另一张图片中所有出现的一张图片
【发布时间】:2013-06-13 06:09:37
【问题描述】:

在 Java 中,我试图在另一个 BufferedImage 中替换一个 BufferedImage。

例如, 可以在 中替换为,这样就可以生成。

是否可以编写一个函数,将一个 BufferedImage 替换为另一个 BufferedImage,并返回生成的 BufferedImage?

public static BufferedImage replaceInsideBufferedImage(BufferedImage containingImage, BufferedImage toBeReplaced, BufferedImage replaceWithThis){
//In containingImage, replace all occurrences of toBeReplaced with replaceWithThis    
}

【问题讨论】:

  • 只需搜索模式,找到后替换它。哪些部分是你不能实现的?
  • @thejh 为了搜索模式,我可能需要以某种方式将每个 BufferedImage 转换为 2d 整数数组,然后在替换其中的一个整数数组后将结果数组转换回 BufferedImage另一个整数数组。将每个 BufferedImage 转换为整数数组(反之亦然)会很麻烦:有没有更简单的方法来解决这个问题?
  • 我刚刚发现了一个密切相关的问题,询问如何在另一个图像中查找图像:stackoverflow.com/questions/454498/…

标签: java bufferedimage


【解决方案1】:

下面的方法可以解决问题。伪代码:

  • (1) 对于containingImage 的每个像素:
    • 开始匹配toBeReplaced (逐个像素)
      • 如果找到它(所有像素都匹配),它会将所有像素替换为replaceWithThis
      • 如果不是,则返回 (1)

因为所有的模式都会被找到,最后会返回returnImage

replaceInsideBufferedImage()代码:

public static BufferedImage replaceInsideBufferedImage(BufferedImage containingImage, BufferedImage toBeReplaced, BufferedImage replaceWithThis) {
    BufferedImage returnImage = deepCopyImage(containingImage);
    for (int x = 0; x+toBeReplaced.getWidth() < containingImage.getWidth(); x++) {
        for (int y = 0; y+toBeReplaced.getHeight() < containingImage.getHeight(); y++) {
            BufferedImage subImg = containingImage.getSubimage(x, y, toBeReplaced.getWidth(), toBeReplaced.getHeight());
            if (imageEquals(subImg,toBeReplaced)) {
                for (int sx = 0; sx < replaceWithThis.getWidth(); sx++) {
                    for (int sy = 0; sy < replaceWithThis.getHeight(); sy++) {
                        returnImage.setRGB(x+sx, y+sy, replaceWithThis.getRGB(sx, sy));
                    }
                }
            }
        }
    }
    return returnImage;
}

完整的工作代码:

import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.io.File;

import javax.imageio.ImageIO;

public class ReplacePattern {

    public static void main(String[] args) throws Exception {
        BufferedImage containingImage = ImageIO.read(new File("fourWhites.png"));
        BufferedImage toBeReplaced = ImageIO.read(new File("oneWhite.png"));
        BufferedImage replaceWithThis = ImageIO.read(new File("oneRed.png"));
        BufferedImage replaced = replaceInsideBufferedImage(containingImage, toBeReplaced, replaceWithThis);
        ImageIO.write(replaced, "png", new File("fourReds.png"));
    }

    public static BufferedImage replaceInsideBufferedImage(BufferedImage containingImage, BufferedImage toBeReplaced, BufferedImage replaceWithThis) {
        BufferedImage returnImage = deepCopyImage(containingImage);
        for (int x = 0; x+toBeReplaced.getWidth() < containingImage.getWidth(); x++) {
            for (int y = 0; y+toBeReplaced.getHeight() < containingImage.getHeight(); y++) {
                BufferedImage subImg = containingImage.getSubimage(x, y, toBeReplaced.getWidth(), toBeReplaced.getHeight());
                if (imageEquals(subImg,toBeReplaced)) {
                    for (int sx = 0; sx < replaceWithThis.getWidth(); sx++) {
                        for (int sy = 0; sy < replaceWithThis.getHeight(); sy++) {
                            returnImage.setRGB(x+sx, y+sy, replaceWithThis.getRGB(sx, sy));
                        }
                    }
                }
            }
        }
        return returnImage;
    }

    // http://stackoverflow.com/a/3514297/1850609
    public static BufferedImage deepCopyImage(BufferedImage bi) {
        ColorModel cm = bi.getColorModel();
        boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
        WritableRaster raster = bi.copyData(null);
        return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
    }

    // http://stackoverflow.com/a/11006474/1850609
    private static boolean imageEquals(BufferedImage image1, BufferedImage image2) {
        int width;
        int height;
        boolean imagesEqual = true;
        if( image1.getWidth()  == ( width  = image2.getWidth() ) && 
            image1.getHeight() == ( height = image2.getHeight() ) ){
            for(int x = 0;imagesEqual == true && x < width; x++){
                for(int y = 0;imagesEqual == true && y < height; y++){
                    if( image1.getRGB(x, y) != image2.getRGB(x, y) ){
                        imagesEqual = false;
                    }
                }
            }
        }else{
            imagesEqual = false;
        }
        return imagesEqual;
    }
}

【讨论】:

    【解决方案2】:

    这是可能的,但我不建议这样做。

    检测一个图像是否存在于另一个图像中会很慢。

    此外,由于可能存在编码伪影,因此可能永远无法在另一张图像中检测到一张图像。在这种情况下,您将不得不实现更灵活的检测功能,这将花费更长的时间并可能导致误报。

    您很可能拥有从头开始重建映像的数据。无需对图像进行操作,只需获取用于生成初始图像的数据并基于它创建一个新图像。

    但如果你真的需要这样做,你将不得不遍历这两个图像并比较像素。使用getRGB()函数逐像素比较图像。

    【讨论】:

    • 我正在尝试用另一个特定图像中的另一个图像替换一个图像的所有匹配项。这三张图片中哪一张是您所指的“初始图片”?
    • 只要我使用无损格式(例如 .bmp 或 .png),就不会有任何编码伪影。
    • @AndersonGreen 初始图像是要查找其他图像的图像;至于工件:这就是我写 possible 的原因。
    • 另外,如果我正在使用的所有 3 个图像都是从外部文件生成的,我不确定如何“从头开始重建图像”。
    • @AndersonGreen 如果您首先将所有这些信息放在问题中,那么回答会简单得多。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多