使用自定义内核/图像过滤器在二维数组中查找特定模式
Use a custom kernel / image filter to find a specific pattern in a 2d array
给定一张图片 im
,
>>> np.random.seed(0)
>>> im = np.random.randint(0, 100, (10,5))
>>> im
array([[44, 47, 64, 67, 67],
[ 9, 83, 21, 36, 87],
[70, 88, 88, 12, 58],
[65, 39, 87, 46, 88],
[81, 37, 25, 77, 72],
[ 9, 20, 80, 69, 79],
[47, 64, 82, 99, 88],
[49, 29, 19, 19, 14],
[39, 32, 65, 9, 57],
[32, 31, 74, 23, 35]])
找到此图像的特定片段的最佳方法是什么,例如
>>> im[6:9, 2:5]
array([[82, 99, 88],
[19, 19, 14],
[65, 9, 57]])
如果特定组合不存在(可能是由于噪声),我想有一个相似性度量,它搜索具有相似分布的片段并告诉我 im
的每个像素,如何好的协议是。例如像
array([[0.03726647, 0.14738364, 0.04331007, 0.02704363, 0.0648282 ],
[0.02993497, 0.04446428, 0.0772978 , 0.1805197 , 0.08999 ],
[0.12261269, 0.18046972, 0.01985607, 0.19396181, 0.13062801],
[0.03418192, 0.07163043, 0.15013723, 0.12156613, 0.06500945],
[0.00768509, 0.12685481, 0.19178985, 0.13055806, 0.12701177],
[0.19905991, 0.11637007, 0.08287372, 0.0949395 , 0.12470202],
[0.06760152, 0.13495046, 0.06344035, 0.1556691 , 0.18991421],
[0.13250537, 0.00271433, 0.12456922, 0.97 , 0.194389 ],
[0.17563869, 0.10192488, 0.01114294, 0.09023184, 0.00399753],
[0.08834218, 0.19591735, 0.07188889, 0.09617871, 0.13773224]])
示例代码是python。
我认为应该有一个将内核与 im
相关联的解决方案。但是,这会有一个问题,即具有相同值但缩放的段将给出更清晰的响应。
模板匹配将是实现它的方法之一。当然deeplearning/ML也可以用于更复杂的匹配
大多数图像处理库都支持某种匹配函数,该函数比较一组 2 张图像 - 参考图像和要匹配的图像。在 OpenCV 中,它 returns 一个可以用来确定匹配的分数。匹配方法使用各种支持scale and/or rotation invariant匹配的函数。当心您计划使用的方法中的许可限制。
如果图像可能并不总是准确的,您可以使用标准差 (StdDev) 来允许允许的偏差并将它们分类到桶中。根据要匹配的图像条件,也可以使用直方图匹配(照明、颜色可能很重要,除非您使用特定通道)。使用直方图将避免完全匹配模板。
模板匹配参考:
感谢 banerjk 的出色回答 - template matching 正是解决方案!
一些备份方法
考虑到我的correlating-with-a-kernel想法,有一些进展:
当将图像与模板相关联时(即我在问题中所说的目标片段),相关图像中最强烈的点(相对于平均强度)与模板位置匹配的可能性很高(参见 im
和示例中的 m
)。好像我不是第一个提出这个想法的人,从第 39 页的 lecture notes 中可以看出。
然而,这并不总是正确的。这种方法或多或少只是检测模板中最大值处的权重。在这个例子中,im2
被构造成这样,它欺骗了这个概念。
如果事先在图像上应用一些过滤器(例如中值),也许它会变得更可靠。
我只是想在这里提一下,因为它在某些情况下可能有优势(与 template_matching 的 Wikipedia-implementation 相比,它应该具有更高的性能)。
例子
import numpy as np
from scipy import ndimage
np.random.seed(0)
im = np.random.randint(0, 100, (10,5))
t = im[6:9, 2:5]
print('t', t, sep='\n')
m = ndimage.correlate(im, t) / ndimage.correlate(im, np.ones(t.shape))
m /= np.amax(m)
print('im', im, sep='\n')
print('m', m, sep='\n')
print("this can be 'tricked', however")
im2 = im.copy()
im2[6:9, :3] = 0
im2[6,1] = 1
m2 = ndimage.correlate(im2, t) / ndimage.correlate(im2, np.ones(t.shape))
m2 /= np.amax(m2)
print('im2', im2, sep='\n')
print('m2', m2, sep='\n')
输出
t
[[82 99 88]
[19 19 14]
[65 9 57]]
im
[[44 47 64 67 67]
[ 9 83 21 36 87]
[70 88 88 12 58]
[65 39 87 46 88]
[81 37 25 77 72]
[ 9 20 80 69 79]
[47 64 82 99 88]
[49 29 19 19 14]
[39 32 65 9 57]
[32 31 74 23 35]]
m
[[0.73776208 0.62161208 0.74504705 0.71202601 0.66743979]
[0.70809611 0.70617161 0.70284942 0.80653741 0.67067733]
[0.55047727 0.61675268 0.5937487 0.70579195 0.74351706]
[0.7303857 0.77147963 0.74809273 0.59136392 0.61324214]
[0.70041161 0.7717032 0.69220064 0.72463532 0.6957257 ]
[0.89696894 0.69741108 0.64136612 0.64154719 0.68621613]
[0.48509474 0.60700037 0.65812918 0.68441118 0.68835903]
[0.73802038 0.83224745 0.87301124 1. 0.92272565]
[0.72708573 0.64909142 0.54540817 0.60859883 0.52663327]
[0.72061572 0.70357846 0.61626289 0.71932261 0.75028955]]
this can be 'tricked', however
im2
[[44 47 64 67 67]
[ 9 83 21 36 87]
[70 88 88 12 58]
[65 39 87 46 88]
[81 37 25 77 72]
[ 9 20 80 69 79]
[ 0 1 0 99 88]
[ 0 0 0 19 14]
[ 0 0 0 9 57]
[32 31 74 23 35]]
m2
[[0.53981867 0.45483201 0.54514907 0.52098765 0.48836403]
[0.51811216 0.51670401 0.51427317 0.59014141 0.49073293]
[0.40278285 0.4512764 0.43444444 0.51642621 0.54402958]
[0.5344214 0.56448972 0.54737758 0.43269951 0.44870774]
[0.51248943 0.56465331 0.50648148 0.53021386 0.50906076]
[0.78923691 0.56633529 0.51641414 0.44336403 0.50210263]
[0.88137788 0.89779614 0.63552189 0.55070797 0.50367059]
[0.88888889 1. 0.75544508 0.75694003 0.67515605]
[0.43965976 0.48492221 0.37490287 0.48511085 0.38533625]
[0.30754918 0.32478065 0.27066895 0.46685032 0.548985 ]]
也许有人可以对讲义的背景做出贡献。
更新: 在第一页J. P. Lewis, “Fast Normalized Cross-Correlation”, Industrial Light and Magic.中讨论。
给定一张图片 im
,
>>> np.random.seed(0)
>>> im = np.random.randint(0, 100, (10,5))
>>> im
array([[44, 47, 64, 67, 67],
[ 9, 83, 21, 36, 87],
[70, 88, 88, 12, 58],
[65, 39, 87, 46, 88],
[81, 37, 25, 77, 72],
[ 9, 20, 80, 69, 79],
[47, 64, 82, 99, 88],
[49, 29, 19, 19, 14],
[39, 32, 65, 9, 57],
[32, 31, 74, 23, 35]])
找到此图像的特定片段的最佳方法是什么,例如
>>> im[6:9, 2:5]
array([[82, 99, 88],
[19, 19, 14],
[65, 9, 57]])
如果特定组合不存在(可能是由于噪声),我想有一个相似性度量,它搜索具有相似分布的片段并告诉我 im
的每个像素,如何好的协议是。例如像
array([[0.03726647, 0.14738364, 0.04331007, 0.02704363, 0.0648282 ],
[0.02993497, 0.04446428, 0.0772978 , 0.1805197 , 0.08999 ],
[0.12261269, 0.18046972, 0.01985607, 0.19396181, 0.13062801],
[0.03418192, 0.07163043, 0.15013723, 0.12156613, 0.06500945],
[0.00768509, 0.12685481, 0.19178985, 0.13055806, 0.12701177],
[0.19905991, 0.11637007, 0.08287372, 0.0949395 , 0.12470202],
[0.06760152, 0.13495046, 0.06344035, 0.1556691 , 0.18991421],
[0.13250537, 0.00271433, 0.12456922, 0.97 , 0.194389 ],
[0.17563869, 0.10192488, 0.01114294, 0.09023184, 0.00399753],
[0.08834218, 0.19591735, 0.07188889, 0.09617871, 0.13773224]])
示例代码是python。
我认为应该有一个将内核与 im
相关联的解决方案。但是,这会有一个问题,即具有相同值但缩放的段将给出更清晰的响应。
模板匹配将是实现它的方法之一。当然deeplearning/ML也可以用于更复杂的匹配
大多数图像处理库都支持某种匹配函数,该函数比较一组 2 张图像 - 参考图像和要匹配的图像。在 OpenCV 中,它 returns 一个可以用来确定匹配的分数。匹配方法使用各种支持scale and/or rotation invariant匹配的函数。当心您计划使用的方法中的许可限制。
如果图像可能并不总是准确的,您可以使用标准差 (StdDev) 来允许允许的偏差并将它们分类到桶中。根据要匹配的图像条件,也可以使用直方图匹配(照明、颜色可能很重要,除非您使用特定通道)。使用直方图将避免完全匹配模板。
模板匹配参考:
感谢 banerjk 的出色回答 - template matching 正是解决方案!
一些备份方法
考虑到我的correlating-with-a-kernel想法,有一些进展:
当将图像与模板相关联时(即我在问题中所说的目标片段),相关图像中最强烈的点(相对于平均强度)与模板位置匹配的可能性很高(参见 im
和示例中的 m
)。好像我不是第一个提出这个想法的人,从第 39 页的 lecture notes 中可以看出。
然而,这并不总是正确的。这种方法或多或少只是检测模板中最大值处的权重。在这个例子中,im2
被构造成这样,它欺骗了这个概念。
如果事先在图像上应用一些过滤器(例如中值),也许它会变得更可靠。
我只是想在这里提一下,因为它在某些情况下可能有优势(与 template_matching 的 Wikipedia-implementation 相比,它应该具有更高的性能)。
例子
import numpy as np
from scipy import ndimage
np.random.seed(0)
im = np.random.randint(0, 100, (10,5))
t = im[6:9, 2:5]
print('t', t, sep='\n')
m = ndimage.correlate(im, t) / ndimage.correlate(im, np.ones(t.shape))
m /= np.amax(m)
print('im', im, sep='\n')
print('m', m, sep='\n')
print("this can be 'tricked', however")
im2 = im.copy()
im2[6:9, :3] = 0
im2[6,1] = 1
m2 = ndimage.correlate(im2, t) / ndimage.correlate(im2, np.ones(t.shape))
m2 /= np.amax(m2)
print('im2', im2, sep='\n')
print('m2', m2, sep='\n')
输出
t
[[82 99 88]
[19 19 14]
[65 9 57]]
im
[[44 47 64 67 67]
[ 9 83 21 36 87]
[70 88 88 12 58]
[65 39 87 46 88]
[81 37 25 77 72]
[ 9 20 80 69 79]
[47 64 82 99 88]
[49 29 19 19 14]
[39 32 65 9 57]
[32 31 74 23 35]]
m
[[0.73776208 0.62161208 0.74504705 0.71202601 0.66743979]
[0.70809611 0.70617161 0.70284942 0.80653741 0.67067733]
[0.55047727 0.61675268 0.5937487 0.70579195 0.74351706]
[0.7303857 0.77147963 0.74809273 0.59136392 0.61324214]
[0.70041161 0.7717032 0.69220064 0.72463532 0.6957257 ]
[0.89696894 0.69741108 0.64136612 0.64154719 0.68621613]
[0.48509474 0.60700037 0.65812918 0.68441118 0.68835903]
[0.73802038 0.83224745 0.87301124 1. 0.92272565]
[0.72708573 0.64909142 0.54540817 0.60859883 0.52663327]
[0.72061572 0.70357846 0.61626289 0.71932261 0.75028955]]
this can be 'tricked', however
im2
[[44 47 64 67 67]
[ 9 83 21 36 87]
[70 88 88 12 58]
[65 39 87 46 88]
[81 37 25 77 72]
[ 9 20 80 69 79]
[ 0 1 0 99 88]
[ 0 0 0 19 14]
[ 0 0 0 9 57]
[32 31 74 23 35]]
m2
[[0.53981867 0.45483201 0.54514907 0.52098765 0.48836403]
[0.51811216 0.51670401 0.51427317 0.59014141 0.49073293]
[0.40278285 0.4512764 0.43444444 0.51642621 0.54402958]
[0.5344214 0.56448972 0.54737758 0.43269951 0.44870774]
[0.51248943 0.56465331 0.50648148 0.53021386 0.50906076]
[0.78923691 0.56633529 0.51641414 0.44336403 0.50210263]
[0.88137788 0.89779614 0.63552189 0.55070797 0.50367059]
[0.88888889 1. 0.75544508 0.75694003 0.67515605]
[0.43965976 0.48492221 0.37490287 0.48511085 0.38533625]
[0.30754918 0.32478065 0.27066895 0.46685032 0.548985 ]]
也许有人可以对讲义的背景做出贡献。
更新: 在第一页J. P. Lewis, “Fast Normalized Cross-Correlation”, Industrial Light and Magic.中讨论。