zoukankan      html  css  js  c++  java
  • 【工程应用二】 多目标多角度的快速模板匹配算法(基于边缘梯度)

           基于NCC的多目标多角度快速模板匹配算法详见:https://www.cnblogs.com/Imageshop/p/14559685.html

           乘着研究NCC的热情,顺便也研究了下基于边缘梯度的匹配。

           基于边缘梯度方面的匹配,最为出名的莫过于CodeProject上一篇多年前的印度小哥的文章,链接为:Edge Based Template Matching

           这篇文章的核心计算公式为:

                               (1)

     

           在国内的中文有关网站上却常常看到下述公式(分母第二项不同),这明显是个错误的式子,也不知道哪位是原始创造者。

                  

            这个核心计算式和基于NCC的看上去相似又有着很多不同。注意式子中的大写字母G表示图像的梯度信息,这个是可正亦可负的。即计算式已经脱离原有的像素信息,而使用了梯度相关信息,常用的获取X和Y方向梯度的方式有:

                

        即Sobel边缘检测算子。

             在印度小哥的文章里,采用了Canny检测来检测出边缘,然后只对模板图和搜索图中对应的边缘位置计算上述得分公式(以模板图中的边缘处为依据), 这样起到减少取样点,提高速度的作用。

             我实际测试这种方法如果直接对模板和搜索图做,很多情况下是可以的,但是还是存在着一些问题,主要有:

             1、虽然Canny的使用减少了很多计算量,但是他完全剔除了其他弱边缘处的信息,就好像把考试中那些不及格的学生都定型为差生一样,是不科学的。这些弱边缘在一定程度上也有着相当的信息量。

             2、Canny本身是有着很多参数来控制最终的效果的,不是一个固定的参数对每一副图像都能获取稳定的效果,因此,这就很难成为一个稳定的算法了。

             3、如果采用了金字塔等技术,在金字塔层数增加时,Canny所对应的边缘会越来越不稳定,这会影响最终的精度。

             所以,我觉得不应该使用Canny获其他的类似技术实现这个过程,我的想法还是对全图实现上述公式的计算。

             但是,这又会遇到几个问题。

             1、计算量飙升,这个可以通过金字塔的技术来解决。

             2、我们仔细的观察公式(1),如果做一个全局的匹配计算,在计算过程中,必然会遇到不少地方的X和Y方向的梯度都为0或者很小,而且这种像素占的比例还相当高,毕竟图像中真正属于边缘的地方很少。那么这样的一个事实就回到导致很多累加项的值为0或很小(X和Y梯度都为0时,式子的分母为0,程序需要做判断,但输出的结果必然也会是0),这样整体累加后再求平均数我们将获得一个很小的得分(哪怕和模板图一模一样的地方)。

            一种改进的方法就是把模板图的整体的幅值信息作为一个因子放入到上述计算公式的分母中,这样,模板图中梯度较小的位置,对整体的幅值贡献就小,从而不会对最后的得分造成影响。

            在实际的编码中,我们还会遇到很多的其他方面的困难,列举一些如下:

           1、对于角度的检测,类似的,我们也创建多个离散的模板,我们需要旋转模板,然后计算模板的边缘梯度,但是,旋转本身产生了新的边缘,而且是强边缘,如下所示:

              

         如果把这边缘带入式中计算,非常明显不会得到可靠的结果,我们需要把这个边缘剔除。

         2、无论采用何种边缘梯度检测算子,最小的都会涉及到3*3的局部范围,那么对于未旋转或者旋转后的模板图,都存在一个明显问题,最外一圈像素的梯度如何处理,如果使用重复边缘像素的方式,那么就会获得一个较小的梯度,但是实际在在搜索图中是不存在这个问题的,只要模板不在搜索图的边缘处。因此,如果这样处理,哪怕模板就是从搜索图中直接扣取出来的,依据(1)式计算出的结果也不会等于1,而是小于1。

      如何解决这个问题,我目前想到的也只有忽略最外圈的梯度值,即他们不参与相似性计算。这样就要求在做模板图时,需要可以在实际需要的模板的基础上,中心对称的长和宽每边各增加一个像素。但是,这样实际上还是没有完美解决问题,因为当有金字塔存在时,这可以增加的1个像素经过下采样后已经没有一个像素了,还是有点头大,暂时没有想到什么好办法。、

    IM_Rotate(Template, Rotate, RTI.Mask, Angle, 1, Amount);            //    旋转图像,获取Mask值
    IM_Edge_Erode_3X3(RTI.Mask, RTI.Mask);

      想到的另外一个方法就是旋转时不是旋转图像然后再计算梯度,而是直接旋转X和Y方向的梯度,但是新的难处是梯度值是有正有负的,这种数据的旋转在使用双线性插值时,由于四个取样点的极性不同,是否能直接处理呢,我感觉好像有问题,比如四个数,2正2负,有可能插值后结果就为0了。

          目前,采用了一些非常规的手段,还是基本有一定的成果了,一些不是特别情况的图,使用基于边缘梯度的方式也能获取到较为准确的结果,比如基于NCC那个几个测试图,也是可以的。

          进一步测试表明,这个算法相对于NCC,在某些情况下确实是有更靠谱的识别结果,而且是对强边缘的识别效果很不错。

               

              基于NCC的结果                                               基于边缘梯度的结果

           由上面的测试图也可看出,两种算法对于光照的影响都有一定的抵抗能力。

           再看一个比较有意思的图:

           

           这里的MaxOverlap设置为0.7,MinScore也设置为0.7.

           对于下面这种复杂的边缘重叠的对象也有一定的免疫力。

            

                                               基于NCC的结果                                                                基于边缘梯度的结果

         上述测试图,基于边缘的成功的锁定了20个待检测的目标,而基于NCC的则丢失了一个,当然这并不是说基于NCC的就比基于边缘的差。

           本算法待进一步改进后可能会集成到国产视觉软件Malcon中,详情请看 中国的Malcon跟德国的Halcon的相比的优缺点 

           Malcon官方博客:https://www.cnblogs.com/Malcon

           或者点击:         https://blog.csdn.net/lindrs/article/details/114113280?spm=1001.2014.3001.5502

           目前可通过下面链接获取一个可视化的Demo:  https://files.cnblogs.com/files/Imageshop/TemplateMatching.rar

           同样声明,这个Demo本身是有Bug的(不影响测试使用),请不要将其直接应用到工业环境中,以免造成不必要的损失。

             如果想时刻关注本人的最新文章,也可关注公众号:

                                 

         

  • 相关阅读:
    sharpen和filter2D
    Changing the contrast and brightness of an image!(opencv对比度和亮度调节)
    人脸表情识别
    Pycharm下载和安装
    Anaconda下载与安装
    图像人脸检测+人眼检测 (opencv + c++)
    cv2.VideoWriter()指定写入视频帧编码格式
    python_openCV例程遇到error: (-215) !empty() in function cv::CascadeClassifier::detectMultiScale的简单解决方法
    图像处理库 Pillow与PIL
    IDE bulid构建隐藏了什么(预处理->编译->汇编->链接)
  • 原文地址:https://www.cnblogs.com/Imageshop/p/14615375.html
Copyright © 2011-2022 走看看