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;    //該圖像特徵點的座標3d

float  size;     //特徵點鄰域直徑orm

float  angle; //特徵點的方向,值爲[零,三百六十),負值表示不使用,有了這個方向,可以讓特徵點擁有更高的辨識度,不然僅僅座標和直徑有時會誤判特徵點視頻

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

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;
}

  

相關文章
相關標籤/搜索