OpenCV中feature2D學習——自定義角點檢測函數

概述

除了之前文章所說的利用Harris進行角點檢測利用Shi-Tomasi方法進行角點檢測外,也可以自己製作角點檢測的函數:使用cornerEigenValsAndVecs()函數和minMaxLoc()函數結合來模擬Harris角點檢測,或者使用cornerMinEigenVal()函數和minMaxLoc()函數結合來模擬Shi-Tomasi角點檢測,最後特徵點選取的判斷條件要根據實際情況進行選擇。

cornerEigenValsAndVecs()函數

(1)函數原型

cornerEigenValsAndVecs()函數在角點檢測中計算掃描圖像塊的特徵向量與特徵值,其函數原型如下:

C++: void cornerEigenValsAndVecs(InputArray src, OutputArray dst, int blockSize, int ksize, int borderType=BORDER_DEFAULT );
C: void cvCornerEigenValsAndVecs(const CvArr* image, CvArr* eigenvv, int block_size, int aperture_size=3 );

(2)函數參數

函數參數說明如下:

src:輸入單通道8-bit或者浮點類型圖像。

dst:用來存儲結果的圖像,大小與輸入圖像一致並且爲CV_32FC(6)類型。

blockSize:鄰域大小。

ksize:Sobel算子當中的核大小,只能取1、3、5、7(具體可參考這裏:Sobel())。

borderType:像素擴展的方法,因爲在濾波處理的過程中會擴展圖像邊緣,每擴張一個邊界像素,都需要計算出該像素點在原圖中的位置,這個功能被提煉出來就變成了borderInterpolate()函數。該函數輸入一個點座標,返回他在原圖中的座標,關於這個函數的詳細解釋,參考:

1、在OpenCV中圖像邊界擴展 copyMakeBorder 的實現_人人IT網

2、borderInterpolate解釋_Halley_新浪博客

(3)函數功能

對於每個像素點p,該函數考慮一個blockSize*blockSize的鄰域S(p),它在鄰域上計算導數的協方差矩陣:



其中導數是使用Sobel()算子計算得到的。

隨後,函數計算矩陣M的特徵值和特徵向量,並將它們以(λ1, λ2, x1, y1, x2,y2)的形式存儲在目標圖像dst中。其中λ1, λ2是M未經過排序的特徵值;x1, y1是對應於λ1的特徵向量;x2, y2是對應於λ2的特徵向量。該函數的輸出能夠用於魯棒的邊緣或角點檢測。

cornerMinEigenVal()函數

(1)函數原型

cornerMinEigenVal()函數在角點檢測中計算梯度矩陣的最小特徵值,其函數原型如下:

C++: void cornerMinEigenVal(InputArray src, OutputArray dst, int blockSize, int ksize=3, int borderType=BORDER_DEFAULT );
C: void cvCornerMinEigenVal(const CvArr* image, CvArr* eigenval, int block_size, int aperture_size=3 );

(2)函數參數

函數參數說明中除了dst必須爲CV_32FC1類型以外,其它與cornerEigenValsAndVecs()函數的一致。

(3)函數功能

功能與cornerEigenValsAndVecs()函數相似,但是它只計算導數協方差矩陣的最小特徵值,按照cornerEigenValsAndVecs()函數給定的特徵值λ1, λ2來說就是min(λ1, λ2)。

代碼示例

(1)採用cornerEigenValsAndVecs()函數和minMaxLoc()函數結合來模擬Harris角點檢測的代碼示例如下:

/**
 * @使用cornerEigenValsAndVecs()函數模擬Harris角點檢測
 * @author holybin
 */

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;

/// 全局變量
Mat src;
Mat srcGray, srcCopy;	//srcCopy用於繪圖,srcGray用於檢測角點
Mat dstHarris;	//dstHarris用於存儲角點檢測的結果
Mat resHarris;	//resHarris用於存儲特徵點選擇後的結果
/// 各類閾值
int HarrisQualityLevel = 50;
int maxQualityLevel = 100;
double HarrisMinVal = 0.0;
double HarrisMaxVal = 0.0;
char* HarrisWindow = "My Harris corner detector";

/// 角點檢測函數聲明
void HarrisFunction( int, void* );

int main( int argc, char** argv )
{
	/// 載入圖像並灰度化
	src = imread("D:\\opencv_pic\\house_small.jpg", 1 );
	cvtColor( src, srcGray, CV_BGR2GRAY );

	/// 設置參數
	int blockSize = 3;
	int apertureSize = 3;

	/// 使用cornerEigenValsAndVecs()函數檢測角點
	dstHarris = Mat::zeros( srcGray.size(), CV_32FC(6) );
	resHarris = Mat::zeros( srcGray.size(), CV_32FC1 );
	cornerEigenValsAndVecs( srcGray, dstHarris, blockSize, apertureSize, BORDER_DEFAULT );

	/// 特徵點選擇
	for( int j = 0; j < srcGray.rows; j++ )
	{
		for( int i = 0; i < srcGray.cols; i++ )
		{
			// 兩個特徵值
			float* lambda = dstHarris.ptr<float>( j, i);
			float lambda1 = lambda[0];
			float lambda2 = lambda[1];
			// 會報錯!!!//
			//float lambda1 = dstHarris.at<float>( j, i, 0);
			//float lambda2 = dstHarris.at<float>( j, i, 1);
			resHarris.at<float>(j,i) = lambda1*lambda2 - 0.04*pow( ( lambda1 + lambda2 ), 2 );
		}
  }
  minMaxLoc( resHarris, &HarrisMinVal, &HarrisMaxVal, 0, 0, Mat() );
  
  /// 創建窗口和滑動條
  namedWindow( HarrisWindow, CV_WINDOW_AUTOSIZE );
  createTrackbar( "Quality:", HarrisWindow, &HarrisQualityLevel, maxQualityLevel, HarrisFunction );  
  HarrisFunction( 0, 0 );
  
  waitKey(0);
  return(0);
}

/// 角點檢測函數實現
void HarrisFunction( int, void* )
{
	/// 深度拷貝原圖像用於繪製角點
	srcCopy = src.clone();

	if( HarrisQualityLevel < 1 )
		HarrisQualityLevel = 1;

	/// 角點滿足條件則繪製
	for( int j = 0; j < srcGray.rows; j++ )
	{ 
		for( int i = 0; i < srcGray.cols; i++ )
		{
			if( resHarris.at<float>(j,i) > HarrisMinVal + ( HarrisMaxVal - HarrisMinVal )*HarrisQualityLevel/maxQualityLevel )
				circle( srcCopy, Point(i,j), 2, Scalar( 0,0,255 ), -1, 8, 0 );
		}
	}
	imshow( HarrisWindow, srcCopy );
	cout<<"Harris Quality Level: "<<HarrisQualityLevel<<endl;
}

實驗結果:




這裏需要注意這裏floatlambda1 = dstHarris.at<float>( j, i, 0);使用at方式訪問Mat的數據會報錯:


所以我改成了採用指針的形式float* lambda = dstHarris.ptr<float>( j, i);。結果顯示當Quality Level增大時,滿足條件被保留的角點數目越來越少。


(2)採用cornerMinEigenVal()函數和minMaxLoc()函數結合來模擬Shi-Tomasi角點檢測的代碼示例如下:

/**
* @使用cornerMinEigenVal()函數模擬Shi-Tomasi角點檢測
* @author holybin
*/

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;

/// 全局變量
Mat src;
Mat srcGray, srcCopy;	//srcCopy用於繪圖,srcGray用於檢測角點
Mat dstShiTomasi;	//dstShiTomasi用於存儲角點檢測的結果
/// 各類閾值
int ShiTomasiQualityLevel = 50;
int maxQualityLevel = 100;
double ShiTomasiMinVal;
double ShiTomasiMaxVal;
char* ShiTomasiWindow = "My Shi-Tomasi corner detector";

/// 角點檢測函數聲明
void ShiTomasiFunction( int, void* );

int main( int argc, char** argv )
{
	/// 載入圖像並灰度化
	src = imread("D:\\opencv_pic\\house_small.jpg", 1 );
	cvtColor( src, srcGray, CV_BGR2GRAY );

	/// 設置參數
	int blockSize = 3;
	int apertureSize = 3;

	/// 使用cornerMinEigenVal()函數檢測角點
	dstShiTomasi = Mat::zeros( srcGray.size(), CV_32FC1 );  
	cornerMinEigenVal( srcGray, dstShiTomasi, blockSize, apertureSize, BORDER_DEFAULT );
	minMaxLoc( dstShiTomasi, &ShiTomasiMinVal, &ShiTomasiMaxVal, 0, 0, Mat() );

	/// 創建窗口和滑動條
	namedWindow( ShiTomasiWindow, CV_WINDOW_AUTOSIZE );   
	createTrackbar( " Quality:", ShiTomasiWindow, &ShiTomasiQualityLevel, maxQualityLevel, ShiTomasiFunction );  
	ShiTomasiFunction( 0, 0 );

	waitKey(0);
	return(0);
}

/// 角點檢測函數實現
void ShiTomasiFunction( int, void* )
{
	/// 深度拷貝原圖像用於繪製角點
	srcCopy = src.clone();

	if( ShiTomasiQualityLevel < 1 )
		ShiTomasiQualityLevel = 1;

	/// 角點滿足條件則繪製
	for( int j = 0; j < srcGray.rows; j++ )
	{ 
		for( int i = 0; i < srcGray.cols; i++ )
		{
			if( dstShiTomasi.at<float>(j,i) > ShiTomasiMinVal + ( ShiTomasiMaxVal - ShiTomasiMinVal )*ShiTomasiQualityLevel/maxQualityLevel )
				circle( srcCopy, Point(i,j), 2, Scalar( 255,0,0 ), -1, 8, 0 );
		}
	}
	imshow( ShiTomasiWindow, srcCopy );
	cout<<"Shi-Tomasi Quality Level: "<<ShiTomasiQualityLevel<<endl;
}

實驗結果:



結果顯示當QualityLevel增大時,滿足條件被保留的角點數目越來越少。

發佈了93 篇原創文章 · 獲贊 97 · 訪問量 104萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章