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

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

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 );

Opencv2系列学习笔记5(检测Harris角点)_第1张图片

Result:

  Opencv2系列学习笔记5(检测Harris角点)_第2张图片

二:极大值抑制

以上获取到的角点图像包含许多角点群,所以需要极大值抑制。我们使用膨胀函数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系列学习笔记5(检测Harris角点)_第3张图片


三:适合跟踪的优质特征

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, 欢迎交流!)

你可能感兴趣的:(opencv2,harris,cornerHarris)