获取一幅图像在另一幅图像中的位置

我有一个显示网站的浏览器截图。 现在我想找出网站(视口)的位置(相对于整个屏幕截图)。 在这个图像中看到一个带有黑色边框的矩形:

显示带有视口的样本截图的图像

在开始image processing之前,我有可能向网站的DOM添加任何东西。

我已经尝试生成QR码,将其添加到视口的左上angular和右下angular,然后使用imagemagick来确定QR码在较大图像中的位置:

compare -metric "rmse" -subimage-search -dissimilarity-threshold "0.1" -virtual-pixel "edge" "haystack.png" "needle.png" "results.png" 

然而,这需要很长的时间。 事实上,我在40分钟后辞职了。

我使用了QR码,因为通过使用时间戳,我可以确信这张图片不会在网站的其他地方find。

此外,截图中QR码的大小是原始QR码的两倍,但我想这是由于我的Mac屏幕有144dpi。

我正在使用node.js,所以我需要任何可以通过命令行(如imagemagick )执行的东西,以便我可以从节点或直接节点模块执行它。

我有一个优势,就是我可以select想要在更大的图像中search的图像。 我猜测要find的确切知识可能是一个有用的信息来加速过程(但我不知道如何使用这些信息)。

如果您发现子图像search太慢,我有几个build议可以考虑加快search速度。

1.减小图像大小

我进行了一个小实验来testing在各种大小的干草堆中search不同大小的针,如下所示:

 #!/bin/bash # Create a range of haystack sizes for h in 200 400 800; do # And a range of needle sizes for n in 10 20 40; do # Create haystack to search in, containing two needles convert -size ${h}x${h}! gradient:red-black -fill white \ -draw "rectangle 100,100 139,139" \ -draw "rectangle 150,150 189,189" \ haystack.png # Create a needle this size to search for convert -size ${n}x${n}! xc:white needle.png cp haystack.png haystack_${h}x${h}.png cp needle.png needle${n}x${n}.png # Search, measuring the time start=$SECONDS compare -dissimilarity-threshold 1.0 -metric rmse -subimage-search haystack.png needle.png null: > /dev/null 2>&1 end=$SECONDS ((elapsed=end-start)) echo Haystack:${h}x${h}, needle:${n}x${n}, time:$elapsed done done 

并发现大小如何影响search时间,如下所示:

 Haystack:200x200, needle:10x10, time:2 Haystack:200x200, needle:20x20, time:2 Haystack:200x200, needle:40x40, time:2 Haystack:400x400, needle:10x10, time:8 Haystack:400x400, needle:20x20, time:8 Haystack:400x400, needle:40x40, time:10 Haystack:800x800, needle:10x10, time:33 Haystack:800x800, needle:20x20, time:36 Haystack:800x800, needle:40x40, time:47 

正如你所看到的,图像的大小有很大的不同。

这里有三个不同大小的干草堆,每个包含2个白色“ ”:

在这里输入图像说明

这里是ImageMagick认为“ ”所在的“ 结果 ”图像:

在这里输入图像说明

尽可能地停下来

如果添加参数-similarity-threshold并将其设置为合理的值,则可以在find第一个匹配项时立即停止search,如grep -m 1

像这样设置会使它在第一次完美匹配时停止(相似度为零):

 -similarity-threshold 0.0 

或者像这样设置会使它停止在第一个“非常好的匹配”

 -similarity-threshold 0.05 

并且默认设置是1.0从不匹配,从而导致search在整个图像上继续。

现在我知道你想find视口的顶部和底部,这是两场比赛,看起来很快find第一场比赛是没有用的。 但孔子说, “旋转你的形象” 🙂

所以,find你的第一个(即顶部)匹配,然后旋转你的图像(和针)180度,再次search,但这次你从底部search,可以再次停止在第一场比赛。 (旋转你的结果。)

3.使用你付出的所有可爱的核心 – 并行化!

您可以将图像拆分为多个部分,并行search以充分利用您为之付出的所有可爱的英特尔内核。 你需要小心重叠一点,以便你的针没有跨越你所切割的边界,但是你所需要的就是在针的宽度上添加一条条纹到search区域……就像这样

 #!/bin/bash # Create a range of haystack sizes for h in 200 400 800; do # And a range of needle sizes for n in 10 20 40; do # Create haystack to search in, containing two needles convert -size ${h}x${h}! gradient:red-black -fill white \ -draw "rectangle 100,100 139,139" \ -draw "rectangle 150,150 189,189" \ haystack.png # Create a needle this size to search for convert -size ${n}x${n}! xc:white needle.png cp haystack.png haystack_${h}x${h}.png cp needle.png needle${n}x${n}.png # Search, measuring the time start=$SECONDS compare -dissimilarity-threshold 1.0 -metric rmse -subimage-search haystack.png needle.png null: > /dev/null 2>&1 end=$SECONDS ((elapsed=end-start)) echo Haystack:${h}x${h}, needle:${n}x${n}, time:$elapsed ((a=h/2)) ((b=h/2)) ((c=a+n)) ((d=b+n)) ((e=an)) ((f=bn)) # Measure time for parallel search, including dividing up image start=$SECONDS convert haystack.png -crop ${c}x${d}+0+0 +repage h1.png convert haystack.png -crop ${a}x${b}+${a}+0 +repage h2.png convert haystack.png -crop ${a}x${b}+0+${b} +repage h3.png convert haystack.png -crop ${c}x${d}+${e}+${f} +repage h4.png for p in 1 2 3 4; do compare -dissimilarity-threshold 1.0 -metric rmse -subimage-search h${p}.png needle.png null: > /dev/null 2>&1 & done wait end=$SECONDS ((elapsed=end-start)) echo Parallel Haystack:${h}x${h}, needle:${n}x${n}, time:$elapsed done done 

你可以看到并行时间几乎比单线程时间快4倍:

 Haystack:200x200, needle:10x10, time:2 Parallel Haystack:200x200, needle:10x10, time:0 Haystack:200x200, needle:20x20, time:2 Parallel Haystack:200x200, needle:20x20, time:1 Haystack:200x200, needle:40x40, time:2 Parallel Haystack:200x200, needle:40x40, time:1 Haystack:400x400, needle:10x10, time:8 Parallel Haystack:400x400, needle:10x10, time:2 Haystack:400x400, needle:20x20, time:8 Parallel Haystack:400x400, needle:20x20, time:3 Haystack:400x400, needle:40x40, time:10 Parallel Haystack:400x400, needle:40x40, time:4 Haystack:800x800, needle:10x10, time:33 Parallel Haystack:800x800, needle:10x10, time:10 Haystack:800x800, needle:20x20, time:36 Parallel Haystack:800x800, needle:20x20, time:11 Haystack:800x800, needle:40x40, time:47 Parallel Haystack:800x800, needle:40x40, time:14