获取一张图片在另一张图片中的位置

Get position of one image in another image

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

我可以在开始图像处理之前向网站的 DOM 添加任何内容。

我已经尝试生成二维码,将其添加到视口的左上角和右下角,然后使用 imagemagick 来确定二维码的位置-大图代码:

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

但是,这需要很长时间。事实上,我在 40 分钟后就退出了。

我使用了二维码,因为通过使用时间戳,我可以非常确定这张图片不会在网站的其他任何地方找到。

此外,屏幕截图中二维码的大小是原始二维码的两倍,但我猜这是因为我的 mac 屏幕有 144dpi。

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

我的优势是可以在大图中选择要搜索的图片。我想确切了解要找到的内容可能是加快流程的有用信息(但我还不知道如何使用这些信息)。

如果您发现子图像搜索速度太慢,我有一些建议可以帮助您加快搜索速度。

1。缩小图片大小

我做了一个小实验来测试在不同大小的大海捞针中寻找不同大小的针头,像这样:

#!/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

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

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 认为“”所在的“结果”图像:

2。尽快停止

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

这样设置会在第一个完美匹配处停止(相似度差为零):

-similarity-threshold 0.0

或者像这样设置会让它停在第一个"pretty good match"

-similarity-threshold 0.05

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

现在我知道你想找到视口的顶部和底部,这是 两个 匹配,看起来快速找到第一场比赛是没有用的。但是孔子,他说"rotate your image" :-)

因此,找到您的第一个(即顶部)匹配项,然后将您的图像(和针)旋转 180 度并再次搜索,但这次您是从底部搜索并且可以再次在第一个匹配项处停止。 (也旋转你的结果。)

3。使用您付费购买的所有可爱内核 - 并行化!

您可以将图像拆分成多个部分并并行搜索,以利用您付出如此多代价购买的所有可爱的 Intel 内核。你需要小心一点重叠一点,这样你的针就不会跨越你切割的边界,但你所需要的只是在一条条子上添加你的针的宽度到搜索区域......就像这样

#!/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=a-n))
      ((f=b-n))
      # 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