學習OpenCV關注微信公眾號【OpenCV學堂】
一:介紹
我們知道SIFT算法通常通過對每個關鍵點生成128個特征向量作為描述子、SURF算法通常對關鍵點生成最少64個特征向量作為描述子。但是對于圖像來說創建上千或者上萬個這樣的描述子內存開銷比較大,運行速度受到嚴重影響。特別對嵌入式設備與一定設備來說,內存限制尤為明顯,而且匹配的時候計算也比較耗時。
但是實際上這些特征數據OpenCV在匹配的時候并沒有完全利用上,而是通過PCA、LDA等方法對它進行壓縮,或者是LSH(局部敏感哈希)方法把這些特征描述子壓縮從浮點數轉換為二進制字符串,然后通過漢明距離(HammingDistance)進行比較。這樣就可以通過簡單的異或操作(OXR)與位值計算來加速實現對象特征匹配,對于SSE指令集的CPU這種方法可以大大加速。但是這種方法仍然需要首先計算描述子,然后使用LSH方法進行壓縮,無法避免過度的內存開銷。
而Brief方法可以直接通過關鍵點生成二進制字符串,跳過了中間描述子生成步驟,這樣就大大減低了內存要求與計算開銷。Brief方法主要思路是對每個關鍵點附件選擇若干個像素點,將這些像素點的像素值組合成二進制字符串,然后使用該字符串作為該關鍵點的描述子。
此方法是在2010年提出來的。結果實驗測試在選取256個點甚至128個點情況下對沒有旋轉對象識別率非常高而且速度比SURF還快。但是當對象有旋轉時候由于Brief不能很好的支持旋轉不變性識別,特別是當旋轉角度超過30度以上,準確率會快速下降。
二:Brief描述子生成步驟
Brief描述子生成首先需要產生足夠多的隨機點對,然后根據隨機點對坐標得到對應像素值,對所有點對進行二進制字符串拼接,拼接完成即生成了描述子。
第一步:選擇關鍵點周圍SxS大小正方形圖像區塊,進行高斯模糊。這樣做的原因是需要降低圖像隨機噪聲,OpenCV在完成Brief的時候考慮到效率問題并沒有采用高斯模糊而是采用了基于積分圖的盒子模糊方法。
第二步:選擇n個像素點對,其中n的取值常見為256、此外還可以是128、512。每個點對比較像素值輸出如下。

對N個點對完成操作最終得到了二進制字符串,表達如下:

三:方法
高斯模糊比較
通過實驗對比高斯sigma參數在0~3之間準確率比較高,窗口大小取值在9x9取得比較好的模糊去噪效果。論文中實驗結果圖示如下:

隨機點生成方法比較
對于隨機生成點對的方法,論文中給出了五種隨機方法與實驗結果比較,五種方法描述如下:

圖示如下:

對圖像五個幾何采樣完成測試結果如下:

其中第二種方法比其他四種稍微有點優勢,而最不好的方法則是第五種方法。
四:OpenCV中Biref描述子演示
#include <opencv2/opencv.hpp>#include <opencv2/xfeatures2d.hpp>#include <iostream>using namespace cv;using namespace std;using namespace cv::xfeatures2d;int main(int argc, char** argv) { Mat img1 = imread("D:/tree.png", IMREAD_GRAYSCALE); Mat img2 = imread("D:/tree_in_scene.png", IMREAD_GRAYSCALE); Mat src = imread("D:/gloomyfish/14.png", IMREAD_GRAYSCALE); Mat src1 = imread("D:/gloomyfish/14.png"); if (!img1.data || !img2.data) { PRintf("could not load images.../n"); return -1; } imshow("box", img1); imshow("scene", img2); auto detector = FastFeatureDetector::create(); vector<KeyPoint> keypoints_obj; vector<KeyPoint> keypoints_scene; detector->detect(img1, keypoints_obj, Mat()); detector->detect(img2, keypoints_scene, Mat()); auto descriptor = BriefDescriptorExtractor::create(); Mat descriptor_obj, descriptor_scene; descriptor->compute(img1, keypoints_obj, descriptor_obj); descriptor->compute(img2, keypoints_scene, descriptor_scene); BFMatcher matcher(NORM_L2); vector<DMatch> matches; matcher.match(descriptor_obj, descriptor_scene, matches); Mat resultImg; drawMatches(img1, keypoints_obj, img2, keypoints_scene, matches, resultImg); imshow("Brief Descriptor Match Result", resultImg); waitKey(0); return 0;}運行結果
新聞熱點
疑難解答