乐趣区

关于图像处理:图像匹配大图中找小图之findtemplate源码解析

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,匹配成果更佳。
    — 退出信息:有时候除了模板图像自身,咱们兴许晓得更多的信息,比方图像可能呈现的地位范畴,图像周边区域的款式等等,来帮忙晋升辨认准确度,缩小误识和漏识。
退出移动版