共计 2175 个字符,预计需要花费 6 分钟才能阅读完成。
aircv 是网易放出的小开源我的项目,应该也是当初做简略图像匹配被援用最多的我的项目了。上一篇做了如何应用 aircv 之 find_template 的形容,然而,它并不算是一个成熟的我的项目,外面的小坑不少,有待改良。明天先做个代码逻辑的解析。
外围函数 find_template 与 find_all_template
find_template 函数是返回第一个最匹配的后果(地位未必在最下面),而 find_all_template 是返回所有大于指定置信度的后果。
比方要在思否页面截图中找
后果如如下图所示:
咱们深刻进去看一下代码,就会发现 find_template 是这样写的:
def find_template(im_source, im_search, threshold=0.5, rgb=False, bgremove=False):
'''
@return find location
if not found; return None
'''
result = find_all_template(im_source, im_search, threshold, 1, rgb, bgremove)
return result[0] if result else None
好家伙! 间接调用 find_all_template,而后取返回值的第一个。。。
所以 find_all_template 才是真正的外围,咱们排除掉无关代码,来看一下最要害的局部:
def find_all_template(im_source, im_search, threshold=0.5, maxcnt=0, rgb=False, bgremove=False):
# 匹配算法,aircv 实际上在代码里写死了用 CCOEFF_NORMED,大部分测试的成果,也的确是这个算法更好
method = cv2.TM_CCOEFF_NORMED
# 获取匹配矩阵
res = cv2.matchTemplate(im_source, im_search, method)
w, h = im_search.shape[1], im_search.shape[0]
result = []
while True:
# 找到匹配最大最小值
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
top_left = max_loc
if max_val < threshold:
break
# 计算中心点
middle_point = (top_left[0]+w/2, top_left[1]+h/2)
# 计算四个角的点,存入后果集
result.append(dict(
result=middle_point,
rectangle=(top_left, (top_left[0], top_left[1] + h), (top_left[0] + w, top_left[1]), (top_left[0] + w, top_left[1] + h)),
confidence=max_val
))
# 把最匹配区域填充掉,再持续查找下一个
cv2.floodFill(res, None, max_loc, (-1000,), max_val-threshold+0.1, 1, flags=cv2.FLOODFILL_FIXED_RANGE)
return result
其中 cv2.matchTemplate
是 opencv 的办法,它的返回值是个矩阵,相当于用小图在大图上滑动,从左上角开始,每次挪动一个像素,而后计算一个匹配后果,最终造成后果矩阵。
后果矩阵大小应该是: (W – w + 1) x (H – h + 1),其中 W,H 是大图的宽高, w 和 h 是小图的宽高。
这个矩阵中最大值的那个点,就示意小图的左上角对在这个地位时,匹配度最高,由此失去第一个匹配后果。
最初 cv2.floodFill
的作用,是把后果矩阵最大值这块区域用别的数字填充掉,这样就能够查找下一个最大值了,而且也防止了区域重叠的景象(要不然下一个最大值,有可能在刚刚找到的区域外面)。
几个小问题
- 不反对灰度图和带通明通道的图
其实 opencv 的 matchTemplate 原本只反对灰度图,但大多数状况下,咱们都是查找黑白图,所以 aircv 封装的时候,把 bgr 三个黑白通道做了拆散,别离调用 matchTemplate,而后再合并后果。
但这个封装没有兼容原本就是灰度图的状况,居然会出错,而且如果源图带通明通道也会出错,为此,我专门提交了一个 PR,但始终没有解决,看来我的项目曾经没人保护了。
- floodFill 貌似有点调兵遣将了,numpy 的切片应该能够实现
这个回头写段小代码验证一下 - 不能解决图片的缩放
模板图片和原图中的内容,并不一定大小严格统一的,那么就须要做一些缩放解决,反复尝试。 - 图像匹配成果不现实
如果是完全一致的图,find_template 的成果十分好,但当须要含糊匹配时,某些人眼一看就雷同的图像,是无奈被辨认进去的,有点时候又会误辨认,这可能须要从两方面改良:
— 调整算法:采纳 SIFT 之类的特色点检测算法,能够解决大小和角度都不统一的图像匹配问题;Halcon 等商业软件,采纳了 shape based matching,匹配成果更佳。
— 退出信息:有时候除了模板图像自身,咱们兴许晓得更多的信息,比方图像可能呈现的地位范畴,图像周边区域的款式等等,来帮忙晋升辨认准确度,缩小误识和漏识。