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,運行結果:


可以看出,檢測出的有些角點粘連在了一起,可以採用膨脹處理進行非極大值抑制。

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圖像角點提取(二)》。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章