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