找到两个图像之间的不同区域

时间:2014-10-28 13:18:30

标签: algorithm image-processing

我的目的是比较两个图像之间的像素并找出最小的(优化的) 矩形区域,包含图像之间的所有不同像素。 简单地说,我比较了两个图像的所有像素(例如1024 * 768像素)并发现了不同的部分,但由于速度,这不是一个好主意。 我需要比较每秒至少十五次。 你知道更有效的算法吗?

2 个答案:

答案 0 :(得分:8)

从另一个图像中减去一个图像。相同的像素将变为零,即黑色。

找到一个黑色的角落并使用trim(修剪边框/边缘)类型的命令来修剪黑色边框,这将告诉您区别的区域。

如果可以使用它,可以在ImageMagick的两行中很简单 - 它可以在许多平台上用于C / C ++,Python,Perl ......

我们拍摄两张图片,a.jpgb.jpg

enter image description here

enter image description here

你看到我在那里做了什么吗? :-)

现在我们可以使用ImageMagick来查找差异和不同区域。我正在使用命令行,但正如我所说,你可以使用C / C ++,Perl,Python,.NET或任何漂浮你的船。

使用它来找出差异:

convert a.jpg b.jpg \
       -compose difference \
       -composite \
       -threshold 0 \
       -separate \
       -evaluate-sequence Add \
        diff.jpg

给出了这个:

enter image description here

或者使用它:

composite a.jpg b.jpg  -compose difference diff.jpg

给出了这个:

enter image description here

或者用它来进行简单的减法:

convert a.jpg b.jpg -compose minus -composite diff.jpg

enter image description here

现在你可以使用ImageMagick的边框修剪功能来评估如果你修剪掉所有黑色边框会留下什么,如下所示:

convert a.jpg b.jpg \
       -compose difference \
       -composite \
       -threshold 0 \
       -separate \
       -evaluate-sequence Add \
       -format "%w %h %@" \
        info:

输出:

400 463 264x240+80+176

告诉你图像是400x463,如果你裁剪边框,你将留下一个长方形264x240,其左上角的像素从图像的左上角偏移80,176。

为了好玩,我将使用此命令将该矩形绘制成红色的图像:

convert diff.jpg \
       -stroke red \
       -fill transparent \
       -draw "rectangle 80,176 344,416" \
        rect.jpg

给出了这个:

enter image description here

基本上你可以用一行或两行shell或8-10行C / C ++完成我在这里解释的所有内容。请注意,边界框略大,因为我叠加的漫画具有透明的矩形背景。如果您需要在差异中允许一定程度的“邋iness”,您还可以使用-fuzz 5%来允许图像中的细微差别。

检测边界框的另一种方法是 squidge 差异图像,直到它是一个高像,只有一个像素宽,如下所示:

convert diff.jpg -scale 1x! -threshold 1% t.jpg

下面的结果图片:

enter image description here

现在你可以轻松地找到第一个白色像素,如果你将输出转换为文本格式(你不会在程序中这样做 - 你会写一个循环而不是 - 但我在这里展示了这个概念):< / p>

convert diff.jpg -scale 1x! -threshold 1% txt: | grep -m1 white

 0,176: (255,255,255)  #FFFFFF  white

grep -m1 white查找其中包含white的第一行,然后停止查找(匹配限制为1)。这表明第一行中有一个白色像素是176 - 与上面的红色框相比。现在我们可以使用:

找到最后一个白色像素
convert diff.jpg -scale 1x! -threshold 1% txt: | grep white | tail -1

 0,415: (255,255,255)  #FFFFFF  white

我们知道第415行是边界框的底部。

现在,您将图像分解为宽度仅为1像素的宽扁平版本,并找到边界框的左右限制:

convert diff.jpg -scale x1! -threshold 1% txt: | grep -m1 white

 80,0: (255,255,255)  #FFFFFF  white

convert diff.jpg -scale x1! -threshold 1% txt: | grep white | tail -1

 343,0: (255,255,255)  #FFFFFF  white

因此,您的边界框的左右限制为80和343 - 根据红色矩形。

答案 1 :(得分:1)

如果您的像素值存储在2D数组中(暂时称为灰度,0-255),您可以做的就是将数组视为矩阵,然后从减去两者开始。结果中的条目为零是相同的像素,非零意味着它们是不同的。然后你会发现包含一个非零项的顶行作为你的y-MAX,你的y-MIN的最低行为非零,第一列的x-MIN为非零,最后一列为非零对于x-MAX。然后矩形有4个坐标:

  • (x-MIN,y-MIN) - 左下角
  • (x-MAX,y-MIN) - 右下角
  • (x-MAX,y-MAX) - 右上角
  • (x-MIN,y-MAX) - 左上角

如果您碰巧知道所有条目都至少为零(可以通过获取绝对值来完成,但这会增加成本),那么您可以将矩阵乘以右侧的全1列向量。这将为您提供行和。然后你找到第一个和最后一个非零行和(搜索自上而下和自下而上)。如果你在左边乘以全1的行向量,你会得到相同的东西,但是列总和。再看一下那些非零。

矩阵运算很好,因为有优化的库可以帮助加速计算(并且你的矩阵不是那么大)...特别是如果你有GPU可以用来进行计算。但即使是连续的,小矩阵矢量计算并不耗费时间。