在Numpy图像中查找子图像

Eti*_*rot 18 python numpy image python-imaging-library

我有两个从PIL图像转换的Numpy数组(3维uint8).

我想查找第一个图像是否包含第二个图像,如果是,请找出匹配所在的第一个图像内左上角像素的坐标.

有没有办法在Numpy中以足够快的方式完成这个,而不是使用(4!非常慢)纯Python循环?

2D示例:

a = numpy.array([
    [0, 1,  2,  3],
    [4, 5,  6,  7],
    [8, 9, 10, 11]
])
b = numpy.array([
    [2, 3],
    [6, 7]
])
Run Code Online (Sandbox Code Playgroud)

怎么做这样的事情?

position = a.find(b)
Run Code Online (Sandbox Code Playgroud)

position那会是(0, 2).

PiQ*_*uer 32

我正在使用OpenCVmatchTemplate 功能.有一个很好的python绑定到OpenCV内部使用numpy,所以图像只是numpy数组.例如,假设您有一个100x100像素的BGR文件testimage.bmp.我们在位置(30,30)处拍摄10x10子图像并在原始图像中找到它.

import cv2
import numpy as np

image = cv2.imread("testimage.bmp")
template = image[30:40,30:40,:]

result = cv2.matchTemplate(image,template,cv2.TM_CCOEFF_NORMED)
print np.unravel_index(result.argmax(),result.shape)
Run Code Online (Sandbox Code Playgroud)

输出:

(30, 30)
Run Code Online (Sandbox Code Playgroud)

您可以选择几种算法来将模板与原始模板匹配,cv2.TM_CCOEFF_NORMED只是其中之一.有关详细信息,请参阅文档,有些算法表示匹配为最小值,其他算法表示结果数组中的最大值.警告:OpenCV默认使用BGR通道顺序,所以要小心,例如,当您将加载cv2.imread的图像与从PIL转换为numpy的图像进行比较时.您始终可以使用cv2.cvtColor格式之间的转换.

要查找超过给定阈值的所有匹配项confidence,我会使用沿着此行的某些内容从我的结果数组中提取匹配的坐标:

match_indices = np.arange(result.size)[(result>confidence).flatten()]
np.unravel_index(match_indices,result.shape)
Run Code Online (Sandbox Code Playgroud)

这给出了长度为2的数组元组,每个数组都是匹配的坐标.


tom*_*m10 9

这可以使用scipy的correlate2d完成,然后使用argmax在互相关中找到峰值.

这里有一个关于数学和思想的更完整的解释,以及一些例子.

如果你想保持纯粹的Numpy甚至不使用scipy,或者如果图像很大,你可能最好使用基于FFT的方法来进行交叉相关.

编辑:问题特别要求一个纯粹的Numpy解决方案.但是如果你可以使用OpenCV或其他图像处理工具,使用其中一种显然更容易.下面的PiQuer给出了一个这样的例子,如果你可以使用它,我建议你这样做.