opencv图像角点的提取

opencv角点检测(一)

Harris角点检测算法原理简介

harris角点检测算法首先对图像中的每个像素计算2*2的协方差矩阵M,然后求出如下表达式的值:

R=det(M) -k*(trace(M)^2)  (一般k的取值在0.04~0.06之间,opencv中取值范围更大)

det(M)=λ1*λ2      trace(M)=λ1+λ2,    λ1、λ2为协方差矩阵M的特征值;

R值为正且比较大时为角点位置,R值为负时为边缘,R值很小时是平坦区域。

opencv中cornerHarris函数实现harris角点的提取,具体代码如下:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
//添加函数中用到的模块
#include <iostream>

using namespace std;
using namespace cv;
//定义全局变量,与Trackbar相关联的变量声明为全局变量,调用比较方便;
Mat src,src_gray;
int thresh = 150;
int max_thresh = 255;

char* sourceimg = "Source image";
char* cornersimg = "Corners detected";

void Harris_demo(int,void*);

int main(int argc,char* argv[])
{
	src=imread("road.jpg");//读取图像,在当前文件夹下

	cvtColor(src,src_gray,CV_RGB2GRAY);//将图像转换成灰度图

	namedWindow(sourceimg,CV_WINDOW_AUTOSIZE);//一般在创建控制条前,先创建一个窗口用来放置控制条;
	createTrackbar("thresh:",sourceimg,&thresh,max_thresh,Harris_demo);//创建一个控制条,用来改变检测角点的阈值;
	imshow(sourceimg,src);

	Harris_demo(0,0);//调用回调函数;将<span style="font-family: verdana, Arial, helvetica, sans-seriff;">thresh定义为全局变量,不用传递参数;</span>


	waitKey(0);//回车结束
	return 0;
}

void Harris_demo(int,void*)
{
	Mat dst,dst_norm,dst_norm_scaled;

	dst = Mat::zeros(src.size(),CV_32FC1);
	int blocksize = 2;
	int kernel =3;
	double k = 0.04;

	cornerHarris(src_gray,dst,blocksize,kernel,k,4);//进行harris角点检测

	normalize(dst,dst_norm,0,255,NORM_MINMAX,-1,Mat());//对检测的结果进行归一化处理,0到255;
	convertScaleAbs(dst_norm,dst_norm_scaled);//求其绝对值;这个函数会将结果转换成8bit;

	for(int j = 0; j < dst_norm.rows ; j++)
	{
		for(int i = 0; i < dst_norm.cols ; i++)
		{
			if((int) dst_norm.at<float>(j,i) > thresh)//在满足阈值条件的角点处画圆;

			{
				circle(src,Point(i,j),5,Scalar(0,0,255),2,8);
			}
		}
	}
	namedWindow(cornersimg,CV_WINDOW_AUTOSIZE);
	imshow(cornersimg,src);
}
阈值thresh的值为80,运行结果:

opencv图像角点的提取_第1张图片

可以看出,检测出的有些角点粘连在了一起,可以采用膨胀处理进行非极大值抑制。

2、其它Harris角点检测程序

在CSDN上查找资料时,在http://blog.csdn.net/crzy_sparrow/article/details/7391511博客上看到了一个不错的Harris角点检测程序;其先定义了一个harris类,并将具体的检测过程在类的方法中进行实现;有助于理解角点检测的具体过程,而且还能加深对c++类和对象的理解;故将其程序进行整理和重新编写如下:

harris.h
<span style="font-size:14px;">#ifndef HARRIS_H
#define HARRIS_H

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
class harris
{
private:
	Mat cornerStrength;//opencv harris函数检测的结果,即每个像素点的角点响应函数值;
	Mat cornerThresh;//cornerStrength阈值化的结果
	Mat localMax;//局部最大值的结果
	int neighbourhood;//邻域窗口的大小
	int aperture;//sobel边缘检测窗口的大小
	double k;//cornerHarris函数的系数0.04-0.05
	double maxStrength;//角点响应函数的最大值
	double thresh;//角点检测的阈值
	int nonMaxSize;//最大值抑制的邻域窗口的大小
	Mat kernel;//最大值抑制的核,即膨胀用到的核
public:
	harris():neighbourhood(3),aperture(3),k(0.04),maxStrength(0.0),thresh(0.01),nonMaxSize(3)
	{}

	void setLocalMaxWindowsize(int nonMaxSize)
	{
		this->nonMaxSize = nonMaxSize;
	}

	void detect(const Mat image);
	Mat getCornerMap(double qualityLevel);
	void getCorners(vector<Point> &points,double qualityLevel);
	//void getCorners(vector<Point> &points,const Mat &cornerMap);
	void drawOnImage(Mat &image,const vector<Point> &points,Scalar color = Scalar(255,255,255),
		int radius = 3,int thickness = 2);
};

#endif</span>
<span style="font-size:14px;">
</span>
</pre><pre>
harris.cpp

 
 
<span style="font-size:14px;">#include "harris.h"

//计算角点的响应函数以及非极大值抑制
void harris::detect(const Mat image)
{
	//用opencv自带的函数求解角点的响应函数
	cornerHarris(image,cornerStrength,neighbourhood,aperture,k,4);
	double minStrength;
	//求解相应的最大最小值
	minMaxLoc(cornerStrength,&minStrength,&maxStrength);
	Mat dilated;
	//采用默认的3*3的核膨胀,膨胀之后,除了局部最大点和原来相同,其他非局部最大值
	//被3*3邻域内的最大值取代
	dilate(cornerStrength,dilated,Mat());
	compare(cornerStrength,dilated,localMax,CMP_EQ);

}
//获取焦点图像
Mat harris::getCornerMap(double qualityLevel)
{
	Mat cornerMap;
	thresh = qualityLevel*maxStrength;
	threshold(cornerStrength,cornerThresh,thresh,255,THRESH_BINARY);
	cornerThresh.convertTo(cornerMap,CV_8U);
	//和局部最大值与,剩下局部最大值,即完成非极大值抑制,且满足阈值条件
	bitwise_and(cornerMap,localMax,cornerMap);
	return cornerMap;
}
void harris::getCorners(vector<Point> &points,double qualityLevel)
{
	Mat cornerMap = getCornerMap(qualityLevel);

	for(int y = 0; y < cornerMap.rows; y++)
	{
		//取图像每一行的指针
		const uchar* rowPtr = cornerMap.ptr<uchar>(y);
		for(int x = 0; x < cornerMap.cols; x++)
		{
			if(rowPtr[x])
				points.push_back(Point(x,y));
		}
	}
}

void harris::drawOnImage(Mat &image,const vector<Point> &points,Scalar color,int radius,int thickness )
{
	vector<Point>::const_iterator it = points.begin();
	while(it != points.end())
	{
		circle(image,*it,radius,color,thickness);
		it++;
	}
}</span>

main.cpp
 
 
</pre><pre name="code" class="cpp"><span style="font-size:14px;">#include <iostream>
#include "harris.h"
using namespace std;
int main(int argc,char* argv[])
{
	Mat src,src_gray;
	src = imread("road.jpg");

	cvtColor(src,src_gray,CV_BGR2GRAY);

	harris Harris1;
	Harris1.detect(src_gray);

	//获得角点
	vector<Point> POINTS;
	Harris1.getCorners(POINTS,0.03);

	//标记角点
	Harris1.drawOnImage(src,POINTS,Scalar(0,0,255));
	namedWindow("road",CV_WINDOW_AUTOSIZE);
	imshow("road",src);
	waitKey();
	return 0;
}</span>

程序运行的结果如下:


其它角点检测算法和亚像素角点检测见《opencv图像角点提取(二)》。

你可能感兴趣的:(opencv,角点检测,亚像素,harris,Shi-Tomsi)