harris角点检测
![](http://static.blog.csdn.net/images/category_icon.jpg)
版权声明:本文为博主原创文章,未经博主允许不得转载。
在计算机视觉中,兴趣点(也叫关键点或者特征点)的概念被大量用于解决物体识别、图像匹配、视觉跟踪、三维重建等问题。它依赖于这个想法,即不再观察整副图像,而是选择某些特殊的点,然后对它们执行局部分析。如果能检测到足够多的这种点,同时它们的区分度很高,并且可以精确定位稳定的特征,那么这个方法就很有效。
Harris角点的理论部分见opencv1的这篇blog:http://blog.csdn.net/lu597203933/article/details/15088485。 下面阐述opencv2中如何进行harris角点检测和极大值抑制。
一:harris角点检测
Code:
- int main()
- {
- Mat image = imread("F:\\huangrong.jpg", 0);
- if(!image.data)
- {
- cout << "Fail to load image" << endl;
- return 0;
- }
- Mat cornerStrength;
- int blockSize = 2; //
- int kSize = 3; // the size of sobel kernel
- cornerHarris(image, cornerStrength, blockSize, kSize, 0.01); // 计算的结果为由公式得到的分数
- // 二值化
- Mat harrisCorner;
- double thresh = 0.00001;
- threshold(cornerStrength, harrisCorner, thresh, 255, THRESH_BINARY_INV);
- namedWindow("image");
- imshow("image", image);
- namedWindow("cornerStrength");
- imshow("cornerStrength", cornerStrength);
- namedWindow("harrisCorner");
- imshow("harrisCorner", harrisCorner);
- waitKey(0);
- return 0;
- }
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
- class HarrisDetector{
- private:
- // 表示角点强度的32位浮点图像
- Mat cornerStrength;
- // 表示阀值后角度的32位浮点图像
- Mat cornerTh;
- // 局部极大值图像(内部)--标识
- Mat localMax;
- int neighbourhood;
- int aperture; // the size of the sobel kernel
- double k;
- //阀值
- double thre; // 阀值
- public:
- HarrisDetector():neighbourhood(2),aperture(3), k(0.01),
- thre(0.00001){
- //setLocalMaxWindowSize(nonMaxSize);
- }
- void detect(Mat &image); // 得到局部范围内的极大值点所对应的标识
- Mat getCornerMap(); //得到局部极大值
- void getCorners(vector<Point> &points); //将局部极大值点push入vector中
- void drawOnImage(Mat &image, vector<Point> &points);
- };
- void HarrisDetector::detect(Mat &image){ // 通过膨胀和比较得到局部极大值点所对应的标识。。
- cornerHarris(image, cornerStrength, neighbourhood, aperture, k);
- Mat dilated;
- //膨胀运算替换每个像素值为相邻范围内的最大值,只有局部极大值的点才会保留原样
- dilate(cornerStrength, dilated, Mat()); // 膨胀操作
- compare(cornerStrength, dilated, localMax, CMP_EQ); // 对应点是否相等进行比较 是则为255,否则为0
- }
- Mat HarrisDetector::getCornerMap() // 二值化后通过与操作得到抑制后得极大值 ===角点
- {
- Mat cornerMap;
- // 对角点图像进行阀值化
- threshold(cornerStrength, cornerTh, thre, 255, THRESH_BINARY);
- // 转换为8位图像。。
- cornerTh.convertTo(cornerMap, CV_8U);
- // 非极大值抑制
- bitwise_and(cornerMap, localMax, cornerMap);
- return cornerMap;
- }
- void HarrisDetector::getCorners(vector<Point> &points) // 将极大值点所对应的points放入
- {
- Mat cornerMap = getCornerMap();
- for(int y = 0; y < cornerMap.rows; y++)
- {
- uchar *cornerPtr = cornerMap.ptr<uchar>(y); // 遍历所有的特征点
- for(int x = 0; x < cornerMap.cols; x++)
- {
- if(cornerPtr[x]){
- points.push_back(Point(x, y));
- }
- }
- }
- }
- void HarrisDetector::drawOnImage(Mat &image, vector<Point> &points)
- {
- int radius = 3, thickness = 2;
- vector<Point>::iterator it = points.begin();
- // 对于所有角点
- while(it!= points.end())
- {
- // 绘制一个圆
- circle(image, *it, radius, Scalar(255,255,255), thickness);
- it ++;
- }
- }
main.cpp:
- Mat image = imread("F:\\huangrong.jpg", 0);
- vector<Point> points;
- HarrisDetector hdetector;
- hdetector.detect(image); //// 通过膨胀和比较得到局部极大值点所对应的标识。。
- hdetector.getCorners(points); // 得到极大值并将极大值点所对应的points放入
- cout << points.size()<< endl;
- hdetector.drawOnImage(image, points);<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
Result:
三:适合跟踪的优质特征
Opencv2自带了goodFeaturesToTrack这个函数,用于解决特征点聚类问题,除了引入局部极大值的条件,特征点倾向于在图像中不均匀分布,集中在在纹理丰富的部分。该函数的具体解释见代码注释。
Code:
- /*1:将cornerHarris函数得到的得分进行降序排列,依次取为角点,数量不超过100个,两个角点之间的距离要大于10。。
- 效果:解决了特征点聚类问题,此外特征点倾向于在图像中均匀分布。
- */
- goodFeaturesToTrack(image, points, 100, 0.01, 10); // 0.01 为质量等级
- cout << points.size() << endl;
此外cv:: goodFeaturesToTrack函数拥有一个封装类cv::GoodFeaturesToTrackDetector,他继承自抽象类FeatureDetector类。下面代码实现功能和上面一样。
Code:
- /*2:与1的效果是一样的,只是goodFeaturesToTrack函数拥有一个封装类GoodsFeaturesToTrackDetector,*/
- Mat result;
- vector<KeyPoint> keypoints; // 特征点向量
- GoodFeaturesToTrackDetector gftt(100, 0.01, 10); // 检测器的构造函数
- gftt.detect(image, keypoints); // 检测
- drawKeypoints(image, keypoints, result);