若该文为原创文章,未经允许不得转载
原博主博客地址: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最邻近差值匹配识别...相关推荐

  1. OpenCV开发笔记(四十六):红胖子8分钟带你深入了解仿射变化(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

  2. OpenCV开发笔记(三十六):红胖子8分钟带你深入了解缩放与图像金字塔(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

  3. OpenCV开发笔记(六十九):红胖子8分钟带你使用传统方法识别已知物体(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,转载请注明出处 本文章博客地址:https://blog.csdn.net/qq21497936/article/details/107837715 各位读者,知识无穷而人力有穷,要 ...

  4. OpenCV开发笔记(七十二):红胖子8分钟带你使用opencv+dnn+tensorFlow识别物体

    本博客是转载的 本文章源博客地址:https://blog.csdn.net/qq21497936/article/details/109194717 各位读者,知识无穷而人力有穷,要么改需求,要么找 ...

  5. OpenCV开发笔记(五十二):红胖子8分钟带你深入了解直方图对比匹配(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

  6. OpenCV开发笔记(六十七):红胖子8分钟带你深入了解特征点暴力匹配(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

  7. Android开发笔记(十八)书籍翻页动画PageAnimation

    前面几节的动画都算简单,本文就介绍一个复杂点的动画--书籍翻页动画.Android有自带的翻页动画ViewPager,不过ViewPager只实现了平移效果.即便使用补间组合动画或者属性动画,也只是把 ...

  8. OpenCV开发笔记(七十一):红胖子8分钟带你深入级联分类器训练

    若该文为原创文章,转载请注明原文出处 本文章博客地址:https://blog.csdn.net/qq21497936/article/details/109096211 各位读者,知识无穷而人力有穷 ...

  9. OpenCV开发笔记(五十四):红胖子8分钟带你深入了解Haar级联分类器进行人脸检测(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

最新文章

  1. 数字电视接口(HDMI,DVI)
  2. jQuery Validate验证框架详解
  3. Could not calculate build plan: Plugin org.apache.maven.plugins:maven-war-plugin:2.4
  4. sed行处理详解(交换行,合并行,删除行等)
  5. DataSet转化为DataTable
  6. 任务执行者EventLoop
  7. PAT (Basic Level) 1095 解码PAT准考证(模拟+stl,好题)
  8. Telltale:看Netflix如何简化应用程序监控体系
  9. 【ArcGIS风暴】根据海拔(坡度)范围分级统计土地覆盖的类型和面积(兰州市GlobeLand30m数据为例)
  10. [转载] 应急管理体系及其业务流程研究
  11. django-后台传图0912
  12. windows下cmd中命令操作
  13. 重庆木叶村,每天被忍者迷骚扰500次
  14. SpringCloud工作笔记052---各种数据库在java中的连接配置_以及连接驱动
  15. 数字孪生 - 认知篇
  16. 【测试】对手机拍照测试用例的设计
  17. 计算机病毒课后讨论题,《防治计算机病毒》答辩题目及解析
  18. python爬取堆糖网每日精选图片
  19. C#实现简单气泡屏保(二)
  20. Qpython SL4A服务调用GPS定位获取获取位置信息

热门文章

  1. 这个网盘下载60MB/s!PanDownload复活了!
  2. 清华计算机考研笔记,[考研天地]清华计算机,电子,自动化全套考研资料
  3. 全志r11_全志R328 Demo开发板;全志R333开发板/核心板;全志R11开发板/核心板;全志R16开发板/方案设计...
  4. php代码function,ThinkPHP ~function()和function()方法和U方法
  5. java刘保_[SSH] Eclipse+Struts2的简单应用
  6. wpf的tabcontrol获取当前选中的名字_技巧:ANSA中如何快速批量修改PID名字
  7. JavaScript三种创建构造函数的方式
  8. Python猫荐书系列之七:Python入门书籍有哪些?
  9. appium 5-27屏幕旋转、
  10. BURP 测试出 OPTIONS PUT DELETE TRACE 方法