1. 程式人生 > >【OpenCV3】角點檢測——cv::goodFeaturesToTrack()與cv::cornerSubPix()詳解

【OpenCV3】角點檢測——cv::goodFeaturesToTrack()與cv::cornerSubPix()詳解

一提到角點檢測,最常用的方法莫過於Harris角點檢測,opencv中也提供了Harris角點檢測的介面,即cv::cornerHarris(),但是Harris角點檢測存在很多缺陷(如角點是畫素級別的,速度較慢等),因此我們這裡將介紹opencv中的另一個功能更為強大的函式——cv::goodFeaturesToTrack(),它不僅支援Harris角點檢測,也支援Shi Tomasi演算法的角點檢測。但是,該函式檢測到的角點依然是畫素級別的,若想獲取更為精細的角點座標,則需要呼叫cv::cornerSubPix()函式進一步細化處理,即亞畫素。

1、cv::goodFeaturesToTrack()角點檢測

cv::goodFeaturesToTrack()的具體呼叫形式如下:

	void cv::goodFeaturesToTrack(
		cv::InputArray image, // 輸入影象(CV_8UC1 CV_32FC1)
		cv::OutputArray corners, // 輸出角點vector
		int maxCorners, // 最大角點數目
		double qualityLevel, // 質量水平係數(小於1.0的正數,一般在0.01-0.1之間)
		double minDistance, // 最小距離,小於此距離的點忽略
		cv::InputArray mask = noArray(), // mask=0的點忽略
		int blockSize = 3, // 使用的鄰域數
		bool useHarrisDetector = false, // false ='Shi Tomasi metric'
		double k = 0.04 // Harris角點檢測時使用
	);


第一個引數是輸入影象(8位或32位單通道圖)。

第二個引數是檢測到的所有角點,型別為vector或陣列,由實際給定的引數型別而定。如果是vector,那麼它應該是一個包含cv::Point2f的vector物件;如果型別是cv::Mat,那麼它的每一行對應一個角點,點的x、y位置分別是兩列。

第三個引數用於限定檢測到的點數的最大值。

第四個引數表示檢測到的角點的質量水平(通常是0.10到0.01之間的數值,不能大於1.0)。

第五個引數用於區分相鄰兩個角點的最小距離(小於這個距離得點將進行合併)。

第六個引數是mask,如果指定,它的維度必須和輸入影象一致,且在mask值為0處不進行角點檢測。

第七個引數

是blockSize,表示在計算角點時參與運算的區域大小,常用值為3,但是如果影象的解析度較高則可以考慮使用較大一點的值。

第八個引數用於指定角點檢測的方法,如果是true則使用Harris角點檢測,false則使用Shi Tomasi演算法。

第九個引數是在使用Harris演算法時使用,最好使用預設值0.04。

下面使用測試程式碼,看一下實際的檢測效果。

測試程式碼如下:

	cv::Mat image_color = cv::imread("house.jpg", cv::IMREAD_COLOR);

	//使用灰度影象進行角點檢測
	cv::Mat image_gray;
	cv::cvtColor(image_color, image_gray, cv::COLOR_BGR2GRAY);

	//設定角點檢測引數
	std::vector<cv::Point2f> corners;
	int max_corners = 200;
	double quality_level = 0.01;
	double min_distance = 3.0;
	int block_size = 3;
	bool use_harris = false;
	double k = 0.04;

	//角點檢測
	cv::goodFeaturesToTrack(image_gray, 
							corners, 
							max_corners, 
							quality_level, 
							min_distance, 
							cv::Mat(), 
							block_size, 
							use_harris, 
							k);

	//將檢測到的角點繪製到原圖上
	for (int i = 0; i < corners.size(); i++)
	{
		cv::circle(image_color, corners[i], 1, cv::Scalar(0, 0, 255), 2, 8, 0);
	}

	cv::imshow("house corner", image_color);
	cv::waitKey(0);
	return;


實際檢測效果如下:


2、cv::cornerSubPix()亞畫素角點檢測

前面已經提及,cv::goodFeaturesToTrack()提取到的角點只能達到畫素級別,在很多情況下並不能滿足實際的需求,這時,我們則需要使用cv::cornerSubPix()對檢測到的角點作進一步的優化計算,可使角點的精度達到亞畫素級別。

具體呼叫形式如下:

	void cv::cornerSubPix(
		cv::InputArray image, // 輸入影象
		cv::InputOutputArray corners, // 角點(既作為輸入也作為輸出)
		cv::Size winSize, // 區域大小為 NXN; N=(winSize*2+1)
		cv::Size zeroZone, // 類似於winSize,但是總具有較小的範圍,Size(-1,-1)表示忽略
		cv::TermCriteria criteria // 停止優化的標準
	);

第一個引數是輸入影象,和cv::goodFeaturesToTrack()中的輸入影象是同一個影象。

第二個引數是檢測到的角點,即是輸入也是輸出。

第三個引數是計算亞畫素角點時考慮的區域的大小,大小為NXN; N=(winSize*2+1)。

第四個引數作用類似於winSize,但是總是具有較小的範圍,通常忽略(即Size(-1, -1))。

第五個引數用於表示計算亞畫素時停止迭代的標準,可選的值有cv::TermCriteria::MAX_ITER 、cv::TermCriteria::EPS(可以是兩者其一,或兩者均選),前者表示迭代次數達到了最大次數時停止,後者表示角點位置變化的最小值已經達到最小時停止迭代。二者均使用cv::TermCriteria()建構函式進行指定。

下面就通過一個示例看看cv::cornerSubPix()亞畫素角點檢測的具體效果。

	cv::Mat image_color = cv::imread("image.jpg", cv::IMREAD_COLOR);

	//用於繪製亞畫素角點
	cv::Mat image_copy = image_color.clone();
	//使用灰度影象進行角點檢測
	cv::Mat image_gray;
	cv::cvtColor(image_color, image_gray, cv::COLOR_BGR2GRAY);

	//設定角點檢測引數
	std::vector<cv::Point2f> corners;
	int max_corners = 100;
	double quality_level = 0.01;
	double min_distance = 10;
	int block_size = 3;
	bool use_harris = false;
	double k = 0.04;

	//角點檢測
	cv::goodFeaturesToTrack(image_gray,
		corners,
		max_corners,
		quality_level,
		min_distance,
		cv::Mat(),
		block_size,
		use_harris,
		k);

	//將檢測到的角點繪製到原圖上
	for (int i = 0; i < corners.size(); i++)
	{
		cv::circle(image_color, corners[i], 5, cv::Scalar(0, 0, 255), 2, 8, 0);
	}

	//指定亞畫素計算迭代標註
	cv::TermCriteria criteria = cv::TermCriteria(
					cv::TermCriteria::MAX_ITER + cv::TermCriteria::EPS,
					40,
					0.01);

	//亞畫素檢測
	cv::cornerSubPix(image_gray, corners, cv::Size(5, 5), cv::Size(-1, -1), criteria);

	//將檢測到的亞畫素角點繪製到原圖上
	for (int i = 0; i < corners.size(); i++)
	{
		cv::circle(image_copy, corners[i], 5, cv::Scalar(0, 255, 0), 2, 8, 0);
	}

	cv::imshow("corner", image_color);
	cv::imshow("sub pixel corner", image_copy);

	cv::imwrite("corner.jpg", image_color);
	cv::imwrite("corner_sub.jpg", image_copy);
	cv::waitKey(0);
	return;


直接角點檢測和亞畫素角點檢測的結果分別如下:



從檢測的效果來看,使用亞畫素角點檢測后角點的精細度確實得到了顯著的提升。

2017.04.07