QT + opencv 实现形状(轮廓)模板匹配

ops/2025/1/12 8:22:56/

opencv__0">QT + opencv 实现形状(轮廓)模板匹配

实现思路

1.创建模板数据:主要是提取模板的轮廓信息,这一步通常通过边缘检测实现。将模板的轮廓信息存储起来。

代码:

//创建形状模板
bool cvLearnShapeMatchPattern_(Mat matDst, MyShapeUiParam param, MyShapeTemplData* pTemplData)
{//图像不存在if(matDst.empty())return false;//清除模板pTemplData->clear();//边缘检测Mat canny, gray;vector<Point> contours;cv::Canny(matDst, canny, pTemplData->minThresh, pTemplData->maxThresh);canny.copyTo(gray);/*if(!(pTemplData->sample==0)){Mat element=getStructuringElement(MORPH_ELLIPSE, Size(pTemplData->dilate, pTemplData->dilate));cv::dilate(canny, gray, element);}*/cvFindContour_(gray, contours, pTemplData->minLen, 10e9, pTemplData->sample);if((int)contours.size()==0)return false;//压缩金字塔int iTopLayer=param.m_iPyramid;buildPyramid(matDst, pTemplData->vecPyramid, iTopLayer);for(size_t i=0;i<pTemplData->vecPyramid.size();i++){//轮廓信息Mat src=pTemplData->vecPyramid[i];vector<Point> pyrContour=cvPyrContour_(contours, matDst.size(), src.size());pTemplData->vecPoints.push_back(pyrContour);//显示Mat dst=Mat::zeros(src.size(), CV_8UC1);for(size_t j=0;j<pyrContour.size();j++)dst.at<uchar>(pyrContour[j].y, pyrContour[j].x)=255;imshow(QString("%1").arg(i).toStdString(), dst);cv::waitKey(5);//梯度信息Mat gx, gy, mag, dir;Sobel(src, gx, CV_32F, 1, 0);Sobel(src, gy, CV_32F, 0, 1);cartToPolar(gx, gy, mag, dir);//提取梯度vector<SPtin> vecSPtin;for(size_t j=0;j<pyrContour.size();j++){SPtin info;Point p=pyrContour[j];info.derivativeX=gx.at<float>(p.y, p.x);info.derivativeY=gy.at<float>(p.y, p.x);info.magnitude=mag.at<float>(p.y, p.x);info.magnitudeN = info.magnitude==0 ? 0 : (1.0f / info.magnitude);vecSPtin.push_back(info);}pTemplData->vecSPtins.push_back(vecSPtin);}//训练标记pTemplData->bIsPatternLearned=true;return true;
}

2.模板匹配:同样需要利用压缩金字塔的方法来提升搜索速度,减少参数量。然后取顶层金字塔进行旋转,和模板轮廓进行匹配,找到大致角度后再进行细致的搜索。

部分代码

//模板匹配
bool cvShapeMatch_(Mat matSrc, vector<MyShapeTemplData> templDatas, MyShapeUiParam param, vector<MySingleTargetMatch>& vecSingleTargetData)
{//图像if(matSrc.empty())return false;//模板if((int)templDatas.size()==0)return false;//決定金字塔層數 總共為1 + iLayer層int iTopLayer=param.m_iPyramid;vector<Mat> vecMatSrcPyr;buildPyramid(matSrc, OutputArrayOfArrays(vecMatSrcPyr), iTopLayer);//取顶层图片的中心点int iTopSrcW = vecMatSrcPyr[iTopLayer].cols, iTopSrcH = vecMatSrcPyr[iTopLayer].rows;Point2f ptCenter((iTopSrcW - 1) / 2.0f, (iTopSrcH - 1) / 2.0f);//Caculate lowest score at every layervector<double> vecLayerScore(iTopLayer + 1, param.m_dScore);for (int iLayer = 1; iLayer <= iTopLayer; iLayer++)vecLayerScore[iLayer] = vecLayerScore[iLayer - 1] * param.m_dGreed;//clearvecSingleTargetData.clear();//并行加速omp_set_num_threads(4);#pragma omp parallel forfor(int k=0;k<(int)templDatas.size();k++){MyShapeTemplData* pTemplData = &templDatas[k];if((int)pTemplData->vecPyramid.size()==0 || !pTemplData->bIsPatternLearned)continue;Mat matDst=pTemplData->vecPyramid[0];if (matDst.empty())continue;if ((matDst.cols<matSrc.cols && matDst.rows>matSrc.rows) || (matDst.cols>matSrc.cols && matDst.rows<matSrc.rows))continue;if (matDst.size().area()>=matSrc.size ().area())continue;//匹配轮廓vector<Point> Contour=pTemplData->vecPoints[0];cvAffineTrans_(Contour, Point3f((float)(matDst.cols - 1)/2.0f, (float)(matDst.rows - 1)/2.0f, 0), Point3f(0, 0, 0));//第一階段以最頂層找出大致角度與ROIdouble dAngleStep=atan(2.0 / max(pTemplData->vecPyramid[iTopLayer].cols, pTemplData->vecPyramid[iTopLayer].rows)) * R2D;

实现效果:实际匹配目标时,角度搜索范围可以不必像我这样设置这么大。在相机画面中进行检测时,通常是在ROI中进行检测,速度通常在100ms以内。

在这里插入图片描述
在这里插入图片描述


http://www.ppmy.cn/ops/149391.html

相关文章

字节小米等后端岗位C++面试题

C 基础 引用和指针之间的区别&#xff1f;堆栈和堆中的内存分配有何区别&#xff1f;存在哪些类型的智能指针&#xff1f;unique_ptr 是如何实现的&#xff1f;我们如何强制在 unique_ptr 中仅存在一个对象所有者&#xff1f;shared_ptr 如何工作&#xff1f;对象之间如何同步…

RK3568-ubuntu旋转显示和触摸

旋转屏幕显示 临时生效&#xff1a;xrandr -o <normal,inverted,left,right,0,1,2,3> 永久生效&#xff1a;/etc/X11/Xsession.d/55gnome-session_gnomerc最后一行添加临时生效命令旋转屏幕触摸 方法1&#xff1a;cp /usr/share/X11/xorg.conf.d/40-libinput.conf /etc…

机器学习顶会NeurIPS: AGILE: A Novel Reinforcement Learning Framework of LLM Agents

&#x1f31f; 研究背景 &#x1f31f; 随着大型语言模型&#xff08;LLMs&#xff09;在指令遵循、推理和零样本学习等方面展现出卓越的能力&#xff0c;基于LLMs的自主代理&#xff08;LLM Agents&#xff09;的研究逐渐兴起。然而&#xff0c;如何将规划、反思、工具使用等…

模型 九屏幕分析法

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。九屏幕法&#xff1a;全方位分析问题的系统工具。 1 九屏幕分析法的应用 1.1 新产品研发的市场分析 一家科技公司计划开发一款新型智能手机&#xff0c;为了全面评估市场潜力和风险&#xff0c;他们…

C#数据库操作系列---SqlSugar完结篇

1. 不同寻常的查询 之前介绍了针对单个表的查询&#xff0c;同样也是相对简单的查询模式。虽然开发完全够用&#xff0c;但是难免会遇到一些特殊的情况。而下面这些方法就是为了解决这些意料之外。 1.1 多表查询 SqlSugar提供了一种特殊的多表查询方案&#xff0c;使用IQuer…

Redis常见知识点

1、什么是缓存穿透&#xff1f; 缓存穿透是指查询一定某个key是否存在&#xff0c;每次不存在都查询DB会把DB压垮。 解决方案的话&#xff0c;我们通常都会用布隆过滤器来解决。 布隆过滤器&#xff1a;在查找一个数是否在一个集合中使用的&#xff0c;通过对数组长度取模&a…

在php中,Fiber、Swoole、Swow这3个协程都是如何并行运行的?

文章精选推荐 1 JetBrains Ai assistant 编程工具让你的工作效率翻倍 2 Extra Icons&#xff1a;JetBrains IDE的图标增强神器 3 IDEA插件推荐-SequenceDiagram&#xff0c;自动生成时序图 4 BashSupport Pro 这个ides插件主要是用来干嘛的 &#xff1f; 5 IDEA必装的插件&…

js装饰器模式

装饰器模式是一种结构型设计模式&#xff0c;它允许你在不改变对象结构的情况下&#xff0c;动态地给对象添加新的行为或职责。 装饰器模式通过创建一个装饰器类&#xff0c;来包装原始对象&#xff0c;并在不改变原始对象的基础上&#xff0c;为其添加新的功能。装饰器类和原始…