OpenCV3 使用GFTTDetector進行Shift-Tomasi角點檢測、特征提取以及特征匹配


原創:轉載請備注https://www.cnblogs.com/soulfly/articles/11283855.html
前言
如果使用Shift-Tomasi檢測出的角點進行特征匹配?這個是本文的重點
作為一名OpenCV小白,在篩選特征提取方法時,發現Shift-Tomasi角點檢測算法不錯,通過調節參數能夠實現交通牌邊沿角點和白線繪制角點的提取,如下圖示
 
第一步 初步探索:角點檢測接口以及參數說明
在網上搜索了不少,大都是使用OpenCV的函數goodFeaturesToTrack實現,定義如下
void goodFeaturesToTrack( InputArray image, OutputArray corners,
int maxCorners, double qualityLevel, double minDistance,
InputArray mask = noArray(), int blockSize = 3,
bool useHarrisDetector = false, double k = 0.04 );
該函數使用的使用方法不是本文的講解重點,就不再舉例詳細贅述,僅說明一下參數含義:
第一個參數image:8位或32位單通道灰度圖像;
第二個參數corners:位置點向量,保存的是檢測到的角點的坐標;
第三個參數maxCorners:定義可以檢測到的角點的數量的最大值;
第四個參數qualityLevel:檢測到的角點的質量等級,角點特征值小於qualityLevel*最大特征值的點將被舍棄;
第五個參數minDistance:兩個角點間最小間距,以像素為單位;
第六個參數mask:指定檢測區域,若檢測整幅圖像,mask置為空Mat();
第七個參數blockSize:計算協方差矩陣時窗口大小;
第八個參數useHarrisDetector:是否使用Harris角點檢測,為false,則使用Shi-Tomasi算子;
第九個參數k:留給Harris角點檢測算子用的中間參數,一般取經驗值0.04~0.06。第八個參數為false時,該參數不起作用;
檢測效果如下圖所示:
可見牌子的邊沿角點和繪制角點基本全部檢測出來了,效果還不錯,主要參數取值如下:
int maxCornerNumber = 300;
double qualityLevel = 0.01;
double minDistance = 10;
int blockSize = 10;
 
第二步 大海撈針:查找計算特征點(關鍵點:KeyPoint)的接口
這一步真是費了好多時間才找到相關接口,先是從網上查找相關資料,但是無一例外的全是講解接口goodFeaturesToTrack和Shi-Tomasi算法原理,無意中發現大神“冠軍的試煉”的博客:
OpenCV探索之路(二十三):特征檢測和特征匹配方法匯總,
連接: https://www.cnblogs.com/skyfsm/p/7401523.html 中提到Harris角點特征匹配相關代碼
但是這個是OpenCV2的實現方法,在OpenCV3中找不到。
發現這一個后,我確定了一個問題,即OpenCV3中肯定有相關的實現接口,於是采用暴力解決
,即在源碼中全工程搜索“goodFeaturesToTrack”,終於找到的實現接口GFTTDetector:
該接口簡介:使用goodFeaturesToTrack函數實現特征檢測的封裝類。
使用該接口就能直接計算出特征點,可用於計算特征描述符,進而用於匹配。
 
第三步 臨門一腳:查找特征匹配的接口
本以為找到GFTTDetector類就大功告成,沒想到,調用compute計算描述符時崩潰了。。。
這時回看大神“冠軍的試煉”的博客,就輕松的找到了答案:換一個計算描述符的接口就行了,哈哈
 
源碼如下:
int main(int argc, char** argv)
{
Mat leftImage1 = imread("D:/branch/openCV330/OpenCVTest/image/38-1-190504094217209-003481.jpg", cv::IMREAD_GRAYSCALE);
Mat rightImage2 = imread("D:/branch/openCV330/OpenCVTest/image/38-2-190504094217209-003481.jpg", cv::IMREAD_GRAYSCALE);
if (!leftImage1.data || !rightImage2.data)
{
return 0;
}
equalizeHist(leftImage1, leftImage1);
equalizeHist(rightImage2, rightImage2);
cv::Rect imageRect(0, 0, leftImage1.cols, leftImage1.rows);
cv::Rect leftRoiRect = cv::Rect(2300, 300, 1000, 1000)&imageRect;
cv::Rect rightRoiRect = cv::Rect(2200, 300, 1000, 1000)&imageRect;
Mat srcImage1 = leftImage1(leftRoiRect);
Mat srcImage2 = rightImage2(rightRoiRect);
 
// 定義用到的變量和類 [7/25/2019 wufuzheng]
int minHessian = 400;
cv::Ptr<ORB > orb = ORB::create();
orb->setScaleFactor(1.4);
orb->setNLevels(8);
orb->setScoreType(ORB::kBytes);
std::vector<KeyPoint> Keypoints1;
std::vector<KeyPoint> Keypoints2;
Mat descriptors1, descriptors2;
// 檢測特征點 [7/25/2019 wufuzheng]
orb->detect(srcImage1, Keypoints1);
orb->detect(srcImage2, Keypoints2);
// 計算描述符 [7/26/2019 wufuzheng]
orb->compute(srcImage1, Keypoints1, descriptors1);
orb->compute(srcImage2, Keypoints2, descriptors2);
std::vector<DMatch> matches;
BFMatcher bfMatcher(NORM_HAMMING, true);
bfMatcher.match(descriptors1, descriptors2, matches);
// 匹配對篩選
double min_dist = 1000, max_dist = 0;
// 找出所有匹配之間的最大值和最小值
for (int i = 0; i < matches.size(); i++)
{
double dist = matches[i].distance;
if (dist < min_dist) min_dist = dist;
if (dist > max_dist) max_dist = dist;
}
// 當描述子之間的匹配不大於2倍的最小距離時,即認為該匹配是一個錯誤的匹配。
// 但有時描述子之間的最小距離非常小,可以設置一個經驗值作為下限
std::vector<DMatch> goodMatches;
for (int i = 0; i < matches.size(); i++)
{
if (matches[i].distance <= max(2 * min_dist, 30.0))
goodMatches.push_back(matches[i]);
}
// 轉為興趣區坐標 [7/29/2019 wufuzheng]
//Geometries::Coordinate tmpRoiCoord(srcCoord.x - matchRoiRect.x, srcCoord.y - matchRoiRect.y, 0);
 
 
//繪制出匹配到的關鍵點
//Mat img_matches;
cv::drawMatches(srcImage1, Keypoints1, srcImage2, Keypoints2, goodMatches, img_matches);
cv::imshow("good match", img_matches);
//waitKey(0);
return 0;
}
匹配效果圖如下:
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM