getvalue参数计数不匹配_OpenCV开发笔记(六十八):红胖子8分钟带你使用特征点Flann最邻近差值匹配识别...
若該文為原創(chuàng)文章,未經(jīng)允許不得轉(zhuǎn)載
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客導(dǎo)航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/107357296
各位讀者,知識(shí)無(wú)窮而人力有窮,要么改需求,要么找專業(yè)人士,要么自己研究
紅胖子(紅模仿)的博文大全:開(kāi)發(fā)技術(shù)集合(包含Qt實(shí)用技術(shù)、樹(shù)莓派、三維、OpenCV、OpenGL、ffmpeg、OSG、單片機(jī)、軟硬結(jié)合等等)持續(xù)更新中…(點(diǎn)擊傳送門)
OpenCV開(kāi)發(fā)專欄(點(diǎn)擊傳送門)
上一篇:《OpenCV開(kāi)發(fā)筆記(六十七):紅胖子8分鐘帶你深入了解特征點(diǎn)暴力匹配(圖文并茂+淺顯易懂+程序源碼)》
下一篇:持續(xù)補(bǔ)充中…
前言
紅胖子,來(lái)也!
前面講解了特征點(diǎn),那么匹配特征點(diǎn),就是匹配兩者的相似度,相似度達(dá)到一定的閾值,則認(rèn)為識(shí)別了。
考慮性能,除開(kāi)暴力匹配外,還有最近鄰匹配。
Demo
最近鄰匹配(FLANN)
FlannBasedMatcher中FLANN的含義是Fast Library forApproximate Nearest Neighbors,目前最完整的(近似)最近鄰匹配。不但實(shí)現(xiàn)了一系列查找算法,還包含了一種自動(dòng)選取最快算法的機(jī)制。
從字面意思可知它是一種近似法,算法更快但是找到的是最近鄰近似匹配,所以當(dāng)我們需要找到一個(gè)相對(duì)好的匹配但是不需要最佳匹配的時(shí)候往往使用FlannBasedMatcher。
當(dāng)然也可以通過(guò)調(diào)整FlannBasedMatcher的參數(shù)來(lái)提高匹配的精度或者提高算法速度,但是相應(yīng)地算法速度或者算法精度會(huì)受到影響。
本篇章使用sift/surf特征點(diǎn)
sift特征點(diǎn)
尺度不變特征變換(Scale-invariant feature transform,SIFT),是用于圖像處理領(lǐng)域的一種描述。這種描述具有尺度不變性,可在圖像中檢測(cè)出關(guān)鍵點(diǎn),是一種局部特征描述子。
surf特征點(diǎn)
SURF算法采用了很多方法來(lái)對(duì)每一步進(jìn)行優(yōu)化從而提高速度。分析顯示在結(jié)果效果相當(dāng)?shù)那闆r下SURF的速度是SIFT的3倍。SURF善于處理具有模糊和旋轉(zhuǎn)的圖像,但是不善于處理視角變化和光照變化。(SIFT特征是局部特征,其對(duì)旋轉(zhuǎn)、尺度縮放、亮度變化保持不變性,對(duì)視角變化、仿射變換、噪聲也保持一定程度的穩(wěn)定性)。
針對(duì)圖像場(chǎng)景的特點(diǎn),選擇不同的特征點(diǎn),列出之前特征點(diǎn)相關(guān)的博文:
《OpenCV開(kāi)發(fā)筆記(六十三):紅胖子8分鐘帶你深入了解SIFT特征點(diǎn)(圖文并茂+淺顯易懂+程序源碼)》
《OpenCV開(kāi)發(fā)筆記(六十四):紅胖子8分鐘帶你深入了解SURF特征點(diǎn)(圖文并茂+淺顯易懂+程序源碼)》
《OpenCV開(kāi)發(fā)筆記(六十五):紅胖子8分鐘帶你深入了解ORB特征點(diǎn)(圖文并茂+淺顯易懂+程序源碼)》
FlannBasedMatcher類的使用
定義
// 定義匹配器 cv::Ptr<cv::FlannBasedMatcher> pFlannBasedMatcher = cv::FlannBasedMatcher::create(); // 定義結(jié)果存放 std::vector<cv::DMatch> listDMatch; // 存儲(chǔ)特征點(diǎn)檢測(cè)器檢測(cè)特征后的描述字 cv::Mat descriptor1; cv::Mat descriptor2;
特征點(diǎn)提取
pFlannBasedMatcher->detectAndCompute(srcMat1, cv::Mat(), keyPoints1, descriptor1); pFlannBasedMatcher->detectAndCompute(srcMat1, cv::Mat(), keyPoints1, descriptor1);
匹配
// FlannBasedMatcher最近鄰匹配 pFlannBasedMatcher->match(descriptor1, descriptor2, listDMatch); FlannBasedMatcher相關(guān)函數(shù)原型 static Ptr<FlannBasedMatcher> create() ;
無(wú)參數(shù)
FlannBasedMatcher::match( InputArray queryDescriptors, InputArray trainDescriptors, std::vector<DMatch>& matches, InputArray mask=noArray() ) const;
- 參數(shù)一:InputArray類型的queryDescriptors,查詢描述符集,一般cv::Mat,某個(gè)特征提取的描述符。
- 參數(shù)二:InputArray類型的trainDescriptors,訓(xùn)練描述符集,此處輸入的應(yīng)該是沒(méi)有加入到類對(duì)象集合種的(該類有訓(xùn)練的數(shù)據(jù)集合),一般cv::Mat,某個(gè)特征提取的描述符。
- 參數(shù)三:std::vector類型的matches。如果在掩碼中屏蔽了查詢描述符,則不會(huì)為此添加匹配項(xiàng)描述符。因此,匹配項(xiàng)的大小可能小于查詢描述符計(jì)數(shù)。
- 參數(shù)四:InputArray類型的mask,指定輸入查詢和訓(xùn)練矩陣之間允許的匹配的掩碼描述符。
繪制匹配關(guān)系圖函數(shù)原型
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 );
- 參數(shù)一:InputArray類型的img1,圖像1。
- 參數(shù)二:std::vector類型的keypoints1,圖像1的關(guān)鍵點(diǎn)。
- 參數(shù)三:InputArray類型的img2,圖像2。
- 參數(shù)四:std::vector類型的keypoints2,圖像2的關(guān)鍵點(diǎn)。
- 參數(shù)五:std::vector類型的matchers1to2,從第一個(gè)圖像匹配到第二個(gè)圖像,這意味著keypoints1[i]在keypoints2中有一個(gè)對(duì)應(yīng)的點(diǎn)[matches[i]]。
- 參數(shù)六:InputOutputArray類型的outImg,為空時(shí),默認(rèn)并排繪制輸出圖像以及連接關(guān)鍵點(diǎn);若不為空,則在圖像上繪制關(guān)系點(diǎn)。
- 參數(shù)七:Scalar類型的matcherColor,匹配顏色匹配(線和連接的關(guān)鍵點(diǎn))的顏色。如果顏色為cv::Scalar::all(-1),則為隨機(jī)顏色。
- 參數(shù)八:Scalar類型的singlePointColor,顏色單個(gè)關(guān)鍵點(diǎn)(圓)的顏色,這意味著關(guān)鍵點(diǎn)沒(méi)有匹配到的則認(rèn)是該顏色。
- 參數(shù)九:std::vector類型的matchersMask,確定繪制的匹配項(xiàng)目,若是為空,則表示全部繪制。
- 參數(shù)十: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();// 定義結(jié)果存放std::vector<cv::DMatch> listDMatch;// 存儲(chǔ)特征點(diǎn)檢測(cè)器檢測(cè)特征后的描述字cv::Mat descriptor1;cv::Mat descriptor2;bool moveFlag = true; // 移動(dòng)的標(biāo)志,不用每次都匹配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;//特征點(diǎn)檢測(cè)// _pSift->detect(srcMat, keyPoints1);_pFeature2D->detectAndCompute(srcMat, cv::Mat(), keyPoints1, descriptor1);//繪制特征點(diǎn)(關(guān)鍵點(diǎn))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);//特征點(diǎn)檢測(cè)// _pSift->detect(srcMat2, keyPoints2);_pFeature2D->detectAndCompute(srcMat2, cv::Mat(), keyPoints2, descriptor2);//繪制特征點(diǎn)(關(guān)鍵點(diǎn))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繪制出來(lái),并排顯示了,高度一樣,寬度累加(因?yàn)閮蓚€(gè)寬度相同,所以是兩倍了)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;}} }工程模板:對(duì)應(yīng)版本號(hào)v1.62.0
對(duì)應(yīng)版本號(hào)v1.62.0
上一篇:《OpenCV開(kāi)發(fā)筆記(六十七):紅胖子8分鐘帶你深入了解特征點(diǎn)暴力匹配(圖文并茂+淺顯易懂+程序源碼)》
下一篇:持續(xù)補(bǔ)充中…
總結(jié)
以上是生活随笔為你收集整理的getvalue参数计数不匹配_OpenCV开发笔记(六十八):红胖子8分钟带你使用特征点Flann最邻近差值匹配识别...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 华为 Mate 10、P20 系列开启鸿
- 下一篇: 长虹即将发布中国首款 8K 高刷 Min