在计算机视觉中,兴趣点(也叫关键点或者特征点)的概念被大量用于解决物体识别、图像匹配、视觉跟踪、三维重建等问题。它依赖于这个想法,即不再观察整副图像,而是选择某些特殊的点,然后对它们执行局部分析。如果能检测到足够多的这种点,同时它们的区分度很高,并且可以精确定位稳定的特征,那么这个方法就很有效。
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);
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);作者:小村长 出处:http://blog.csdn.net/lu597203933 欢迎转载或分享,但请务必声明文章出处。 (新浪微博:小村长zack, 欢迎交流!)