Opencv学习笔记(五)Harris角点检测

 6194人阅读 评论(11) 收藏 image算法测试iteratoralgorithmfeatures

原创文章,转载请注明出处:http://blog.csdn.net/crzy_sparrow/article/details/7391511

文章目录:

一、Harris角点检测基本理论

二、opencv代码实现

三、改进的Harris角点检测

四、FAST角点检测

五、参考文献

六、附录(资料和源码)


一、Harris角点检测基本理论(要讲清楚东西太多,附录提供文档详细说明)

1.1 简略表达:

角点:最直观的印象就是在水平、竖直两个方向上变化均较大的点,即Ix、Iy都较大 
边缘:仅在水平、或者仅在竖直方向有较大的变化量,即Ix和Iy只有其一较大 
平坦地区:在水平、竖直方向的变化量均较小,即Ix、Iy都较小

Opencv学习笔记(五)Harris角点检测_第1张图片



角点响应

R=det(M)-k*(trace(M)^2)   (附录资料给出k=0.04~0.06,opencv指出是0.05-0.5,浮动较大)

det(M)=λ1*λ2      trace(M)=λ1+λ2

R取决于M的特征值,对于角点|R|很大,平坦的区域|R|很小,边缘的R为负值。


1.2 详细描述:见附录里的ppt

1.3 算法步骤

Opencv学习笔记(五)Harris角点检测_第2张图片

Opencv学习笔记(五)Harris角点检测_第3张图片


其中,局部极大值可用先膨胀后与原图比较的方法求得,具体见二中源码。


二、opencv代码实现

harris类

[cpp]  view plain copy
  1. #ifndef HARRIS_H  
  2. #define HARRIS_H  
  3. #include "opencv2/opencv.hpp"  
  4.   
  5. class harris  
  6. {  
  7. private:  
  8.     cv::Mat  cornerStrength;  //opencv harris函数检测结果,也就是每个像素的角点响应函数值  
  9.     cv::Mat cornerTh; //cornerStrength阈值化的结果  
  10.     cv::Mat localMax; //局部最大值结果  
  11.     int neighbourhood; //邻域窗口大小  
  12.     int aperture;//sobel边缘检测窗口大小(sobel获取各像素点x,y方向的灰度导数)  
  13.     double k;  
  14.     double maxStrength;//角点响应函数最大值  
  15.     double threshold;//阈值除去响应小的值  
  16.     int nonMaxSize;//这里采用默认的3,就是最大值抑制的邻域窗口大小  
  17.     cv::Mat kernel;//最大值抑制的核,这里也就是膨胀用到的核  
  18. public:  
  19.     harris():neighbourhood(3),aperture(3),k(0.01),maxStrength(0.0),threshold(0.01),nonMaxSize(3){  
  20.   
  21.     };  
  22.   
  23.     void setLocalMaxWindowsize(int nonMaxSize){  
  24.         this->nonMaxSize = nonMaxSize;  
  25.     };  
  26.   
  27.     //计算角点响应函数以及非最大值抑制  
  28.     void detect(const cv::Mat &image){  
  29.             //opencv自带的角点响应函数计算函数  
  30.             cv::cornerHarris (image,cornerStrength,neighbourhood,aperture,k);  
  31.             double minStrength;  
  32.             //计算最大最小响应值  
  33.             cv::minMaxLoc (cornerStrength,&minStrength,&maxStrength);  
  34.   
  35.             cv::Mat dilated;  
  36.             //默认3*3核膨胀,膨胀之后,除了局部最大值点和原来相同,其它非局部最大值点被  
  37.             //3*3邻域内的最大值点取代  
  38.             cv::dilate (cornerStrength,dilated,cv::Mat());  
  39.             //与原图相比,只剩下和原图值相同的点,这些点都是局部最大值点,保存到localMax  
  40.             cv::compare(cornerStrength,dilated,localMax,cv::CMP_EQ);  
  41.     }  
  42.   
  43.     //获取角点图  
  44.     cv::Mat getCornerMap(double qualityLevel) {  
  45.             cv::Mat cornerMap;  
  46.             // 根据角点响应最大值计算阈值  
  47.             threshold= qualityLevel*maxStrength;  
  48.             cv::threshold(cornerStrength,cornerTh,  
  49.             threshold,255,cv::THRESH_BINARY);  
  50.             // 转为8-bit图  
  51.             cornerTh.convertTo(cornerMap,CV_8U);  
  52.             // 和局部最大值图与,剩下角点局部最大值图,即:完成非最大值抑制  
  53.             cv::bitwise_and(cornerMap,localMax,cornerMap);  
  54.             return cornerMap;  
  55.     }  
  56.   
  57.     void getCorners(std::vector<cv::Point> &points,  
  58.             double qualityLevel) {  
  59.             //获取角点图  
  60.             cv::Mat cornerMap= getCornerMap(qualityLevel);  
  61.             // 获取角点  
  62.             getCorners(points, cornerMap);  
  63.     }  
  64.   
  65.     // 遍历全图,获得角点  
  66.     void getCorners(std::vector<cv::Point> &points,  
  67.     const cv::Mat& cornerMap) {  
  68.   
  69.             forint y = 0; y < cornerMap.rows; y++ ) {  
  70.                     const uchar* rowPtr = cornerMap.ptr<uchar>(y);  
  71.                     forint x = 0; x < cornerMap.cols; x++ ) {  
  72.                     // 非零点就是角点  
  73.                           if (rowPtr[x]) {  
  74.                                 points.push_back(cv::Point(x,y));  
  75.                           }  
  76.                      }  
  77.                 }  
  78.           }  
  79.   
  80.     //用圈圈标记角点  
  81.     void drawOnImage(cv::Mat &image,  
  82.     const std::vector<cv::Point> &points,  
  83.             cv::Scalar color= cv::Scalar(255,255,255),  
  84.             int radius=3, int thickness=2) {  
  85.                     std::vector<cv::Point>::const_iterator it=points.begin();  
  86.                     while (it!=points.end()) {  
  87.                     // 角点处画圈  
  88.                     cv::circle(image,*it,radius,color,thickness);  
  89.                     ++it;  
  90.             }  
  91.     }  
  92.   
  93. };  
  94.   
  95. #endif // HARRIS_H  
相关测试代码:

[cpp]  view plain copy
  1. cv::Mat  image, image1 = cv::imread ("test.jpg");  
  2.    //灰度变换  
  3.    cv::cvtColor (image1,image,CV_BGR2GRAY);  
  4.   
  5.   
  6.    // 经典的harris角点方法  
  7.    harris Harris;  
  8.    // 计算角点  
  9.    Harris.detect(image);  
  10.    //获得角点  
  11.    std::vector<cv::Point> pts;  
  12.    Harris.getCorners(pts,0.01);  
  13.    // 标记角点  
  14.    Harris.drawOnImage(image,pts);  
  15.   
  16.    cv::namedWindow ("harris");  
  17.    cv::imshow ("harris",image);  
  18.    cv::waitKey (0);  
  19.    return 0;  
相关测试结果:

Opencv学习笔记(五)Harris角点检测_第4张图片

三、改进的Harris角点检测

    从经典的Harris角点检测方法不难看出,该算法的稳定性和k有关,而k是个经验值,不好把握,浮动也有可能较大。鉴于此,改进的Harris方法()直接计算出两个特征值,通过比较两个特征值直接分类,这样就不用计算Harris响应函数了。

    另一方面,我们不再用非极大值抑制了,而选取容忍距离:容忍距离内只有一个特征点。
    该算法首先选取一个具有最大   最小特征值的点(即:max(min(e1,e2)),e1,e2是harris矩阵的特征值)作为角点,然后依次按照最大最小特征值顺序寻找余下的角点,当然和前一角点距离在容忍距离内的新角点呗忽略。

    opencv测试该算法代码如下:

[cpp]  view plain copy
  1.     cv::Mat  image, image1 = cv::imread ("test.jpg");  
  2.     //灰度变换  
  3.     cv::cvtColor (image1,image,CV_BGR2GRAY);  
  4.     // 改进的harris角点检测方法  
  5.     std::vector<cv::Point> corners;  
  6.     cv::goodFeaturesToTrack(image,corners,  
  7.     200,  
  8.     //角点最大数目  
  9.     0.01,  
  10.     // 质量等级,这里是0.01*max(min(e1,e2)),e1,e2是harris矩阵的特征值  
  11.     10);  
  12.     // 两个角点之间的距离容忍度  
  13.     harris().drawOnImage(image,corners);//标记角点  
    测试结果如下:
Opencv学习笔记(五)Harris角点检测_第5张图片


四、FAST角点检测

    算法原理比较简单,但实时性很强。

    该算法的角点定义为:若某像素点圆形邻域圆周上有3/4的点和该像素点不同(编程时不超过某阈值th),则认为该点就是候选角点。opencv更极端,选用半径为3的圆周上(上下左右)四个点,若超过三个点和该像素点不同,则该点为候选角点。

    和Harris算法类似,该算法需要非极大值抑制。

opencv代码:

[cpp]  view plain copy
  1. cv::Mat  image, image1 = cv::imread ("test.jpg");  
  2. cv::cvtColor (image1,image,CV_BGR2GRAY);  
  3. //快速角点检测  
  4. std::vector<cv::KeyPoint> keypoints;  
  5. cv::FastFeatureDetector fast(40,true);  
  6. fast .detect (image,keypoints);  
  7. cv::drawKeypoints (image,keypoints,image,cv::Scalar::all(255),cv::DrawMatchesFlags::DRAW_OVER_OUTIMG);  


测试结果如下:

Opencv学习笔记(五)Harris角点检测_第6张图片

五、参考文献

【1】The classical article describing the Harris operator: C. Harris and M.J. Stephens, A combined  corner and edge detector, by Alvey Vision Conference, pp. 147–152, 1988.

【2】The article by J. Shi and C. Tomasi, Good features to track, Int. Conference on Computer Vision  and Pattern Recognition, pp. 593-600, 1994 which introduced these features.

【3】The article by K. Mikolajczyk and C. Schmid, Scale and Affine invariant interest point  detectors, International Journal of Computer Vision, vol 60, no 1, pp. 63-86, 2004, which proposes a multi-scale and affine-invariant Harris operator.

【4】The article by E. Rosten and T. Drummond, Machine learning for high-speed corner detection, in In European Conference on Computer Vision, pp. 430-443, 2006 that describes the FAST feature algorithm in detail

  

2011-04-26 11:11:59|  分类: matlab|字号 订阅

1.3 Harris角点检测算子

Harris[2]角点检测算子是Moravec角点检测算子的改进.

(1) Harris算子用高斯函数代替二值窗口函数,对离中心点越近的像素赋于越大的权重,以减少噪声影响。


Opencv学习笔记(五)Harris角点检测_第7张图片

图1-3 高斯函数

(2) Moravec算子只考虑了每隔45度方向,Harris算子用Taylor展开去近似任意方向。


Harris角点检测算子 - zhaowei0425 - zhaowei0425的博客

写成矩阵形式:

               Harris角点检测算子 - zhaowei0425 - zhaowei0425的博客       (1- 2)

                            Harris角点检测算子 - zhaowei0425 - zhaowei0425的博客                    (1- 3)

式中,Ix为x方向的差分,Iy为y方向的差分,w(x,y)为高斯函数。

(3)Harris采用了一种新的角点判定方法。矩阵M的两个特征向量l1和l2与矩阵M的主曲率成正比。Harris利用l1, l2来表征变化最快和最慢的两个方向.若两个都很大就是角点,一个大一个小就是边缘,两个都小就是在变化缓慢的图像区域.

                            

Opencv学习笔记(五)Harris角点检测_第8张图片

来自文献[11]

图1- 4用矩阵M的特征向量分类图像像素点

但是解特征向量需要比较多的计算量,且两个特征值的和等于矩阵M的迹,两个特征值的积等于矩阵M的行列式。所以用(1-4)式来判定角点质量。(k常取0.04-0.06)

                         Harris角点检测算子 - zhaowei0425 - zhaowei0425的博客                 (1- 4)

(4) Harris算法总结

Step 1:对每一像素点计算相关矩阵M。

Harris角点检测算子 - zhaowei0425 - zhaowei0425的博客

Harris角点检测算子 - zhaowei0425 - zhaowei0425的博客

Harris角点检测算子 - zhaowei0425 - zhaowei0425的博客

Harris角点检测算子 - zhaowei0425 - zhaowei0425的博客

Step 2:计算每像素点的Harris 角点响应。 

              Harris角点检测算子 - zhaowei0425 - zhaowei0425的博客

Step 3.在w*w范围内寻找极大值点,若Harris 角点响应大于阀值,则视为角点。

Harris算子对灰度的平移是不变的,因为只有差分,对旋转也有不变性,但是对尺度很敏感,在一个尺度下是角点, 在在另一个尺度下可能就不是了.

Opencv学习笔记(五)Harris角点检测_第9张图片

图1- 5 harris算子对尺度的敏感性


Opencv学习笔记(五)Harris角点检测_第10张图片

图1- 6 harris算子对简单图像的响应

Harris 算子是一种有效的点特征提取算子,其优点总结起来有: ①计算简单:Harris 算子中只用到灰度的一阶差分以及滤波,操作简单。②提取的点特征均匀而且合理:Harris 算子对图像中的每个点都计算其兴趣值,然后在邻域中选择最优点。实验表明,在纹理信息丰富的区域,Harris 算子可以提取出大量有用的特征点,而在纹理信息少的区域,提取的特征点则较少。③稳定:Harris算子的计算公式中只涉及到一阶导数,因此对图像旋转、灰度变化、噪声影响和视点变换不敏感,它也是比较稳定的一种点特征提取算子。

Harris 算子的局限性有:①它对尺度很敏感,不具有尺度不变性。②提取的角点是像素级的。


你可能感兴趣的:(Opencv学习笔记(五)Harris角点检测)