本博客內(nèi)容來(lái)源于網(wǎng)絡(luò)以及其他書(shū)籍茵臭,結(jié)合自己學(xué)習(xí)的心得進(jìn)行重編輯疫诽,因?yàn)榭戳撕芏辔恼虏槐阋灰粯?biāo)注引用,如圖片文字等侵權(quán)旦委,請(qǐng)告知?jiǎng)h除踊沸。
傳統(tǒng)2D計(jì)算機(jī)視覺(jué)學(xué)習(xí)筆記目錄------->傳送門(mén)
傳統(tǒng)3D計(jì)算機(jī)視覺(jué)學(xué)習(xí)筆記目錄------->傳送門(mén)
前言
休息了一天,雨天去了一次頤和園社证,不幸逼龟,我感冒了。所以追葡,如果本文有任何常識(shí)性問(wèn)題腺律,請(qǐng)不要懷疑作者的知識(shí)水平,而是腦子有點(diǎn)燒糊涂了宜肉。前面我們描述完了sift以及surf算法匀钧,本片我們描述一下orb特征檢測(cè)算法。
今天一看谬返,竟然已經(jīng)寫(xiě)了15篇文章了之斯,也為自己的堅(jiān)持點(diǎn)個(gè)贊 ~ (≧▽≦)/ ~ 。的的確確這段時(shí)間遣铝,對(duì)一些算法的理解也有了更深的層次佑刷,再接再厲莉擒,今晚獎(jiǎng)勵(lì)給我家貓獎(jiǎng)勵(lì)一罐小魚(yú)干。
ORB簡(jiǎn)介
ORB 全稱(chēng):Oriented FAST and Rotated BRIEF瘫絮,是一種快速特征點(diǎn)提取和描述的算法涨冀,發(fā)布于“ORB:An Efficient Alternative to SIFT or SURF” 論文中。從名字中麦萤,我們可以看出是由兩部分構(gòu)成鹿鳖,Oriented FAST 和 Rotated BRIEF,這也以最簡(jiǎn)單的語(yǔ)言描述了ORB算法壮莹。ORB算法分為兩部分翅帜,分別是特征點(diǎn)提取和特征點(diǎn)描述。特征提取是由FAST算法(前面已經(jīng)學(xué)過(guò))發(fā)展來(lái)的命满,特征點(diǎn)描述是根據(jù)BRIEF特征描述算法改進(jìn)的涝滴。
ORB算法最大的特點(diǎn)就是計(jì)算速度快,計(jì)算時(shí)間大概只有SIFT的1%周荐,SURF的10%狭莱,這主要是因?yàn)槭褂昧薋AST來(lái)加速了特征點(diǎn)的提取。再次是使用BRIEF算法計(jì)算描述子概作,該描述子特有的2進(jìn)制串的表現(xiàn)形式不僅節(jié)約了存儲(chǔ)空間腋妙,而且大大縮短了匹配的時(shí)間。
當(dāng)然ORB算法也有一些缺點(diǎn)讯榕,比如尺度變換的應(yīng)對(duì)能力比較低骤素。接下來(lái)我們來(lái)看ORB的流程,來(lái)分析一下ORB特征提取的優(yōu)缺點(diǎn)愚屁。
ORB 算法流程
1. 關(guān)鍵點(diǎn)提取
有關(guān)FAST算法济竹,可以跳轉(zhuǎn)去看另一篇來(lái)詳細(xì)描述FAST特征點(diǎn)的筆記:FAST角點(diǎn)學(xué)習(xí)筆記中查看。本節(jié)主要描述ORB算法中對(duì)FAST算法的改進(jìn)霎槐。
ORB對(duì)FAST的改進(jìn)或者拓展送浊,主要是為其增加了其尺度不變性以及旋轉(zhuǎn)不變性。接下里來(lái)看一看怎么實(shí)現(xiàn)的丘跌。
1. 提取FAST特征點(diǎn)
通過(guò)FAST算法提取出FAST特征點(diǎn)袭景,過(guò)程不在詳細(xì)描述,這樣我們就找到了一張圖片的基本的關(guān)鍵點(diǎn)闭树。
2. 建立金字塔
ORB實(shí)現(xiàn)尺度不變性耸棒,也是通過(guò)圖像金字塔來(lái)實(shí)現(xiàn)的。ORB論文本身并沒(méi)有解決尺度不變性报辱,而是在opencv實(shí)現(xiàn)中添加了這部分与殃,具體做法為設(shè)置一個(gè)比例因子scale(opencv默認(rèn)取1.2)和金字塔的層數(shù)n(通常取8)。將原圖像按比例因子縮小成n幅圖像》郏縮放后的圖像為:I’= I / scale^k (k=1,2,…, n)米奸。n幅不同比例的圖像提取特征點(diǎn)總和作為這幅圖像的FAST特征點(diǎn)。
當(dāng)然可以通過(guò)采用不同的高斯核進(jìn)行高斯模糊來(lái)建立金字塔衣屏,但是時(shí)間成本就很高了躏升。
3. 定義特征點(diǎn)方向
ORB實(shí)現(xiàn)旋轉(zhuǎn)不變性辩棒,也是通過(guò)確定一個(gè)特征點(diǎn)的方向來(lái)實(shí)現(xiàn)的狼忱,我們來(lái)看看ORB是怎么來(lái)確定特征點(diǎn)的方向的?
ORB的論文中提出了一種利用灰度質(zhì)心法來(lái)解決這個(gè)問(wèn)題一睁,通過(guò)計(jì)算一個(gè)矩來(lái)計(jì)算特征點(diǎn)以r為半徑范圍內(nèi)的質(zhì)心钻弄,特征點(diǎn)坐標(biāo)到質(zhì)心形成一個(gè)向量作為該特征點(diǎn)的方向。我們來(lái)看看具體怎么實(shí)現(xiàn)灰度質(zhì)心法者吁。
一個(gè)圖像塊(比如5x5的圖像塊中)窘俺,對(duì)應(yīng)的2x2的矩的元素表達(dá)為:x,y分別為坐標(biāo)值复凳,I(x瘤泪,y)為像素值
而該圖像窗口的質(zhì)心就是:其實(shí)灰度的質(zhì)心就是對(duì)所有的位置進(jìn)行加權(quán),權(quán)重就是像素值在整個(gè)圖像中像素值之和的比例育八。
那么特征點(diǎn)與質(zhì)心的夾角定義為FAST特征點(diǎn)的方向:也就有了特征點(diǎn)的方向对途,繼而實(shí)現(xiàn)旋轉(zhuǎn)不變性。
通過(guò)上述步驟我們找到了所有的特征點(diǎn)髓棋,并計(jì)算出了特征點(diǎn)的方向实檀,下面就看一下怎么描述這些特征點(diǎn)。
2. 關(guān)鍵點(diǎn)描述
ORB選擇了BRIEF作為特征描述方法按声,并對(duì)其進(jìn)行改進(jìn)使其加上旋轉(zhuǎn)不變性并增加其可區(qū)分性膳犹,首先我們先看看BRIEF描述子。
-
BRIEF描述子
BRIEF算法計(jì)算出來(lái)的是一個(gè)二進(jìn)制串的特征描述符签则。它是在每一個(gè)特征點(diǎn)的鄰域內(nèi)须床,選擇n對(duì)像素點(diǎn)pi、qi(i=1,2,…,n)渐裂。然后比較每個(gè)點(diǎn)對(duì)的灰度值的大小豺旬。如果I(pi)> I(qi),則生成二進(jìn)制串中的1芯义,否則為0哈垢。所有的點(diǎn)對(duì)都進(jìn)行比較,則生成長(zhǎng)度為n的二進(jìn)制串扛拨。一般n取128耘分、256或512,通常取256。
為了增強(qiáng)抗噪性求泰,一般會(huì)先對(duì)圖像進(jìn)行高斯平滑央渣。ORB算子采用5x5的子窗口進(jìn)行平滑。
那么這n個(gè)點(diǎn)對(duì)如何選取呢?
在點(diǎn)周?chē)x取點(diǎn)對(duì)(p,q)的方法有以下5種:
- 在圖像塊內(nèi)平均采樣渴频;
- p和q都符合(0,S2/25)的高斯分布芽丹;
- p符合(0,S2/25)的高斯分布,而q符合(0,S2/100)的高斯分布卜朗;
- 在空間量化極坐標(biāo)下的離散位置隨機(jī)采樣拔第;
- 把p固定為(0,0),q在周?chē)骄蓸印?/li>
BRIEF作者采用的是第二種场钉。而ORB作者沒(méi)有選擇以上任意方式蚊俺,而是一種新的方式,我們?cè)谙旅嬖僬f(shuō)逛万。
BRIEF流程簡(jiǎn)單實(shí)時(shí)性較好泳猬,論文中生成512個(gè)描述子用時(shí)8.18ms,并且其描述子是二進(jìn)制碼宇植,其匹配也比較快得封。但是,當(dāng)BRIEF對(duì)于旋轉(zhuǎn)過(guò)大時(shí)指郁,比如超過(guò)30度時(shí)忙上,匹配正確率迅速下降直到45度時(shí)為0。所以需要增加其描述子的旋轉(zhuǎn)不變性坡氯。
-
BRIEF算法改進(jìn)
在描述基礎(chǔ)BRIEF算法時(shí)晨横,我們提出了兩個(gè)問(wèn)題,一個(gè)是增加其旋轉(zhuǎn)不變性箫柳,一個(gè)是選點(diǎn)方式手形。
-
steered BRIEF 增加其旋轉(zhuǎn)不變性
steered BRIEF加入了旋轉(zhuǎn)不變性罢防,但同時(shí)特征描述量的可區(qū)分行就下降了,所以就有了ORB作者提出的rBRIEF艘虎。
-
rBRIEF 增加其可區(qū)分性
我們?cè)谏线呎f(shuō)過(guò)ORB沒(méi)有使用BRIEF 5種選取點(diǎn)對(duì)方法中的任意一種,那么ORB用的是什么方式咒吐?
ORB使用統(tǒng)計(jì)學(xué)習(xí)的方法來(lái)重新選擇點(diǎn)對(duì)集合野建,目的是增大其特征描述量的可區(qū)分行属划。這里我們先不解釋其具體的實(shí)驗(yàn)流程(主要是我還沒(méi)有完全理解),但是通過(guò)其實(shí)驗(yàn)候生,選出來(lái)的點(diǎn)對(duì)對(duì)特征點(diǎn)描述的區(qū)分度變高了同眯。
至此ORB算法計(jì)算完畢。
OpenCV ORB特征效果展示[代碼]
#include <opencv2/opencv.hpp>
#include <iostream>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/features2d/features2d.hpp>
void extracte_orb(cv::Mat input,std::vector<cv::KeyPoint> &keypoint,cv::Mat &descriptor){
cv::Ptr<cv::ORB> f2d = cv::ORB::create(500);
f2d->detect(input,keypoint);
cv::Mat image_with_kp;
f2d->compute(input,keypoint,descriptor);
cv::drawKeypoints(input, keypoint, image_with_kp, cv::Scalar::all(-1),cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
cv::imwrite("orb"+std::to_string(random())+".png",image_with_kp);
}
void match_two_image(cv::Mat image1,cv::Mat image2, std::vector<cv::KeyPoint> keypoint1,std::vector<cv::KeyPoint> keypoint2,cv::Mat descriptor1,cv::Mat descriptor2){
cv::BFMatcher matcher(cv::NORM_HAMMING);
std::vector<cv::DMatch> matches;
matcher.match(descriptor1,descriptor2, matches);
cv::Mat good_matches_image;
cv::drawMatches(image1, keypoint1, image2, keypoint2,
matches, good_matches_image, cv::Scalar::all(-1), cv::Scalar::all(-1),
std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
cv::imwrite("good_matches_image.png",good_matches_image);
{
std::vector <cv::KeyPoint> RAN_KP1, RAN_KP2;
std::vector<cv::Point2f> keypoints1, keypoints2;
for (int i = 0; i < matches.size(); i++) {
keypoints1.push_back(keypoint1[matches[i].queryIdx].pt);
keypoints2.push_back(keypoint2[matches[i].trainIdx].pt);
RAN_KP1.push_back(keypoint1[matches[i].queryIdx]);
RAN_KP2.push_back(keypoint2[matches[i].trainIdx]);
}
std::vector<uchar> RansacStatus;
cv::findFundamentalMat(keypoints1, keypoints2, RansacStatus, cv::FM_RANSAC);
std::vector <cv::KeyPoint> ransac_keypoints1, ransac_keypoints2;
std::vector <cv::DMatch> ransac_matches;
int index = 0;
for (size_t i = 0; i < matches.size(); i++)
{
if (RansacStatus[i] != 0)
{
ransac_keypoints1.push_back(RAN_KP1[i]);
ransac_keypoints2.push_back(RAN_KP2[i]);
matches[i].queryIdx = index;
matches[i].trainIdx = index;
ransac_matches.push_back(matches[i]);
index++;
}
}
cv::Mat after_ransac_sift_match;
cv::drawMatches(image1, ransac_keypoints1, image2, ransac_keypoints2,
ransac_matches, after_ransac_sift_match, cv::Scalar::all(-1), cv::Scalar::all(-1),
std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
cv::imwrite("after_ransac_orb_match.png",after_ransac_sift_match);
}
}
int main(int argc, char *argv[])
{
cv::Mat image1 = cv::imread(argv[1]);
cv::Mat image2 = cv::imread(argv[2]);
std::vector<cv::KeyPoint> keypoint1,keypoint2;
cv::Mat descriptor1, descriptor2;
extracte_orb(image1,keypoint1,descriptor1);
extracte_orb(image2,keypoint2,descriptor2);
match_two_image(image1,image2,keypoint1,keypoint2,descriptor1,descriptor2);
return 0;
}
因?yàn)閛rb難以應(yīng)對(duì)我們類(lèi)似SIFT或surf那么大的仿射變換唯鸭,所以不得不換了仿射變換小的照片
原圖1 orb識(shí)別效果 | 原圖2 orb識(shí)別效果 |
---|---|
初步匹配效果 | ransac后匹配效果 |
總結(jié)
總體來(lái)說(shuō)ORB在上述實(shí)驗(yàn)實(shí)例中的效果還是很好的须蜗。我們已經(jīng)講完SIFT,SURF還有ORB目溉,我們來(lái)對(duì)比一下這三個(gè)算法明肮。
計(jì)算速度: ORB>>SURF>>SIFT(各差一個(gè)量級(jí))
旋轉(zhuǎn)魯棒性: SURF>ORB~SIFT(~表示差不多)
模糊魯棒性: SURF>ORB~SIFT
尺度變換魯棒性: SURF>SIFT>ORB(ORB尺度變換性很弱)
在日常應(yīng)用中,有SURF基本就不用考慮SIFT停做,SURF基本就是SIFT的全面升級(jí)版晤愧,當(dāng)然也有其他SIFT的改進(jìn)版比如Affine SIFT的效果就要比SUFR要好更多大莫,但是計(jì)算時(shí)間也有延長(zhǎng)蛉腌,而ORB的強(qiáng)點(diǎn)在于計(jì)算時(shí)間。ORB主要還是在VSLAM中應(yīng)用較多只厘,場(chǎng)景變化不明顯烙丛,但是需要高速的計(jì)算時(shí)間,這正好符合ORB羔味。
重要的事情說(shuō)三遍:
如果我的文章對(duì)您有所幫助,那就點(diǎn)贊加個(gè)關(guān)注唄 ( * ^ __ ^ * )
如果我的文章對(duì)您有所幫助赋元,那就點(diǎn)贊加個(gè)關(guān)注唄 ( * ^ __ ^ * )
如果我的文章對(duì)您有所幫助忘蟹,那就點(diǎn)贊加個(gè)關(guān)注唄 ( * ^ __ ^ * )
傳統(tǒng)2D計(jì)算機(jī)視覺(jué)學(xué)習(xí)筆記目錄------->傳送門(mén)
傳統(tǒng)3D計(jì)算機(jī)視覺(jué)學(xué)習(xí)筆記目錄------->傳送門(mén)
任何人或團(tuán)體、機(jī)構(gòu)全部轉(zhuǎn)載或者部分轉(zhuǎn)載搁凸、摘錄媚值,請(qǐng)保留本博客鏈接或標(biāo)注來(lái)源。博客地址:開(kāi)飛機(jī)的喬巴
作者簡(jiǎn)介:開(kāi)飛機(jī)的喬巴(WeChat:zhangzheng-thu)护糖,現(xiàn)主要從事機(jī)器人抓取視覺(jué)系統(tǒng)以及三維重建等3D視覺(jué)相關(guān)方面褥芒,另外對(duì)slam以及深度學(xué)習(xí)技術(shù)也頗感興趣,歡迎加我微信或留言交流相關(guān)工作嫡良。