影像特征—FAST關鍵點
一、引言
最近在看視覺slam十四講這本書,里面關于影像特征點的一些總結非常值得學習一下,
1.特征點所應具有的性質
(1)可重復性:相同的特征可以在不同的影像中找到;
(2)可區別性:不同的特征具有不同的表達;
(3)高效率:同一影像中,特征點的數量應遠小于像素的數量;
(4)本地性:特征僅與一小片影像區域有關,
2.常見的一些特征提取方法的區別
(1)SIFT(尺度不變特征變換)特征:屬于最為經典的一種,該方法充分地考慮了在影像變換程序中出現的光照、
尺度、旋轉等變化,因此也使得這種方法的計算量極大,使用非常耗時,
(2)FAST關鍵點:屬于計算特別快的一種特征點檢測方法,之所以快是因為這種方法只是只是找到了關鍵點,
并沒有相應的描述子,
(3)ORB特征:該方法改進了FAST檢測不具有方向性的問題,并且采用速度極快的二進制描述子BRIEF,使整個
影像特征的提取速度大大加快,
補充:特征點是由關鍵點和描述子兩部分組成,關鍵點是指該特征點在影像中的位置,而描述子是描述特征點
周圍像素的資訊,
二、FAST關鍵點
1.檢測思路
如果一個像素與鄰域的像素差別較大(過亮或過暗),那么它更可能是角點,
2.檢測程序
(1)在影像中選取像素p,假設它的亮度為Ip;
(2)設定一個閾值T,比如為Ip的五分之一;
(3)以像素p為中心,選取半徑為3的圓上的16個像素點;
(4)假如選取的圓上有連續的N個點的亮度大于Ip+T或者小于Ip-T,那么像素p可以被認為是特征點(N通常取12,
即FAST-12,其他的常用的N取值為9和11,即FAST-9和FAST-11);
(5)回圈以上四步,對每個像素執行相同的操作,
補充:在FAST-12中,為提升檢測的效率,通常會增加一步預篩選,具體操作如下:
對每個像素,直接檢測鄰域圓上的第1、5、9、13個像素的亮度,只有當這4個像素中有3個同時大于Ip+T或小于
Ip-T時,當前像素才有可能是一個角點,否則就直接排除,
3.FAST-12代碼如下
#include <iostream>
#include <opencv2/opencv.hpp>
class FastKeyPointDec{
public:
/* 功能:判斷當前像素點是否為角點;
* 輸入:arg1:Ip當前像素點的亮度值
* arg2:t為篩選閾值
* arg3:IpVec為以當前像素點為中心,半徑為3的周圍16個像素
* 輸出:true or false
* */
bool isKeyPoint(double Ip,double T,std::vector<double>IpVec){
assert(IpVec.size()==16);
int n=0; //統計特征點數量
//assert(Ip>=T);
//預篩選:1 5 9 13四個點至少有三個同時滿足條件可進行下一步
int a1=IpVec[0]>Ip+T || IpVec[0]<Ip-T;
int a2=IpVec[4]>Ip+T || IpVec[4]<Ip-T;
int a3=IpVec[8]>Ip+T || IpVec[8]<Ip-T;
int a4=IpVec[12]>Ip+T || IpVec[12]<Ip-T;
if(a1+a2+a3+a4<=2){
return false;
}
for(size_t i=0;i<16;i++){
double temp=IpVec[i];
if(temp>Ip+T||temp<Ip-T){
n++;
}
}
if(n>=12){
return true;
}else{
return false;
}
}
/* 功能:對一幅影像進行角點檢測
* 輸入:arg1:輸入檢測的影像
* arg2:角點坐標
* arg3:閾值
* 輸出:角點檢測的結果
* */
void fastDectKey(const cv::Mat srcImg,std::vector<cv::Point>&keyPoint,double T){
assert(!srcImg.empty());
cv::Mat img;
int row=srcImg.rows;
int col=srcImg.cols;
std::vector<double>ipVec(0);
cv::cvtColor(srcImg,img,cv::COLOR_BGR2GRAY);
//assert(img.channels()==1);
for(int i=3;i<row-3;i++){
for(int j=3;j<col-3;j++){
double ipval=img.at<uchar>(i,j);
ipVec.push_back(img.at<uchar>(i-3,j));ipVec.push_back(img.at<uchar>(i-3,j+1)); //1,2
ipVec.push_back(img.at<uchar>(i-2,j+2)); //3
ipVec.push_back(img.at<uchar>(i-1,j+3));ipVec.push_back(img.at<uchar>(i,j+3));ipVec.push_back(img.at<uchar>(i+1,j+3));//4,5,6
ipVec.push_back(img.at<uchar>(i+2,j+2)); //7
ipVec.push_back(img.at<uchar>(i+3,j+1));ipVec.push_back(img.at<uchar>(i+3,j));ipVec.push_back(img.at<uchar>(i+3,j-1));//8,9,10
ipVec.push_back(img.at<uchar>(i+2,j-2)); //11
ipVec.push_back(img.at<uchar>(i+1,j-3));ipVec.push_back(img.at<uchar>(i,j-3));ipVec.push_back(img.at<uchar>(i-1,j-3));//12,13,14
ipVec.push_back(img.at<uchar>(i-2,j-2)); //15
ipVec.push_back(img.at<uchar>(i-3,j-2)); //16
if(ipVec.size()==16){
if(isKeyPoint(ipval,T,ipVec)){
keyPoint.push_back(cv::Point(j,i));
cv::circle(srcImg,cv::Point(j,i),2,cv::Scalar(255,255,0),1,cv::LINE_8);
}
ipVec.clear();
}
}
}
cv::imshow("res-key",srcImg);
}
};
int main() {
std::cout << "Hello, World!" << std::endl;
cv::Mat src=cv::imread("../1.png");
if(src.empty()){
std::cout<<"no image\n";
}
FastKeyPointDec fast;
std::vector<cv::Point>pt;
//cv::flip(src,src,1);
fast.fastDectKey(src,pt,30);
cv::imshow("src",src);
cv::waitKey(0);
return 0;
}
檢測效果如下

三、總結
觀察FAST-12的檢測結果,影像中大多亮度變化明顯的角點都有被檢測出來,但是單純的論特征點檢測來說,效果
不甚理想,其原因大概有以下三點:
(1)FAST演算法只是比較影像亮度的大小,所以亮度變化明顯的容易被檢測出來,而在一些亮度變化緩慢的地方的
特征點容易被忽略,因此可以在預處理時增加一些邊緣銳化等一些操作,增加一下影像的對比度,可以較好的提升檢測效果,
(2)篩選閾值選取的不夠合理;
(3)檢測的影像不夠理想,
另外,在FAST關鍵點檢測完畢后,還需要使用非極大值抑制法再進行一次篩選,以避免特征點集中的問題,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/423603.html
標籤:AI
上一篇:Qt+OpenCV聯合開發(二十九)--實時人臉檢測案例
下一篇:線性回歸的基本概念以及正規方程
