QT + Opencv 实现灰度模板匹配

ops/2025/1/13 3:02:21/

QT + Opencv 实现灰度模板匹配

实现思路

1.模板创建代码思路

1 初始化和准备:

使用 cv::buildPyramid 函数构建图像金字塔。图像金字塔是一种多分辨率表示,每个层级的图像分辨率逐步降低。
调整 m_TemplData 的大小以匹配图像金字塔的层级数。
计算每个层级的统计数据:

2遍历图像金字塔的每个层级。

计算当前层级图像的倒数面积 invArea,用于后续的归一化处理。
使用 cv::meanStdDev 函数计算当前层级图像的均值 templMean 和标准差 templSdv。
计算模板图像的归一化范数 templNorm,这是模板图像的归一化标准差的平方和。
检查 templNorm 是否小于 DBL_EPSILON,如果是,表示当前层级图像的方差接近于零,将其标记为 vecResultEqual1 为 true。
计算 templSum2,这是 templNorm 加上均值的平方和,然后除以 invArea。
计算 templNorm 的平方根,并归一化。
将计算得到的 invArea、templMean 和 templNorm 存储到 m_TemplData 中对应的位置。

模板训练代码:

//训练模板
void frmTemplateMatch::LearnPattern(const cv::Mat model, const int num_levels,s_TemplData &m_TemplData)
{qDebug()<<"train mode...";m_TemplData.clear();cv::buildPyramid(model, m_TemplData.vecPyramid, num_levels);int iSize = m_TemplData.vecPyramid.size();m_TemplData.resize(iSize);for (int i = 0; i < iSize; i++){double invArea = 1. / ((double)m_TemplData.vecPyramid[i].rows * m_TemplData.vecPyramid[i].cols);cv::Scalar templMean, templSdv;double templNorm = 0, templSum2 = 0;cv::meanStdDev(m_TemplData.vecPyramid[i], templMean, templSdv);templNorm = templSdv[0] * templSdv[0] + templSdv[1] * templSdv[1] + templSdv[2] * templSdv[2] + templSdv[3] * templSdv[3];if (templNorm < DBL_EPSILON){m_TemplData.vecResultEqual1[i] = true;}templSum2 = templNorm + templMean[0] * templMean[0] + templMean[1] * templMean[1] + templMean[2] * templMean[2] + templMean[3] * templMean[3];templSum2 /= invArea;templNorm = std::sqrt(templNorm);templNorm /= std::sqrt(invArea);m_TemplData.vecInvArea[i] = invArea;m_TemplData.vecTemplMean[i] = templMean;m_TemplData.vecTemplNorm[i] = templNorm;}
//    qDebug()<<"train mode end...";m_TemplData.bIsPatternLearned = true;
}

2.匹配思路

1同样先对原图进行构建金字塔,模板和原图的金字塔层数要一致。
2.角度计算与旋转

计算旋转角度步长dAngleStep,基于模板金字塔某层的尺寸和atan函数得到。初始化角度向量vecAngles,并分别向其中添加从0到angle_start_end以及从-dAngleStep到-angle_start_end的递增角度值。

3.一层一层进行匹配

匹配代码:

int frmTemplateMatch::MatchTemplate(const cv::Mat source, const cv::Mat model, cv::Mat& out_source, const bool use_roi, const MRectangle m_rectangle,  const int num_levels, const int angle_start_end, const int num_matches, const double max_overlap,const double int_score, const bool show_result, const int thickness,s_TemplData pTemplData,vector<s_SingleTargetMatch> &m_vecSingleTargetData)
{if (source.empty() || model.empty() || (model.size().area() > source.size().area())){qDebug()<<"error1";return -1;}if ((model.cols < source.cols && model.rows > source.rows) || (model.cols > source.cols && model.rows < source.rows)){qDebug()<<"error2";return -1;}cv::Mat gray_source, gray_model;if (source.channels() == 3){cv::cvtColor(source, gray_source, cv::COLOR_BGR2GRAY);}else if (source.channels() == 4){cv::cvtColor(source, gray_source, cv::COLOR_RGBA2GRAY);}else{source.copyTo(gray_source);}if (model.channels() == 3){cv::cvtColor(model, gray_model, cv::COLOR_BGR2GRAY | cv::COLOR_RGB2GRAY);}else if (model.channels() == 4){cv::cvtColor(model, gray_model, cv::COLOR_RGBA2GRAY);}else{model.copyTo(gray_model);}// LearnPattern(gray_model, num_levels,pTemplData);qDebug()<<"is traind"<<pTemplData.bIsPatternLearned;vector<cv::Mat> vecMatSrcPyr = vector<cv::Mat>(100);vecMatSrcPyr.clear();cv::buildPyramid(gray_source, vecMatSrcPyr, num_levels);double dAngleStep = atan(2.0 / max(pTemplData.vecPyramid[num_levels].cols, pTemplData.vecPyramid[num_levels].rows)) * R2D;vector<double> vecAngles = vector<double>(360);vecAngles.clear();for (double dAngle = 0; dAngle < angle_start_end + dAngleStep; dAngle += dAngleStep){vecAngles.push_back(dAngle);}for (double dAngle = -dAngleStep; dAngle > -angle_start_end - dAngleStep; dAngle -= dAngleStep){vecAngles.push_back(dAngle);}qDebug()<<"match ----- 1";int iTopSrcW = vecMatSrcPyr[num_levels].cols, iTopSrcH = vecMatSrcPyr[num_levels].rows;cv::Point2f ptCenter((iTopSrcW - 1) / 2.0f, (iTopSrcH - 1) / 2.0f);int iSize = (int)vecAngles.size();vector<s_MatchParameter> vecMatchParameter(iSize * (num_matches + MATCH_CANDIDATE_NUM));vector<double> vecLayerScore(num_levels + 1, int_score);for (int iLayer = 1; iLayer <= num_levels; iLayer++)vecLayerScore[iLayer] = vecLayerScore[iLayer - 1] * 0.9;
#pragma omp parallel for  //并发处理for (int i = 0; i < iSize; i++){

3实现效果

项目文件:
在这里插入图片描述

在这里插入图片描述


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

相关文章

Monaco Editor 系列报错修复:webpack-cli已经下载了但是还报错

今天想把项目push到gitee上&#xff0c;复制、拖动改动了好多&#xff0c;导致项目起不来了&#xff0c;从头安装依赖&#xff0c;但是出现了一个奇怪的报错。众所周知&#xff0c;我们启动项目是在 website 目录下&#xff0c;安装依赖也是在这个目录下&#xff0c;我webpack-…

SVM赛道概览:MoveVM落地,SVM能走多远

Sonic SVM、SOON、Eclipse全方位解读。 作者&#xff1a;jk&#xff1b;编辑&#xff1a;郝方舟 出品 | Odaily星球日报&#xff08;ID&#xff1a;o-daily&#xff09; 随着高性能与可扩展性的需求愈发迫切&#xff0c;Solana Virtual Machine&#xff08;SVM&#xff09;正逐…

老榕树的java专题:探索 Nacos:微服务架构中的配置与服务发现利器

在当今微服务架构盛行的时代&#xff0c;如何高效地管理配置信息以及实现服务之间的发现与协调成为了开发者们重点关注的问题。而 Nacos&#xff08;Naming and Configuration Service&#xff09;的出现&#xff0c;就像是为微服务搭建起了一座坚实的桥梁&#xff0c;让这些复…

计算机毕业设计hadoop+spark+hive新能源汽车推荐系统 汽车数据分析可视化大屏 新能源汽车推荐系统 汽车爬虫 汽车大数据 机器学习

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

gesp(C++四级)(14)洛谷:B4041:[GESP202409 四级] 区间排序

gesp(C四级)&#xff08;14&#xff09;洛谷&#xff1a;B4041&#xff1a;[GESP202409 四级] 区间排序 题目描述 小杨有一个包含 n n n 个正整数的序列 a a a。 小杨计划对序列进行多次升序排序&#xff0c;每次升序排序小杨会选择一个区间 [ l , r ] [l,r] [l,r]&#x…

CES Asia 2025:VR/AR/XR引领科技新潮流

在全球科技领域蓬勃发展的大背景下&#xff0c;CES Asia 2025&#xff08;赛逸展&#xff09;即将在京盛大开幕&#xff0c;VR/AR/XR技术作为前沿科技的代表&#xff0c;将在本次展会上大放异彩&#xff0c;展现出令人瞩目的发展趋势和巨大潜力&#xff0c;同时政策优势也将为其…

汽车基础软件AutoSAR自学攻略(四)-AutoSAR CP分层架构(3) (万字长文-配21张彩图)

汽车基础软件AutoSAR自学攻略(四)-AutoSAR CP分层架构(3) (万字长文-配21张彩图) 前面的两篇博文简述了AutoSAR CP分层架构的概念&#xff0c;下面我们来具体到每一层的具体内容进行讲解&#xff0c;每一层的每一个功能块力求用一个总览图&#xff0c;外加一个例子的图给大家进…

如何将光源视角的深度贴图应用于摄像机视角的渲染

我们需要将摄像机视角下的每个像素投影到光源的视角中&#xff0c;然后检查该像素在光源视角下的深度值是否大于深度贴图中的深度值。如果大于&#xff0c;则说明该像素被遮挡&#xff0c;处于阴影中&#xff1b;否则&#xff0c;它不在阴影中。 具体步骤如下&#xff1a; 1.将…