特徵檢測與匹配是Computer Vision 應用總重要的一部分,這須要尋找圖像之間的特徵創建對應關係。點,也就是圖像中的特殊位置,是很經常使用的一類特徵,點的局部特徵也能夠叫作「關鍵特徵點」(keypoint feature),或「興趣點」(interest point),或「角點」(conrner)。html
關於角點的具體描述能夠有幾種:算法
當一個窗口在圖像上移動,在平滑區域如圖(a),窗口在各個方向上沒有變化。在邊緣上如圖(b),窗口在邊緣的方向上沒有變化。在角點處如圖(c),窗口在各個方向上具備變化。Harris角點檢測正是利用了這個直觀的物理現象,經過窗口在各個方向上的變化程度,決定是否爲角點。函數
將圖像窗口平移[u,v]產生灰度變化E(u,v)spa
由:, 獲得:.net
對於局部微小的移動量 [u,v],近似表達爲:3d
其中M是 2*2 矩陣,可由圖像的導數求得:rest
E(u,v)的橢圓形式以下圖:code
定義角點響應函數 R 爲:orm
Harris角點檢測算法就是對角點響應函數R進行閾值處理:R > threshold,即提取R的局部極大值。htm
OpenCV中定義了 cornerHarris 函數:
void cornerHarris( InputArray src, OutputArray dst, int blockSize, int ksize, double k, int borderType=BORDER_DEFAULT );
能夠結合 convertScaleAbs 函數,經過閾值取角點:
void cornerHarris_demo( int, void* ) { Mat dst, dst_norm; dst = Mat::zeros( src.size(), CV_32FC1 ); /// Detector parameters int blockSize = 2; int apertureSize = 3; double k = 0.04; /// Detecting corners cornerHarris( src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT ); /// Normalizing normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() ); convertScaleAbs( dst_norm, dst_norm_scaled ); /// Drawing a circle around corners 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( dst_norm_scaled, Point( i, j ), 5, Scalar(0), 2, 8, 0 ); circle(src,Point( i, j ), 5, Scalar(255,0,0), -1, 8, 0 ); } } } /// Showing the result imshow( corners_window, dst_norm_scaled ); imshow( source_window, src ); }
Shi-Tomasi 算法是Harris 算法的改進。Harris 算法最原始的定義是將矩陣 M 的行列式值與 M 的跡相減,再將差值同預先給定的閾值進行比較。後來Shi 和Tomasi 提出改進的方法,若兩個特徵值中較小的一個大於最小閾值,則會獲得強角點。
如上面第二幅圖中,對自相關矩陣 M 進行特徵值分析,產生兩個特徵值和兩個特徵方向向量。由於較大的不肯定度取決於較小的特徵值,也就是,因此經過尋找最小特徵值的最大值來尋找好的特徵點也就解釋的通了。
Shi 和Tomasi 的方法比較充分,而且在不少狀況下能夠獲得比使用Harris 算法更好的結果。
因爲這種Shi-Tomasi算子與1994年在文章 Good Features to Track [1]中提出,OpenCV 實現的算法的函數名定義爲 goodFeaturesToTrack:
void goodFeaturesToTrack( InputArray image, OutputArray corners, int maxCorners, double qualityLevel, double minDistance, InputArray mask=noArray(), int blockSize=3, bool useHarrisDetector=false, double k=0.04 );
自定義使用函數(以方便createTrackbar的響應)以下:
void cornerShiTomasi_demo( int, void* ) { if( maxCorners < 1 ) { maxCorners = 1; } /// Parameters for Shi-Tomasi algorithm vector<Point2f> corners; double qualityLevel = 0.01; double minDistance = 10; int blockSize = 3; bool useHarrisDetector = false; double k = 0.04; /// Copy the source image Mat cormat; /// Apply corner detection :Determines strong corners on an image. goodFeaturesToTrack( src_gray, corners, maxCorners, qualityLevel, minDistance, Mat(), blockSize, useHarrisDetector, k ); /// Draw corners detected for( int i = 0; i < corners.size(); i++ ){ circle( dst_norm_scaled, corners[i], 5, Scalar(255), 2, 8, 0 ); circle( src, corners[i], 4, Scalar(0,255,0), 2, 8, 0 ); } /// Show what you got imshow( corners_window, dst_norm_scaled ); imshow( source_window, src ); }
在主函數中定義兩個進度條方便調整閾值:
namedWindow( source_window, CV_WINDOW_AUTOSIZE ); createTrackbar( "Threshold: ", source_window, &thresh, max_thresh, cornerHarris_demo ); createTrackbar( "Max corners:", source_window, &maxCorners, maxTrackbar, cornerShiTomasi_demo ); namedWindow( corners_window, CV_WINDOW_AUTOSIZE ); namedWindow( source_window, CV_WINDOW_AUTOSIZE ); imshow( source_window, src ); cornerHarris_demo( 0, 0 ); cornerShiTomasi_demo( 0, 0 );
這裏還須要說的是OpenCV 2.4.2中給的角點檢測跟蹤的示例代碼有些問題,是應爲SURF等再也不定義在 feature2d模塊中,而是legacy和nonfree,因此須要加入引用:
#include "opencv2/legacy/legacy.hpp" #include "opencv2/nonfree/nonfree.hpp"
角點檢測結果:
藍色實心點爲Harris檢測結果,綠色空心圈爲goodFeaturetoTrack檢測結果。
M特徵值分解後每一個像素點相減的圖(也就是Harris閾值判斷的圖)以下:
黑色實心點爲Harris閾值檢測結果,白色空心圈爲閾值爲27時Shi-Tomasi檢測結果。
[1] Shi and C. Tomasi. Good Features to Track. Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition, pages 593-600, June 1994.
[2] Richard Szeliski. Computer Vision: Algorithms and Applications. Springer, New York, 2010.
[3] 圖像特徵點提取PPT http://wenku.baidu.com/view/f61bc369561252d380eb6ef0.html