首页 > 解决方案 > 如何使用 Python 找到图片中的几个关键像素点?

问题描述

我知道通过 Opencv-python 的 matchtemplate 函数可以从图 1 中匹配图 2。

import cv2


template = cv2.imread("1.bmp")
template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
template = cv2.Canny(template, 50, 200)


edged = cv2.imread("2.bmp")
edged = cv2.cvtColor(edged, cv2.COLOR_BGR2GRAY)
edged = cv2.Canny(edged, 50, 200)


result = cv2.matchTemplate(edged, template, cv2.TM_CCOEFF_NORMED)
(_, maxVal, _, maxLoc) = cv2.minMaxLoc(result)

但是如果我只有图3这样的像素,我如何匹配图1?

图3:图2中的部分像素被提取出来,其余部分用红色填充。

我没有找到 opencv-python 或 PIL 解决方案。我认为可以通过遍历像素来解决,但这并不能保证性能。那么有没有更好的方法呢?

标签: pythonimageopencv

解决方案


根据 Neeraj Komuravalli 对这个问题的回答,matchTemplate支持该mask论点作为在匹配中排除模板中某些像素的一种方式(文档)。

要根据红色像素生成遮罩,一个简单的解决方案是使用布尔表达式来选择那些0蓝色和绿色但255红色的像素:

mask = (template[:,:,0]==0) & (template[:,:,1]==0) & (template[:,:,2]==255)
mask = ~mask
mask = mask.astype(np.uint8)

请注意,转换为uint8是必要的,因为掩码必须与模板具有相同的数据类型。

编辑: ~mask反转掩码(0变为1,反之亦然),这是必要的,因为0指示要掩码的像素,至少在使用方法时cv2.TM_CCORR_NORMED


虽然这原则上解决了您的问题,但在这种情况下不会产生有效的解决方案。

这是因为对图像应用了 Canny 边缘过滤器。由于在应用 Canny 时无法屏蔽模板中的红色像素,因此红色像素区域的边界会影响边缘检测的结果,从而使模板看起来与原来的完全不同。

在这个例子中,匹配失败,返回一个完全错误的位置。

删除 Canny 步骤解决了这个问题......但它也使该方法不太健壮/精确。在这种情况下,匹配实际上似乎与 100% 正确的匹配相差几个像素。不幸的是,我想不出任何改进的方法。


这是对我有用的完整代码(在精度方面有上述警告):

import cv2
import numpy as np

template = cv2.imread("masked_template.png")

mask = (template[:,:,0]==0) & (template[:,:,1]==0) & (template[:,:,2]==255)
mask = mask.astype(np.uint8)

template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
#template = cv2.Canny(template, 50, 200)

edged = cv2.imread("edged.png")
edged = cv2.cvtColor(edged, cv2.COLOR_BGR2GRAY)
#edged = cv2.Canny(edged, 50, 200)

result = cv2.matchTemplate(edged, template, cv2.TM_CCORR_NORMED, mask=mask)
(_, maxVal, _, maxLoc) = cv2.minMaxLoc(result)

推荐阅读