getvalue参数计数不匹配_OpenCV开发笔记(六十八):红胖子8分钟带你使用特征点Flann最邻近差值匹配识别...
若該文為原創文章,未經允許不得轉載
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客導航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/107357296
各位讀者,知識無窮而人力有窮,要么改需求,要么找專業人士,要么自己研究
紅胖子(紅模仿)的博文大全:開發技術集合(包含Qt實用技術、樹莓派、三維、OpenCV、OpenGL、ffmpeg、OSG、單片機、軟硬結合等等)持續更新中…(點擊傳送門)
OpenCV開發專欄(點擊傳送門)
上一篇:《OpenCV開發筆記(六十七):紅胖子8分鐘帶你深入了解特征點暴力匹配(圖文并茂+淺顯易懂+程序源碼)》
下一篇:持續補充中…
前言
紅胖子,來也!
前面講解了特征點,那么匹配特征點,就是匹配兩者的相似度,相似度達到一定的閾值,則認為識別了。
考慮性能,除開暴力匹配外,還有最近鄰匹配。
Demo
最近鄰匹配(FLANN)
FlannBasedMatcher中FLANN的含義是Fast Library forApproximate Nearest Neighbors,目前最完整的(近似)最近鄰匹配。不但實現了一系列查找算法,還包含了一種自動選取最快算法的機制。
從字面意思可知它是一種近似法,算法更快但是找到的是最近鄰近似匹配,所以當我們需要找到一個相對好的匹配但是不需要最佳匹配的時候往往使用FlannBasedMatcher。
當然也可以通過調整FlannBasedMatcher的參數來提高匹配的精度或者提高算法速度,但是相應地算法速度或者算法精度會受到影響。
本篇章使用sift/surf特征點
sift特征點
尺度不變特征變換(Scale-invariant feature transform,SIFT),是用于圖像處理領域的一種描述。這種描述具有尺度不變性,可在圖像中檢測出關鍵點,是一種局部特征描述子。
surf特征點
SURF算法采用了很多方法來對每一步進行優化從而提高速度。分析顯示在結果效果相當的情況下SURF的速度是SIFT的3倍。SURF善于處理具有模糊和旋轉的圖像,但是不善于處理視角變化和光照變化。(SIFT特征是局部特征,其對旋轉、尺度縮放、亮度變化保持不變性,對視角變化、仿射變換、噪聲也保持一定程度的穩定性)。
針對圖像場景的特點,選擇不同的特征點,列出之前特征點相關的博文:
《OpenCV開發筆記(六十三):紅胖子8分鐘帶你深入了解SIFT特征點(圖文并茂+淺顯易懂+程序源碼)》
《OpenCV開發筆記(六十四):紅胖子8分鐘帶你深入了解SURF特征點(圖文并茂+淺顯易懂+程序源碼)》
《OpenCV開發筆記(六十五):紅胖子8分鐘帶你深入了解ORB特征點(圖文并茂+淺顯易懂+程序源碼)》
FlannBasedMatcher類的使用
定義
// 定義匹配器 cv::Ptr<cv::FlannBasedMatcher> pFlannBasedMatcher = cv::FlannBasedMatcher::create(); // 定義結果存放 std::vector<cv::DMatch> listDMatch; // 存儲特征點檢測器檢測特征后的描述字 cv::Mat descriptor1; cv::Mat descriptor2;
特征點提取
pFlannBasedMatcher->detectAndCompute(srcMat1, cv::Mat(), keyPoints1, descriptor1); pFlannBasedMatcher->detectAndCompute(srcMat1, cv::Mat(), keyPoints1, descriptor1);
匹配
// FlannBasedMatcher最近鄰匹配 pFlannBasedMatcher->match(descriptor1, descriptor2, listDMatch); FlannBasedMatcher相關函數原型 static Ptr<FlannBasedMatcher> create() ;
無參數
FlannBasedMatcher::match( InputArray queryDescriptors, InputArray trainDescriptors, std::vector<DMatch>& matches, InputArray mask=noArray() ) const;
- 參數一:InputArray類型的queryDescriptors,查詢描述符集,一般cv::Mat,某個特征提取的描述符。
- 參數二:InputArray類型的trainDescriptors,訓練描述符集,此處輸入的應該是沒有加入到類對象集合種的(該類有訓練的數據集合),一般cv::Mat,某個特征提取的描述符。
- 參數三:std::vector類型的matches。如果在掩碼中屏蔽了查詢描述符,則不會為此添加匹配項描述符。因此,匹配項的大小可能小于查詢描述符計數。
- 參數四:InputArray類型的mask,指定輸入查詢和訓練矩陣之間允許的匹配的掩碼描述符。
繪制匹配關系圖函數原型
void drawMatches( InputArray img1, const std::vector<KeyPoint>& keypoints1, InputArray img2, const std::vector<KeyPoint>& keypoints2, const std::vector<DMatch>& matches1to2, InputOutputArray outImg, const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1), const std::vector<char>& matchesMask=std::vector<char>(), int flags=DrawMatchesFlags::DEFAULT );
- 參數一:InputArray類型的img1,圖像1。
- 參數二:std::vector類型的keypoints1,圖像1的關鍵點。
- 參數三:InputArray類型的img2,圖像2。
- 參數四:std::vector類型的keypoints2,圖像2的關鍵點。
- 參數五:std::vector類型的matchers1to2,從第一個圖像匹配到第二個圖像,這意味著keypoints1[i]在keypoints2中有一個對應的點[matches[i]]。
- 參數六:InputOutputArray類型的outImg,為空時,默認并排繪制輸出圖像以及連接關鍵點;若不為空,則在圖像上繪制關系點。
- 參數七:Scalar類型的matcherColor,匹配顏色匹配(線和連接的關鍵點)的顏色。如果顏色為cv::Scalar::all(-1),則為隨機顏色。
- 參數八:Scalar類型的singlePointColor,顏色單個關鍵點(圓)的顏色,這意味著關鍵點沒有匹配到的則認是該顏色。
- 參數九:std::vector類型的matchersMask,確定繪制的匹配項目,若是為空,則表示全部繪制。
- 參數十:int類型的flags,查看枚舉DrawMatchesFlags,如下:
Demo
void OpenCVManager::testFlannBasedMatcher() {QString fileName1 = "21.jpg";QString fileName2 = "24.jpg";int width = 400;int height = 300;cv::Mat srcMat = cv::imread(fileName1.toStdString());cv::Mat srcMat3 = cv::imread(fileName2.toStdString());cv::resize(srcMat, srcMat, cv::Size(width, height));cv::resize(srcMat3, srcMat3, cv::Size(width, height));cv::String windowName = _windowTitle.toStdString();cvui::init(windowName);cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 2, srcMat.rows * 3),srcMat.type());cv::Ptr<cv::xfeatures2d::SIFT> _pSift = cv::xfeatures2d::SiftFeatureDetector::create();cv::Ptr<cv::xfeatures2d::SURF> _pSurf = cv::xfeatures2d::SurfFeatureDetector::create();cv::Ptr<cv::Feature2D> _pFeature2D;int type = 0;int k1x = 0;int k1y = 0;int k2x = 100;int k2y = 0;int k3x = 100;int k3y = 100;int k4x = 0;int k4y = 100;// 定義匹配器cv::Ptr<cv::FlannBasedMatcher> pFlannBasedMatcher = cv::FlannBasedMatcher::create();// 定義結果存放std::vector<cv::DMatch> listDMatch;// 存儲特征點檢測器檢測特征后的描述字cv::Mat descriptor1;cv::Mat descriptor2;bool moveFlag = true; // 移動的標志,不用每次都匹配windowMat = cv::Scalar(0, 0, 0);while(true){cv::Mat mat;{std::vector<cv::KeyPoint> keyPoints1;std::vector<cv::KeyPoint> keyPoints2;int typeOld = type;int k1xOld = k1x;int k1yOld = k1y;int k2xOld = k2x;int k2yOld = k2y;int k3xOld = k3x;int k3yOld = k3y;int k4xOld = k4x;int k4yOld = k4y;mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),cv::Range(srcMat.cols * 0, srcMat.cols * 1));mat = cv::Scalar(0);cvui::trackbar(windowMat, 0 + width * 0, 0 + height * 0, 165, &type, 0, 1);cv::String str;switch(type){case 0:str = "sift";_pFeature2D = _pSift;break;case 1:str = "surf";_pFeature2D = _pSurf;break;default:break;}cvui::printf(windowMat, width / 2 + width * 0, 20 + height * 0, str.c_str());cvui::printf(windowMat, 0 + width * 0, 60 + height * 0, "k1x");cvui::trackbar(windowMat, 0 + width * 0, 70 + height * 0, 165, &k1x, 0, 100);cvui::printf(windowMat, 0 + width * 0, 120 + height * 0, "k1y");cvui::trackbar(windowMat, 0 + width * 0, 130 + height * 0, 165, &k1y, 0, 100);cvui::printf(windowMat, width / 2 + width * 0, 60 + height * 0, "k2x");cvui::trackbar(windowMat, width / 2 + width * 0, 70 + height * 0, 165, &k2x, 0, 100);cvui::printf(windowMat, width / 2 + width * 0, 120 + height * 0, "k2y");cvui::trackbar(windowMat, width / 2 + width * 0, 130 + height * 0, 165, &k2y, 0, 100);cvui::printf(windowMat, 0 + width * 0, 30 + height * 0 + height / 2, "k3x");cvui::trackbar(windowMat, 0 + width * 0, 40 + height * 0 + height / 2, 165, &k3x, 0, 100);cvui::printf(windowMat, 0 + width * 0, 90 + height * 0 + height / 2, "k3y");cvui::trackbar(windowMat, 0 + width * 0, 100 + height * 0 + height / 2, 165, &k3y, 0, 100);cvui::printf(windowMat, width / 2 + width * 0, 30 + height * 0 + height / 2, "k4x");cvui::trackbar(windowMat, width / 2 + width * 0, 40 + height * 0 + height / 2, 165, &k4x, 0, 100);cvui::printf(windowMat, width / 2 + width * 0, 90 + height * 0 + height / 2, "k4y");cvui::trackbar(windowMat, width / 2 + width * 0, 100 + height * 0 + height / 2, 165, &k4y, 0, 100);if( k1xOld != k1x || k1yOld != k1y|| k2xOld != k2x || k2yOld != k2y|| k3xOld != k3x || k3yOld != k3y|| k4xOld != k4x || k4yOld != k4y|| typeOld != type){moveFlag = true;}std::vector<cv::Point2f> srcPoints;std::vector<cv::Point2f> dstPoints;srcPoints.push_back(cv::Point2f(0.0f, 0.0f));srcPoints.push_back(cv::Point2f(srcMat.cols - 1, 0.0f));srcPoints.push_back(cv::Point2f(srcMat.cols - 1, srcMat.rows - 1));srcPoints.push_back(cv::Point2f(0.0f, srcMat.rows - 1));dstPoints.push_back(cv::Point2f(srcMat.cols * k1x / 100.0f, srcMat.rows * k1y / 100.0f));dstPoints.push_back(cv::Point2f(srcMat.cols * k2x / 100.0f, srcMat.rows * k2y / 100.0f));dstPoints.push_back(cv::Point2f(srcMat.cols * k3x / 100.0f, srcMat.rows * k3y / 100.0f));dstPoints.push_back(cv::Point2f(srcMat.cols * k4x / 100.0f, srcMat.rows * k4y / 100.0f));cv::Mat M = cv::getPerspectiveTransform(srcPoints, dstPoints);cv::Mat srcMat2;cv::warpPerspective(srcMat3,srcMat2,M,cv::Size(srcMat.cols, srcMat.rows),cv::INTER_LINEAR,cv::BORDER_CONSTANT,cv::Scalar::all(0));mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),cv::Range(srcMat.cols * 1, srcMat.cols * 2));cv::addWeighted(mat, 0.0f, srcMat2, 1.0f, 0.0f, mat);if(moveFlag){moveFlag = false;//特征點檢測// _pSift->detect(srcMat, keyPoints1);_pFeature2D->detectAndCompute(srcMat, cv::Mat(), keyPoints1, descriptor1);//繪制特征點(關鍵點)cv::Mat resultShowMat;cv::drawKeypoints(srcMat,keyPoints1,resultShowMat,cv::Scalar(0, 0, 255),cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),cv::Range(srcMat.cols * 0, srcMat.cols * 1));cv::addWeighted(mat, 0.0f, resultShowMat, 1.0f, 0.0f, mat);//特征點檢測// _pSift->detect(srcMat2, keyPoints2);_pFeature2D->detectAndCompute(srcMat2, cv::Mat(), keyPoints2, descriptor2);//繪制特征點(關鍵點)cv::Mat resultShowMat2;cv::drawKeypoints(srcMat2,keyPoints2,resultShowMat2,cv::Scalar(0, 0, 255),cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),cv::Range(srcMat.cols * 1, srcMat.cols * 2));cv::addWeighted(mat, 0.0f, resultShowMat2, 1.0f, 0.0f, mat);// FlannBasedMatcher最近鄰匹配pFlannBasedMatcher->match(descriptor1, descriptor2, listDMatch);// drawMatch繪制出來,并排顯示了,高度一樣,寬度累加(因為兩個寬度相同,所以是兩倍了)cv::Mat matchesMat;cv::drawMatches(srcMat,keyPoints1,srcMat2,keyPoints2,listDMatch,matchesMat);mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),cv::Range(srcMat.cols * 0, srcMat.cols * 2));cv::addWeighted(mat, 0.0f, matchesMat, 1.0f, 0.0f, mat);}}cv::imshow(windowName, windowMat);// 更新cvui::update();// 顯示// esc鍵退出if(cv::waitKey(25) == 27){break;}} }工程模板:對應版本號v1.62.0
對應版本號v1.62.0
上一篇:《OpenCV開發筆記(六十七):紅胖子8分鐘帶你深入了解特征點暴力匹配(圖文并茂+淺顯易懂+程序源碼)》
下一篇:持續補充中…
總結
以上是生活随笔為你收集整理的getvalue参数计数不匹配_OpenCV开发笔记(六十八):红胖子8分钟带你使用特征点Flann最邻近差值匹配识别...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为 Mate 10、P20 系列开启鸿
- 下一篇: 用vhdl语言设计一个小游戏_用最直白的