OPENCV圖像特征點檢測與FAST檢測算法


  前面描述角點檢測的時候說到,角點其實也是一種圖像特征點,對於一張圖像來說,特征點分為三種形式包括邊緣,焦點和斑點,在OPENCV中,加上角點檢測,總共提供了以下的圖像特征點檢測方法

  1. FAST
  2. SURF
  3. ORB
  4. BRISK
  5. KAZE
  6. AKAZE
  7. MESR
  8. GFTT good feature to tack
  9. Bob斑點
  10. STAR
  11. AGAST

  接下來分別講述這是一種圖像特征檢測算法,但是首先,需要了解OPENCV的一種數據結構, KeyPoint結構,該結構的頭文件定義如下:

class KeyPoint

{

Point2f  pt;    //該圖像特征點的坐標

float  size;     //特征點鄰域直徑

float  angle; //特征點的方向,值為[零,三百六十),負值表示不使用,有了這個方向,能夠讓特征點擁有更高的辨識度,否則僅僅坐標和直徑有時會誤判特征點

float  response;//響應程度,代表該點的強壯程度,也就是該點角點程度,用於后期使用和排序

int  octave; //特征點所在的圖像金字塔的組

int  class_id; //用於聚類的id

}

  每個圖像特征點檢測算法最終的目標之一,而當一張圖像的特征點被檢測出來之后,就可以和另一張圖像的特征點進行匹配,根據相似級別判定兩個圖像的相似程度.

  比如我們可以在圖像中檢測一張人臉的特征點,從而來檢索在另一張圖中是否存在相似程度很高的特征點集,從而確認另一張圖像中的人臉以及人臉的位置,等,特征點檢測算法在物體檢測,視覺跟蹤,3D重建的時候都有着重要的作用.

一. 圖像特征點檢測的通用接口
  Opencv為了方便用戶使用圖像特征點檢測的相應算法,將全部的特征點檢測都封在一個類似的API中,名為Ptr的模板類,也就是說,所有的特征檢測算法都實現了相同的借口,detect 檢測圖像特征點.使用方法類似於
  Ptr<相應的特征點檢測類名>變量名 = 相應的特征點檢測類::create()
  變量名->detect(原圖像,特征點向量).
  使用上面描述的算法,就可以調用幾乎全部的圖像特征檢測算法.但是注意,create函數有多個重載函數,如果為空,每個圖像檢測算法都會使用自己的一套默認的初始值來初始化類,如果想修改參數,那么create函數調用的時候需要根據檢測類的不同,設置不同的初始化變量.
  另外,opencv提供而一個快速顯示圖像特征點的函數,如下
  drawKeyPoints(畫布圖像,特征點向量集,輸出的繪制結果,繪制顏色值,繪制模式)
  一般來說,畫布圖像會使用我們檢測特征點的原圖像(一般檢測特征點都是原圖像變換為灰度圖像之后進行的檢測,簡單算法復雜度).
  繪制模式有以下方法可以選擇,是DrawMatchesFlags枚舉
  DEFAULT:只繪制特征點的坐標點,顯示在圖像上就是一個個小圓點,每個小圓點的圓心坐標都是特征點的坐標.
  DRAW_OVER_OUTIMG:函數不創建輸出的圖像,而是直接在輸出圖像變量空間繪制,要求本身輸出圖像變量就是一個初始化好了的,size與type都是已經初始化好的變量
  NOT_DRAW_SINGLE 單點的特征點不被繪制
  DRAW_RICH_KEYPOINT 繪制特征點的時候繪制的是一個個帶有方向的圓,這種方法同時顯示圖像的坐標,size,和方向,是最能顯示特征的一種繪制方式,但是缺點就是繪制結果太雜亂.

一.   FAST特征點檢測算法

FAST算法是基於角點檢測的圖像特征.

一個特征點檢測的算法的第一步是定義什么是特征點,FAST算法定義特征點是如果某個像素點和他周圍領域足夠多的像素點處於不同區域,那么這個像素點就是特征點,對於灰度圖像來說,也就是該點的灰度值和其周圍足夠多的像素點的灰度值不同,那么這個像素點就是一個特征點.

該算法的詳細計算步驟如下

  1. 從圖片中選取一個坐標點,獲取該點的像素值,接下來判定該點是否為特征點.
  2. 選取一個以選取點坐標為圓心的半徑等於三的Bresenham圓(一個計算圓的軌跡的離散算法,得到整數級的圓的軌跡點),一般來說,這個圓上有16個點,如下所示

  

黑點坐標為(0,0),坐標step為1

  1. 現在選取一個閾值,假設為t,關鍵步驟,假設這16個點中,有N個連續的像素點,他們的亮度值與中心點的像素值的差大於或者小於t,那么這個點就是一個特征點.(n的取值一般取值12或者9,實驗證明9可以取得更好的效果,因為可以獲取更多的特征點,后面進行處理時,數據樣本額相對多一些).
  2. 加入每個軌跡點都需要遍歷的話,那么需要的時間比較長,有一種比較簡單的方法可以選擇,那就是僅僅檢查在位置1,9,5和13四個位置的像素,首先檢測位置1和位置9,如果它們都比閾值暗或比閾值亮,再檢測位置5和位置13, 如果P" role="presentation" style="word-wrap: normal; max-width: none; max-height: none; min-width: 0px; min-height: 0px; float: none;" id="MathJax-Element-8-Frame">中心點是一個角點,那么上述四個像素點中至少有3個應該必須都大於Ip+t" role="presentation" style="word-wrap: normal; max-width: none; max-height: none; min-width: 0px; min-height: 0px; float: none;" id="MathJax-Element-9-Frame">中心點亮度值+閾值或者小於Ip&#x2212;t" role="presentation" style="word-wrap: normal; max-width: none; max-height: none; min-width: 0px; min-height: 0px; float: none;" id="MathJax-Element-10-Frame">中心點亮度值-閾值,因為若是一個角點,超過四分之三圓的部分應該滿足判斷條件。如果不滿足,那么p" role="presentation" style="word-wrap: normal; max-width: none; max-height: none; min-width: 0px; min-height: 0px; float: none;" id="MathJax-Element-11-Frame">中心點不可能是一個角點。對於所有點做上面這一部分初步的檢測后,符合條件的將成為候選的角點,我們再對候選的角點,做完整的測試,即檢測圓上的所有點.
  3. 但是,這種檢測方法會帶來一個問題,就是造成特征點的聚簇效應,多個特征點在圖像的某一塊重復高頻率的出現,FAST算法提出了一種非極大值抑制的辦法來消除這種情況,具體辦法如下.
    1. 為每一個檢測到的特征點計算它的響應大小(score function)VV。這里VV定義為中心點和它周圍16個像素點的絕對偏差的和.
    2. 考慮兩個相鄰的特征點,並比較它們的VV值
    3. VV值較低的點將會被刪除

  以上就是快速特征點檢測的原理,OPENCV中定義的快速特征點檢測算法的檢測API如下

  static Ptr<FastFeatureDetector> create( int threshold=10, bool nonmaxSuppression=true,

                                 int type=FastFeatureDetector::TYPE_9_16 );

  threshold是指比較時邊緣軌跡點和中心點的差值,也就是第三步的閾值t, nonmaxSuppression代表是否使用第五步非極大值抑制,如果發現fast檢測的結果有聚簇情況,那么可以考慮采用,第三個參數type的取值來自於FastFeatureDetector枚舉,有如下取值:

  1. TYPE_5_8 從軌跡中取8個點,當有5個點滿足條件,就是特征點.
  2. TYPE_7_12 取軌跡12個點,7個滿足條件,就是特征點.
  3. TYPE_9_16 取軌跡16個點,當9個滿足條件,就是特征點.

  綜上所述我們可以看出,FAST檢測算法沒有多尺度的問題,所以計算速度相對較快,但是當圖片中的噪點較多的時候,會產生較多的錯誤特征點,健壯性並不好,並且, 算法的效果還依賴於一個閾值t。而且FAST不產生多尺度特征而且FAST特征點沒有方向信息,這樣就會失去旋轉不變性.但是在要求實時性的場合,比如視頻監控的物體識別,是可以使用的.

使用代碼如下

//fast
int main(int argc,char* argv[])
{
	Mat srcImage = imread("F:\\opencv\\OpenCVImage\\FeatureDetectSrc1.jpg");
	Mat srcGrayImage;
	if (srcImage.channels() == 3)
	{
		cvtColor(srcImage,srcGrayImage,CV_RGB2GRAY);
	}
	else
	{
		srcImage.copyTo(srcGrayImage);
	}
	vector<KeyPoint>detectKeyPoint;
	Mat keyPointImage1,keyPointImage2;

	Ptr<FastFeatureDetector> fast = FastFeatureDetector::create();
	fast->detect(srcGrayImage,detectKeyPoint);
	drawKeypoints(srcImage,detectKeyPoint,keyPointImage1,Scalar(0,0,255),DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
	drawKeypoints(srcImage,detectKeyPoint,keyPointImage2,Scalar(0,0,255),DrawMatchesFlags::DEFAULT);

	imshow("src image",srcImage);
	imshow("keyPoint image1",keyPointImage1);
	imshow("keyPoint image2",keyPointImage2);

	imwrite("F:\\opencv\\OpenCVImage\\FeatureDetectSrc1FASTKeyPointImageDefault.jpg",keyPointImage2);

	waitKey(0);
	return 0;
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM