日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

ORB + OPENCV

發(fā)布時(shí)間:2023/11/27 生活经验 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ORB + OPENCV 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、介紹

假如有兩張人物圖片,我們的目標(biāo)是要確認(rèn)這兩張圖片中的人物是否是同一個(gè)人。如果人來判斷,這太簡單了。但是讓計(jì)算機(jī)來完成這個(gè)功能就困難重重。一種可行的方法是:

?

  1. 分別找出兩張圖片中的特征點(diǎn)
  2. 描述這些特征點(diǎn)的屬性,
  3. 比較這兩張圖片的特征點(diǎn)的屬性。如果有足夠多的特征點(diǎn)具有相同的屬性,那么就可以認(rèn)為兩張圖片中的人物就是同一個(gè)人。

?

ORB(Oriented FAST and Rotated BRIEF)就是一種特征提取并描述的方法。ORB是由Ethan Rublee, Vincent Rabaud, Kurt Konolige以及Gary R.Bradski在2011年提出,論文名稱為"ORB:An Efficient Alternative to SIFTor SURF",(http://www.willowgarage.com/sites/default/files/orb_final.pdf)。

ORB分兩部分,即特征點(diǎn)提取和特征點(diǎn)描述。特征提取是由FAST(Features from Accelerated Segment Test)算法發(fā)展來的,特征點(diǎn)描述是根據(jù)BRIEF(Binary Robust Independent Elementary Features)特征描述算法改進(jìn)的。ORB特征是將FAST特征點(diǎn)的檢測(cè)方法與BRIEF特征描述子結(jié)合起來,并在它們?cè)瓉淼幕A(chǔ)上做了改進(jìn)與優(yōu)化。據(jù)說ORB算法的速度是sift的100倍,是surf的10倍。

二、Oriented FAST(oFast)特征點(diǎn)的提取

oFast就是在使用FAST提取特征點(diǎn)之后,給其定義一個(gè)該特征點(diǎn)的放向,并以此來實(shí)現(xiàn)該特征點(diǎn)的旋轉(zhuǎn)不變形。

2.1、粗提取

圖像的特征點(diǎn)可以簡單的理解為圖像中比較顯著顯著的點(diǎn),如輪廓點(diǎn),較暗區(qū)域中的亮點(diǎn),較亮區(qū)域中的暗點(diǎn)等。

FAST的核心思想是找出那些卓爾不群的點(diǎn)。即拿一個(gè)點(diǎn)跟它周圍的點(diǎn)比較,如果它和其中大部分的點(diǎn)都不一樣,就人物它是一個(gè)特征點(diǎn)。

如上圖,假設(shè)圖像中的一點(diǎn)P,及其一個(gè)鄰域。右半拉是放大的圖,每個(gè)小方格代表一個(gè)像素,方格內(nèi)的顏色只是為了便于區(qū)分,不代表該像素點(diǎn)的顏色。判斷該點(diǎn)是不是特征點(diǎn)的方法是,以P為圓心畫一個(gè)半徑為3pixel的圓(周長為16pixel)。圓周上如果有連續(xù)n個(gè)像素點(diǎn)的灰度值比P點(diǎn)的灰度值大或者小(需事先設(shè)定一個(gè)閾值T),則認(rèn)為P為特征點(diǎn)。一般n設(shè)置為12。

為了加快特征點(diǎn)的提取,快速排除非特征點(diǎn),首先檢測(cè)1、9、5、13位置上的灰度值,如果P是特征點(diǎn),那么這四個(gè)位置上有3個(gè)或3個(gè)以上的的像素值都大于或者小于P點(diǎn)的灰度值。如果不滿足,則直接排除此點(diǎn)。

2.2、使用ID3決策樹,將特征點(diǎn)圓周上的16個(gè)像素輸入決策樹中,以此來篩選出最優(yōu)的FAST特征點(diǎn)。

2.3、使用非極大值抑制算法去除臨近位置多個(gè)特征點(diǎn)的。具體:為每一個(gè)特征點(diǎn)計(jì)算出其響應(yīng)大小(特征點(diǎn)P和其周圍16個(gè)特征點(diǎn)偏差的絕對(duì)值和)。在比較臨近的特征點(diǎn)中,保留響應(yīng)值較大的特征點(diǎn),刪除其余的特征點(diǎn)。

2.4、特征點(diǎn)的尺度不變性

建立金字塔,來實(shí)現(xiàn)特征點(diǎn)的多尺度不變性。設(shè)置一個(gè)比例因子scaleFactor(opencv默認(rèn)為1.2)和金字塔的層數(shù)nlevels(pencv默認(rèn)為8)。將原圖像按比例因子縮小成nlevels幅圖像??s放后的圖像為:I’= I/scaleFactork(k=1,2,…, nlevels)。nlevels幅不同比例的圖像提取特征點(diǎn)總和作為這幅圖像的oFAST特征點(diǎn)。

2.5、特征點(diǎn)的旋轉(zhuǎn)不變形

oFast用矩(moment)法來確定FAST特征點(diǎn)的方向。即計(jì)算特征點(diǎn)以r為半徑范圍內(nèi)的質(zhì)心,特征點(diǎn)坐標(biāo)到質(zhì)心形成一個(gè)向量作為該特征點(diǎn)的方向。矩定義如下:

三、Rotated BRIEF(rBRIEF)特征點(diǎn)的描述

3.1、BRIEF算法

BRIEF算法計(jì)算出來的是一個(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)行比較,則生成長度為n的二進(jìn)制串。一般n取128、256或512(opencv默認(rèn)為256)。

另外,為了增加特征描述符的抗噪性,算法需要先對(duì)圖像進(jìn)行高斯平滑處理。在ORB算法中,在這個(gè)地方進(jìn)行了改進(jìn),在使用高斯函數(shù)進(jìn)行平滑后又用了其他操作,使其更加的具有抗噪性。具體方法下面將會(huì)描述。

在特征點(diǎn)SxS的區(qū)域內(nèi)選取點(diǎn)對(duì)的方法,BRIEF論文中測(cè)試了5種方法:

  • 在圖像塊內(nèi)平均采樣;
  • p和q都符合(0,S2/25)的高斯分布;
  • p符合(0,S2/25)的高斯分布,而q符合(0,S2/100)的高斯分布;
  • 在空間量化極坐標(biāo)下的離散位置隨機(jī)采樣;
  • 把p固定為(0,0),q在周圍平均采樣。

?

3.2、rBRIEF算法

3.2.1、steered BRIEF(旋轉(zhuǎn)不變性改進(jìn)):

在使用oFast算法計(jì)算出的特征點(diǎn)中包括了特征點(diǎn)的方向角度。假設(shè)原始的BRIEF算法在特征點(diǎn)SxS(一般S取31)鄰域內(nèi)選取n對(duì)點(diǎn)集。

經(jīng)過旋轉(zhuǎn)角度θ旋轉(zhuǎn),得到新的點(diǎn)對(duì):

在新的點(diǎn)集位置上比較點(diǎn)對(duì)的大小形成二進(jìn)制串的描述符。這里需要注意的是,在使用oFast算法是在不同的尺度上提取的特征點(diǎn)。因此,在使用BRIEF特征描述時(shí),要將圖像轉(zhuǎn)換到相應(yīng)的尺度圖像上,然后在尺度圖像上的特征點(diǎn)處取SxS鄰域,然后選擇點(diǎn)對(duì)并旋轉(zhuǎn),得到二進(jìn)制串描述符。

3.2.2、rBRIEF-改進(jìn)特征點(diǎn)描述子的相關(guān)性

使用steeredBRIEF方法得到的特征描述子具有旋轉(zhuǎn)不變性,但是卻在另外一個(gè)性質(zhì)上不如原始的BRIEF算法,即描述符的可區(qū)分性(相關(guān)性)。為了解決描述子的可區(qū)分性和相關(guān)性的問題,ORB論文中沒有使用原始BRIEF算法中選取點(diǎn)對(duì)時(shí)的5種方法中的任意一種,而是使用統(tǒng)計(jì)學(xué)習(xí)的方法來重新選擇點(diǎn)對(duì)集合。

對(duì)每個(gè)特征點(diǎn)選取31x31領(lǐng)域,每個(gè)領(lǐng)域選擇5x5的平均灰度值代替原來單個(gè)像素值進(jìn)行比對(duì),因此可以得到N=(31-5+1)x(31-5+1) = 729個(gè)可以比對(duì)的子窗口(patch),可以使用積分圖像加快求取5x5鄰域灰度平均值的速度。一共有M = 1+2+3+...+N = 265356種點(diǎn)對(duì)組合,也就是一個(gè)長度為M的01字符串。顯然M遠(yuǎn)大于256,我們得篩選。

篩選方法如下:

?

  • 重組所有點(diǎn)以及對(duì)應(yīng)的初始二值串得到矩陣O,行數(shù)為提取得到的點(diǎn)數(shù),每行是每個(gè)點(diǎn)對(duì)應(yīng)的初始二值描述子
  • 對(duì)重組后的矩陣?O,按照每列均值與0.5的絕對(duì)差從小到大排序,得到矩陣T
  • 貪心選擇:把T中第一列放進(jìn)矩陣R(一開始為空)中,并從T中移除依次選擇T的每列,與R中所有的列進(jìn)行比較,如果相似度超過一定閾值,忽略,進(jìn)行下一列,否則放進(jìn)R中,并從T中移除重復(fù)以上過程直到選擇?256個(gè)列,這樣每個(gè)特征點(diǎn)就有256個(gè)0,1組成的描述子。如果不足256個(gè),則降低閾值直到滿足256就可,R即為最終特征描述矩陣。

?

三、特征點(diǎn)匹配

這部分是另外一個(gè)話題了。ORB算法最大的特點(diǎn)就是計(jì)算速度快 。這得益于使用FAST檢測(cè)特征點(diǎn),FAST的檢測(cè)速度正如它的名字一樣是出了名的快。再就是是使用BRIEF算法計(jì)算描述子,該描述子特有的2進(jìn)制串的表現(xiàn)形式不僅節(jié)約了存儲(chǔ)空間,而且大大縮短了匹配的時(shí)間。
例如特征點(diǎn)A、B的描述子如下。
A:10101011
B:10101010

設(shè)定一個(gè)閾值,比如80%。當(dāng)A和B的描述子的相似度大于90%時(shí),我們判斷A,B是相同的特征點(diǎn),即這2個(gè)點(diǎn)匹配成功。在這個(gè)例子中A,B只有最后一位不同,相似度為87.5%,大于80%。則A和B是匹配的。
將A和B進(jìn)行異或操作就可以輕松計(jì)算出A和B的相似度。而異或操作可以借助硬件完成,具有很高的效率,加快了匹配的速度。

四、OpenCV實(shí)驗(yàn)(OpenCV3.0以上版本,包含contrib模塊)

?

[cpp]?view plain?copy

  1. #include?<iostream>??
  2. #include?<stdio.h>??
  3. #include?<unistd.h>??
  4. #include?<stdlib.h>??
  5. #include?<string.h>??
  6. #include?<string>??
  7. #include?<dirent.h>??
  8. #include?<unistd.h>??
  9. #include?<vector>??
  10. #include?<sstream>??
  11. #include?<fstream>??
  12. #include?<sys/io.h>??
  13. #include?<sys/times.h>??
  14. #include?<iomanip>??
  15. #include?<tuple>??
  16. #include?<cstdlib>??
  17. using?namespace?std;??
  18. ??
  19. #include?"opencv2/imgproc.hpp"??
  20. #include?"opencv2/imgcodecs.hpp"??
  21. #include?"opencv2/highgui.hpp"??
  22. #include?"opencv2/stitching.hpp"??
  23. #include?"opencv2/xfeatures2d/nonfree.hpp"??
  24. using?namespace?cv;??
  25. ??
  26. #define?ENABLE_LOG??
  27. ??
  28. bool?PreapreImg(vector<Mat>?&imgs);??
  29. bool?Match(vector<cv::detail::MatchesInfo>?&pairwise_matches,???
  30. ???????????const?vector<cv::detail::ImageFeatures>?&features,??
  31. ???????????const?cv::String?matcher_type?=?"homography",???
  32. ???????????const?int?range_width?=?-1,??
  33. ???????????const?bool?try_cuda?=?false,???
  34. ???????????const?double?match_conf?=?0.3f);??
  35. void?demo();??
  36. ??
  37. int?main(int?argc,?char**?argv)??
  38. {??
  39. ????cout?<<?"#?STA?##############################"?<<?endl;??
  40. ????cout?<<?"\n"?<<?endl;??
  41. ????int64?app_start_time?=?getTickCount();??
  42. ??????
  43. ????demo();??
  44. ??????
  45. ????cout?<<?"\n"?<<?endl;??
  46. ????cout?<<?"#?END?##############################?Time:?"???
  47. ?????????<<?((getTickCount()?-?app_start_time)?/?getTickFrequency())???
  48. ?????????<<?"?sec"?<<?endl;??
  49. ????return?0;??
  50. }??
  51. ??
  52. void?demo()??
  53. {??
  54. ????vector<Mat>?imgs;???
  55. ????PreapreImg(imgs);??
  56. ??????
  57. ????//?define?feature?finder??
  58. ????Ptr<cv::detail::FeaturesFinder>?finder?=???
  59. ????cv::makePtr<cv::detail::OrbFeaturesFinder>();??
  60. ??????
  61. ????//?detect?features??
  62. ????int?num_images?=?static_cast<int>(imgs.size());??
  63. ????vector<cv::detail::ImageFeatures>?features(num_images);??
  64. ????for?(int?i?=?0;?i?<?num_images;?i++)?{??
  65. ????????(*finder)(imgs[i],?features[i]);??
  66. ????????features[i].img_idx?=?i;??
  67. #ifdef?ENABLE_LOG??
  68. ????????cout?<<?">>?features?number:?"?<<?setw(4)?<<?features[i].img_idx??
  69. ?????????????<<?setw(5)?<<?static_cast<int>(features[i].keypoints.size())??
  70. ?????????????<<?endl;??
  71. ????????Mat?tmp;??
  72. ????????cv::drawKeypoints(imgs[i],?features[i].keypoints,?tmp);??
  73. ????????stringstream?ss;??
  74. ????????ss?<<?i;??
  75. ????????cv::imwrite(("./img"?+?string(ss.str())?+?"_keypoints.jpg").c_str(),?tmp);??
  76. #endif??
  77. ????}??
  78. ????//?Frees?unused?memory?allocated?before?if?there?is?any??
  79. ????finder->collectGarbage();??
  80. ??????
  81. ????//?Pairwise?matching???
  82. ????vector<cv::detail::MatchesInfo>?pairwise_matches;??
  83. ????Match(pairwise_matches,?features);??
  84. #ifdef?ENABLE_LOG??
  85. ????????cout?<<?">>?pairwise?matches:?"???
  86. ?????????????<<?setw(5)?<<?static_cast<int>(pairwise_matches.size())??
  87. ?????????????<<?endl;??
  88. ????????cout?<<?">>?Saving?matches?graph..."?<<?endl;??
  89. ????????ofstream?f("./matchGraph.txt");??
  90. ????????vector<cv::String>?img_names;??
  91. ????????for?(int?i?=?0;?i?<?num_images;?i++)?{??
  92. ????????????stringstream?ss;?ss?<<?i;??
  93. ????????????img_names.push_back(ss.str());??
  94. ????????}??
  95. ????????f?<<?matchesGraphAsString(img_names,?pairwise_matches,?1.0f);??
  96. ????????cout?<<?">>?Saving?matches?graph?OK.?Position:?./matchGraph.txt"?<<?endl;??
  97. ??
  98. ????????Mat?tmp;??
  99. ????????cv::drawMatches(imgs[0],?features[0].keypoints,???
  100. ????????????????????????imgs[1],?features[1].keypoints,??
  101. ????????????????????????pairwise_matches[1].matches,??
  102. ????????????????????????tmp);??
  103. ????????cv::imwrite("./matches0_1.jpg",?tmp);??
  104. #endif??
  105. }??
  106. ??
  107. bool?PreapreImg(vector<Mat>?&imgs)??
  108. {??
  109. ????Mat?image0?=?imread("./0.jpg",?IMREAD_GRAYSCALE);??
  110. ????Mat?image1?=?imread("./1.jpg",?IMREAD_GRAYSCALE);??
  111. ????imgs.push_back(image0);??
  112. ????imgs.push_back(image1);??
  113. ??????
  114. ????//?Check?if?have?enough?images??
  115. ????int?num_images?=?static_cast<int>(imgs.size());??
  116. ????if?(num_images?<?2)??
  117. ????{??
  118. ????????cout?<<?">>?error.?num_images?<?2"?<<?endl;??
  119. ????????return?false;??
  120. ????}??
  121. ??????
  122. #ifdef?ENABLE_LOG??
  123. ????for?(int?i?=?0;?i?<?num_images;?i++)?{??
  124. ????????cout?<<?">>?image?"?<<?setw(2)?<<?i?<<?":?"??
  125. ?????????????<<?setw(5)?<<?imgs[i].rows??
  126. ?????????????<<?setw(5)?<<?imgs[i].cols??
  127. ?????????????<<?setw(5)?<<?imgs[i].channels()??
  128. ?????????????<<?endl;??
  129. ????}??
  130. #endif??
  131. ??
  132. ????return?true;??
  133. }??
  134. ??
  135. /************************************************?
  136. *?There?are?3?kinds?of?feature?matchers?offered?by?"matchers.hpp"?
  137. */??
  138. bool?Match(vector<cv::detail::MatchesInfo>?&pairwise_matches,???
  139. ???????????const?vector<cv::detail::ImageFeatures>?&features,??
  140. ???????????const?cv::String?matcher_type?=?"homography",???
  141. ???????????const?int?range_width?=?-1,??
  142. ???????????const?bool?try_cuda?=?false,???
  143. ???????????const?double?match_conf?=?0.3f)??
  144. {??
  145. ????Ptr<cv::detail::FeaturesMatcher>?matcher;??
  146. ????if?(matcher_type?==?"affine")???
  147. ????{??
  148. ????????bool?full_affine?=?false;??
  149. ????????int?num_matches_thresh1?=?6;??
  150. ????????matcher?=?makePtr<cv::detail::AffineBestOf2NearestMatcher>(??
  151. ????????full_affine,?try_cuda,?match_conf,?num_matches_thresh1);??
  152. ????}??
  153. ????else?if?(matcher_type?==?"homography")???
  154. ????{??
  155. ????????int?num_matches_thresh1?=?6;??
  156. ????????int?num_matches_thresh2?=?6;??
  157. ????????if?(range_width?==?-1)??
  158. ????????????matcher?=?makePtr<cv::detail::BestOf2NearestMatcher>(??
  159. ????????????try_cuda,?match_conf,?num_matches_thresh1,?num_matches_thresh2);??
  160. ????????else??
  161. ????????????matcher?=?makePtr<cv::detail::BestOf2NearestRangeMatcher>(??
  162. ????????????range_width,?try_cuda,?match_conf,?num_matches_thresh1,?num_matches_thresh2);??
  163. ????}??
  164. ??????
  165. ????(*matcher)(features,?pairwise_matches);??
  166. ????matcher->collectGarbage();??
  167. ??????
  168. ????return?true;??
  169. }??

實(shí)驗(yàn)代碼:https://code.csdn.net/guoyunfei20/orb.git

實(shí)驗(yàn)結(jié)果:

輸入圖像1:

輸入圖像2:

圖像1的ORB特征點(diǎn)位置:

圖像2的ORB特征點(diǎn)位置:

利用cv::detail::BestOf2NearestMatcher匹配算法得到的能匹配上的特征點(diǎn)(圖像0 -> 圖像1):

?

?

?

?

總結(jié)

以上是生活随笔為你收集整理的ORB + OPENCV的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。