Opencv2系列学习笔记5(检测Harris角点)

在计算机视觉中,兴趣点(也叫关键点或者特征点)的概念被大量用于解决物体识别、图像匹配、视觉跟踪、三维重建等问题。它依赖于这个想法,即不再观察整副图像,而是选择某些特殊的点,然后对它们执行局部分析。如果能检测到足够多的这种点,同时它们的区分度很高,并且可以精确定位稳定的特征,那么这个方法就很有效。

Harris角点的理论部分见opencv1的这篇blog:http://blog.csdn.net/lu597203933/article/details/15088485。 下面阐述opencv2中如何进行harris角点检测和极大值抑制。

一:harris角点检测

Code:   

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. int main()  
  2. {  
  3.     Mat image = imread("F:\\huangrong.jpg", 0);  
  4.     if(!image.data)  
  5.     {  
  6.         cout << "Fail to load image" << endl;  
  7.         return 0;  
  8.     }  
  9.     Mat cornerStrength;  
  10.     int blockSize = 2;       //   
  11.     int kSize = 3;    // the size of sobel kernel  
  12.     cornerHarris(image, cornerStrength, blockSize, kSize, 0.01);  // 计算的结果为由公式得到的分数  
  13.     //  二值化  
  14.     Mat harrisCorner;  
  15.     double thresh = 0.00001;  
  16.     threshold(cornerStrength, harrisCorner, thresh, 255, THRESH_BINARY_INV);  
  17.     namedWindow("image");  
  18.     imshow("image", image);  
  19.     namedWindow("cornerStrength");  
  20.     imshow("cornerStrength", cornerStrength);  
  21.     namedWindow("harrisCorner");  
  22.     imshow("harrisCorner", harrisCorner);  
  23.     waitKey(0);  
  24.     return 0;  
  25. }  

Explaination:

<1>opencv2中使用cornerHarris(InputArray src, OutputArray dst, int blockSize,int ksize, double k, int borderType=BORDER_DEFAULT );

    第一个参数: 输入源图像

    第二个参数:输出 用于保存计算得到的得分

    第三个参数:相邻像素尺寸

    第四个:sobel运算核大小

    第五:公式中的参数

<2>二值化函数threshold( InputArray src, OutputArray dst,doublethresh,double maxval, inttype );

Result:

 

二:极大值抑制

以上获取到的角点图像包含许多角点群,所以需要极大值抑制。我们使用膨胀函数dilate和比较compare运算来进行抑制

主要思想是通过dilate和compare这两个函数得到极大值点所对应的标识,后将二值化的得分值与标识进行与运算即bitwise_and 函数。具体解释见代码注释。

Code:

HarrisDetector.h

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. class HarrisDetector{  
  2. private:  
  3.     // 表示角点强度的32位浮点图像  
  4.     Mat cornerStrength;  
  5.     // 表示阀值后角度的32位浮点图像  
  6.     Mat cornerTh;  
  7.     //  局部极大值图像(内部)--标识  
  8.     Mat localMax;  
  9.     int neighbourhood;  
  10.     int aperture;   // the size of the sobel kernel  
  11.     double k;     
  12.     //阀值  
  13.     double thre;           //  阀值  
  14.   
  15. public:  
  16.     HarrisDetector():neighbourhood(2),aperture(3), k(0.01),   
  17.         thre(0.00001){  
  18.         //setLocalMaxWindowSize(nonMaxSize);  
  19.     }  
  20.     void detect(Mat &image);    // 得到局部范围内的极大值点所对应的标识  
  21.     Mat getCornerMap();              //得到局部极大值  
  22.     void getCorners(vector<Point> &points);   //将局部极大值点push入vector中  
  23.     void drawOnImage(Mat &image, vector<Point> &points);  
  24. };  
  25.   
  26. void HarrisDetector::detect(Mat &image){   // 通过膨胀和比较得到局部极大值点所对应的标识。。  
  27.     cornerHarris(image, cornerStrength, neighbourhood, aperture, k);  
  28.     Mat dilated;  
  29.     //膨胀运算替换每个像素值为相邻范围内的最大值,只有局部极大值的点才会保留原样  
  30.     dilate(cornerStrength, dilated, Mat());     // 膨胀操作  
  31.     compare(cornerStrength, dilated, localMax, CMP_EQ);    // 对应点是否相等进行比较 是则为255,否则为0  
  32. }  
  33.   
  34. Mat HarrisDetector::getCornerMap()         // 二值化后通过与操作得到抑制后得极大值 ===角点  
  35. {  
  36.     Mat cornerMap;  
  37.     // 对角点图像进行阀值化  
  38.     threshold(cornerStrength, cornerTh, thre, 255, THRESH_BINARY);  
  39.     // 转换为8位图像。。  
  40.     cornerTh.convertTo(cornerMap, CV_8U);  
  41.     // 非极大值抑制  
  42.     bitwise_and(cornerMap, localMax, cornerMap);  
  43.     return cornerMap;  
  44. }  
  45. void HarrisDetector::getCorners(vector<Point> &points)   // 将极大值点所对应的points放入  
  46. {  
  47.     Mat cornerMap = getCornerMap();  
  48.     for(int y = 0; y < cornerMap.rows; y++)  
  49.     {  
  50.         uchar *cornerPtr = cornerMap.ptr<uchar>(y);      // 遍历所有的特征点  
  51.         for(int x = 0; x < cornerMap.cols; x++)  
  52.         {  
  53.             if(cornerPtr[x]){  
  54.                 points.push_back(Point(x, y));  
  55.             }  
  56.         }  
  57.     }  
  58. }  
  59.   
  60. void HarrisDetector::drawOnImage(Mat &image, vector<Point> &points)  
  61. {  
  62.     int radius = 3, thickness = 2;  
  63.     vector<Point>::iterator it = points.begin();  
  64.     // 对于所有角点  
  65.     while(it!= points.end())  
  66.     {  
  67.         // 绘制一个圆  
  68.         circle(image, *it, radius, Scalar(255,255,255), thickness);  
  69.         it ++;  
  70.     }  
  71. }  

main.cpp:

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. Mat image = imread("F:\\huangrong.jpg", 0);  
  2.     vector<Point> points;  
  3.     HarrisDetector hdetector;  
  4.     hdetector.detect(image);           通过膨胀和比较得到局部极大值点所对应的标识。。  
  5.     hdetector.getCorners(points);        // 得到极大值并将极大值点所对应的points放入  
  6.     cout << points.size()<< endl;  
  7.     hdetector.drawOnImage(image, points);<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">    </span>  

Result:


三:适合跟踪的优质特征

Opencv2自带了goodFeaturesToTrack这个函数,用于解决特征点聚类问题,除了引入局部极大值的条件,特征点倾向于在图像中不均匀分布,集中在在纹理丰富的部分。该函数的具体解释见代码注释。

Code:

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. /*1:将cornerHarris函数得到的得分进行降序排列,依次取为角点,数量不超过100个,两个角点之间的距离要大于10。。 
  2.     效果:解决了特征点聚类问题,此外特征点倾向于在图像中均匀分布。 
  3.     */  
  4.     goodFeaturesToTrack(image, points, 100, 0.01, 10);  // 0.01 为质量等级  
  5.     cout << points.size() << endl;  

此外cv:: goodFeaturesToTrack函数拥有一个封装类cv::GoodFeaturesToTrackDetector,他继承自抽象类FeatureDetector类。下面代码实现功能和上面一样。

Code:

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. /*2:与1的效果是一样的,只是goodFeaturesToTrack函数拥有一个封装类GoodsFeaturesToTrackDetector,*/  
  2.     Mat result;  
  3.     vector<KeyPoint> keypoints;   // 特征点向量  
  4.     GoodFeaturesToTrackDetector gftt(100, 0.01, 10);  // 检测器的构造函数  
  5.     gftt.detect(image, keypoints);          // 检测  
  6.     drawKeypoints(image, keypoints, result);  
作者:小村长  出处:http://blog.csdn.net/lu597203933  欢迎转载或分享,但请务必声明文章出处。 (新浪微博:小村长zack, 欢迎交流!)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值