我的目的是比较两个图像之间的像素并找出最小的(优化的) 矩形区域,包含图像之间的所有不同像素。 简单地说,我比较了两个图像的所有像素(例如1024 * 768像素)并发现了不同的部分,但由于速度,这不是一个好主意。 我需要比较每秒至少十五次。 你知道更有效的算法吗?
答案 0 :(得分:8)
从另一个图像中减去一个图像。相同的像素将变为零,即黑色。
找到一个黑色的角落并使用trim
(修剪边框/边缘)类型的命令来修剪黑色边框,这将告诉您区别的区域。
如果可以使用它,可以在ImageMagick的两行中很简单 - 它可以在许多平台上用于C / C ++,Python,Perl ......
我们拍摄两张图片,a.jpg
和b.jpg
:
你看到我在那里做了什么吗? :-)
现在我们可以使用ImageMagick来查找差异和不同区域。我正在使用命令行,但正如我所说,你可以使用C / C ++,Perl,Python,.NET或任何漂浮你的船。
使用它来找出差异:
convert a.jpg b.jpg \
-compose difference \
-composite \
-threshold 0 \
-separate \
-evaluate-sequence Add \
diff.jpg
给出了这个:
或者使用它:
composite a.jpg b.jpg -compose difference diff.jpg
给出了这个:
或者用它来进行简单的减法:
convert a.jpg b.jpg -compose minus -composite diff.jpg
现在你可以使用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
给出了这个:
基本上你可以用一行或两行shell或8-10行C / C ++完成我在这里解释的所有内容。请注意,边界框略大,因为我叠加的漫画具有透明的矩形背景。如果您需要在差异中允许一定程度的“邋iness”,您还可以使用-fuzz 5%
来允许图像中的细微差别。
检测边界框的另一种方法是 squidge 差异图像,直到它是一个高像,只有一个像素宽,如下所示:
convert diff.jpg -scale 1x! -threshold 1% t.jpg
下面的结果图片:
现在你可以轻松地找到第一个白色像素,如果你将输出转换为文本格式(你不会在程序中这样做 - 你会写一个循环而不是 - 但我在这里展示了这个概念):< / 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个坐标:
如果您碰巧知道所有条目都至少为零(可以通过获取绝对值来完成,但这会增加成本),那么您可以将矩阵乘以右侧的全1列向量。这将为您提供行和。然后你找到第一个和最后一个非零行和(搜索自上而下和自下而上)。如果你在左边乘以全1的行向量,你会得到相同的东西,但是列总和。再看一下那些非零。
矩阵运算很好,因为有优化的库可以帮助加速计算(并且你的矩阵不是那么大)...特别是如果你有GPU可以用来进行计算。但即使是连续的,小矩阵矢量计算并不耗费时间。