OpenCV中一种尺度不变的模板匹配方案
Posted 大林的网络训练营
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV中一种尺度不变的模板匹配方案相关的知识,希望对你有一定的参考价值。
( 注:这一篇的内容其实不属于深度学习,不过搞图像难免要用到一些经典方法,所以也记录一下~ )
工作上需要做一些静态物体的目标检测,深度学习的网络模型还没训练完,因此计划用OpenCV也实现一版,作为备份方案。首先选用的当然是模板匹配,也就是matchTemplate()函数。这个函数的用法很简单,几行代码就搞定,如下图。
但模板匹配函数的使用局限也很大,最主要的一点是摄像机镜头一变焦,物体大小变了,就匹配不上了。
查了半天,网上一般号称能够尺度不变的解决方案,都是把模板缩放多个不同的比例,循环匹配,直到找到一个匹配值较高的为止。不过据我试验,模板跟目标的大小差个20%多,匹配值就下降得非常严重,这要是镜头可变焦距大点,得缩放匹配多少次才能检测得准呢。所以希望能找到一种真正适应各种尺度的方案。
经过研究,找到这么一个类:SurfFeatureDetector,结合BFMatcher,可以找出2幅图片中的特征点,并进行最优匹配。
如上图中左边是模板,右边是待检测的目标图像,模板放大到了目标的2倍。要是直接做模板匹配,那是完全匹配不上的。但是Surf特征点检测就能匹配出两幅图中相应的特征点来。
Surf特征点检测的使用示例如下:
( 需要注意的一点是Surf检测器的代码被移出了OpenCV-3.4.x,你需要自己去下载opencv_contrib包,添加相应的头文件和库文件路径。上述代码所需的头文件路径为:#include <opencv2/xfeatures2d/nonfree.hpp>
匹配上2张图的特征点,后面就简单了。分别计算出2张图中相距最远特征点的间距,比较一下,以此来resize输入模板的大小,搞定!下面是匹配的结果:
写完代码当然要多测试几轮,于是,程序崩了…… 咋回事呢?一调试发现:
原来是没匹配准,有少部分特征点匹配飞了,导致模板的大小被校得比目标图像还大……
这个问题要怎么解决呢?仔细观察目标图像中所有连线的特征点,大部分还是集中在待检测的目标上,其余错误的特征点则较为分散。一开始考虑用聚类算法来处理,但发现Kmeans算法必须将所有点归入已知数量的类别中,而这里仅需要找出相对集中的部分点作为一类即可,并不太适用。
最终采用了这么一个算法。首先把目标图像在x,y方向分别10等分,根据Surf算法挑出的匹配特征点的坐标得到2个直方图,选出其中点最多的区域。再计算区域内特征点的中心点,以及全图所有特征点到该中心点的距离和标准差。设定系数c,判决所有满足与中心点距离
的特征点为正确特征点,再执行前述大小校正算法。
最终这一方案可以实现尺度不变的模板匹配。不过系数c的选取需要根据实际情况进行调试,若c取值过大,可能达不到筛除错误匹配点的目标,使得模板大小的校准不正确;若c取值过小,则可能会仅剩1个特征点,导致无法计算模板校准的比例(剩余特征点过少间距过近也会导致大小校准不精确)。我的代码中c取值选择0.8。
方案的另一个缺点是速度慢,相当的慢。所以实际使用中大部分情况下还是考虑直接匹配,只有在摄像机变焦,无法匹配时调用该方案一次,校准大小后就不再用了。
模板匹配记录完毕。
以上是关于OpenCV中一种尺度不变的模板匹配方案的主要内容,如果未能解决你的问题,请参考以下文章