opencv--使用opencv实现旋转角度的模板匹配

news2024/12/28 3:36:20

下面的例子是简单的使用opencv 实现的模板匹配流程,其中时间性能和精确度还需要调整,如果直接使用会出问题,所以这个只是例子,根据代码原理可以实现尺度变化的模板匹配和旋转尺度变化同时,具体根据实现的旋转代码进一步实现,但是就结果而言和halcon的模板匹配差距较大,性能更不行,因此仅供参考 ,同时本人整理了两个使用各种加速的高性能版本,有兴趣的可以下载看看

struct MatchResult
{
	std::vector<cv::Point> points;
	double angle;
	double score;
	MatchResult(std::vector<cv::Point> points, double angle, double score) :points(points), angle(angle), score(score) {};
};

//旋转图像
cv::Mat ImageRotate(cv::Mat image, double angle)
{
	cv::Mat newImg;
	cv::Point2f pt = cv::Point2f((float)image.cols / 2, (float)image.rows / 2);
	cv::Mat M = cv::getRotationMatrix2D(pt, angle, 1.0);
	cv::warpAffine(image, newImg, M, image.size());
	return newImg;
}
std::vector<cv::Point> GetRotatePoints(cv::Size size, double angle) {
	// 定义模板图像的中心点
	cv::Point2f center(size.width / 2.0, size.height / 2.0);

	// 计算旋转矩阵
	cv::Mat rotationMatrix = cv::getRotationMatrix2D(center, angle, 1.0);

	// 定义模板图像的四个顶点
	std::vector<cv::Point2f> srcPoints = {
		cv::Point2f(0, 0),
		cv::Point2f(size.width, 0),
		cv::Point2f(size.width, size.height),
		cv::Point2f(0, size.height)
	};

	// 存储旋转后的四个顶点
	std::vector<cv::Point2f> dstPoints(4);

	// 进行仿射变换
	cv::transform(srcPoints, dstPoints, rotationMatrix);

	// 将结果转换为cv::Point类型并返回
	std::vector<cv::Point> resultPoints(4);
	for (int i = 0; i < 4; ++i) {
		resultPoints[i] = cv::Point(cvRound(dstPoints[i].x), cvRound(dstPoints[i].y));
	}

	return resultPoints;
}


/*
旋转模板匹配函数(通过图像金字塔、增大旋转步长来提升匹配速度)
Mat src:原图像
Mat model:模板图
double startAngle:旋转的最小角
double endAngle:旋转的最大角
double firstStep:角度旋转时的最大步长
double secondStep:角度旋转时的最小步长
int numLevels = 0:图像金字塔缩放次数
*/
MatchResult rotateMatch(cv::Mat src, cv::Mat model, double startAngle, double endAngle, double firstStep, double secondStep, int numLevels = 0) {
	//对模板图像和待检测图像分别进行图像金字塔下采样
	for (int i = 0; i < numLevels; i++) {
		cv::pyrDown(src, src, cv::Size(src.cols / 2, src.rows / 2));
		cv::pyrDown(model, model, cv::Size(model.cols / 2, model.rows / 2));
	}

	cv::Mat rotatedImg, result;
	double score = -1;
	cv::Point location;
	double angle;

	bool isSecond = false;
	while (true) {
		for (double curAngle = startAngle; curAngle <= endAngle; curAngle += firstStep) {
			rotatedImg = ImageRotate(model, curAngle);
			//imshow("rotated", rotatedImg);
			//imshow("src-pyrDown", src);
			//waitKey();

			matchTemplate(src, rotatedImg, result, cv::TM_CCOEFF_NORMED);
			double minval, maxval;
			cv::Point minloc, maxloc;
			cv::minMaxLoc(result, &minval, &maxval, &minloc, &maxloc);
			if (maxval > score)
			{
				location = maxloc;
				score = maxval;
				angle = curAngle;
			}
		}

		if (isSecond && firstStep<= secondStep) break;

		startAngle = angle - firstStep;
		endAngle = angle + firstStep;

		if ((endAngle - startAngle) / 5 > secondStep) {
			firstStep = (endAngle - startAngle) / 5;
		}
		else {
			firstStep = secondStep;
			isSecond = true;
		}
	}

	cv::Point finalPoint = cv::Point(location.x * pow(2, numLevels), location.y * pow(2, numLevels));
	std::vector<cv::Point> points = GetRotatePoints(cv::Size(model.cols * pow(2, numLevels), model.rows * pow(2, numLevels)), angle);

	for (int j = 0; j < points.size(); j++)
	{
		points[j].x += finalPoint.x;
		points[j].y += finalPoint.y;
	}

	return MatchResult(points, angle, score);
}

int main() {
	//读取所有图像
	std::vector<cv::Mat> imgs;
	std::string imageName;
	std::string path = "E:\\prj\\shape_based_matching-master\\test\\board\\test";
	std::vector<std::string> img_paths;
	cv::glob(path, img_paths);
	for (auto& p : img_paths)
	{
		cv::Mat img = cv::imread(p);
		imgs.push_back(img);
	}
	cv::Mat templateImg = cv::imread("E:\\prj\\shape_based_matching-master\\test\\board\\train.png");
	cv::Rect box(cv::Point(135, 120), cv::Point(470, 365));
	//cv::rectangle(drawFrame, box, cv::Scalar(0, 255, 0), 2);
	templateImg = templateImg(box).clone();
	int i = 0;
	for (cv::Mat img : imgs)
	{
		i += 1;
		MatchResult matchResult = rotateMatch(img, templateImg, 0, 360, 30, 0.1, 0);
		std::vector<cv::Point> points = matchResult.points;
		std::cout << i << "- 角度:" << matchResult.angle << std::endl;
		std::cout << i << "- 得分:" << matchResult.score << std::endl;

		cv::line(img, points[0], points[1], cv::Scalar(255, 0, 0), 2);
		cv::line(img, points[1], points[2], cv::Scalar(255, 0, 0), 2);
		cv::line(img, points[2], points[3], cv::Scalar(255, 0, 0), 2);
		cv::line(img, points[3], points[0], cv::Scalar(255, 0, 0), 2);

		cv::Point pt1 = cv::Point((points[0].x + points[3].x) / 2, (points[0].y + points[3].y) / 2);
		cv::Point pt2 = cv::Point((points[1].x + points[2].x) / 2, (points[1].y + points[2].y) / 2);
		cv::arrowedLine(img, pt2, pt1, cv::Scalar(0, 0, 255), 2);

		cv::imshow("img_" + std::to_string(i), img);
		cv::waitKey(0);
	}

	return 0;
}

结果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1808097.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Unity学习笔记】反射

文章目录 前言反射通过反射获取类型 Unity中的反射用反射在Unity中动态加载 前言 在我平时做项目的时候&#xff0c;由于我们做的项目都是很简单的&#xff0c;所以不怎么接触反射机制。最早了解反射机制是关于Invoke的时候&#xff0c;知道可以通过方法名来直接进行Invoke调用…

【会议征稿,IEEE出版】第三届能源与电力系统国际学术会议 (ICEEPS 2024,7月14-16)

如今&#xff0c;全球能源行业正面临着前所未有的挑战。一方面&#xff0c;加快向清洁、可再生能源转型是遏制能源环境污染问题的最佳途径之一&#xff1b;另一方面&#xff0c;电力系统中新能源发电、人工智能技术、电力电子装备等被广泛应用和期待&#xff0c;以提高能源可持…

汇编:结构体

在32位汇编中&#xff0c;结构体&#xff08;structures&#xff09;用于组织和管理复杂的数据类型&#xff0c;结构体可以包含多个不同类型的数据项&#xff08;成员&#xff09;&#xff1b;在MASM&#xff08;Microsoft Macro Assembler&#xff09;中&#xff0c;使用结构体…

Qt——升级系列(Level Four):控件概述、QWidget 核心属性、按钮类控件

目录 控件概述 QWidget 核心属性 核心属性概览 enabled geometry windowTitle windowIcon windowOpacity cursor font toolTip focusPolicy styleSheet 按钮类控件 Push Button Radio Buttion Check Box Tool Button 控件概述 Widget 是 Qt 中的核⼼概念. 英⽂原义是 "…

10.结构体、共用体、枚举

头文件&#xff1a;#include<string.h> //struct&#xff1a;结构体关键字 //stu&#xff1a;结构体类型名&#xff0c;指定了一个结构体类型&#xff0c;它相当于一个模型&#xff0c;但其中并无具体数据&#xff0c;系统对之也不分配实际内存单元//使用结构体类型必须是…

CDR2024软件破解Keygen激活工具2024最新版

CorelDRAW Graphics Suite2024最新版&#xff0c;这是一款让我爱不释手的图形设计神器&#xff01;作为一个软件评测专家&#xff0c;我一直在寻找一款能够提升我的设计效率和创造力的工具。而这款软件&#xff0c;简直就是为我量身定制的&#xff01;&#x1f389; 「CorelDR…

北航第五次数据结构与程序设计编程题复习

北航第五次数据结构与程序设计编程题复习 树叶节点遍历&#xff08;树-基础题&#xff09;计算器&#xff08;表达式计算-表达式树实现&#xff09;服务优化词频统计&#xff08;树实现&#xff09; 树叶节点遍历&#xff08;树-基础题&#xff09; 【问题描述】 从标准输入中…

OpenCV学习(4.9) OpenCV中的轮廓

1.目标 了解轮廓是什么。学习寻找轮廓&#xff0c;绘制轮廓等您将看到以下功能&#xff1a;**cv.findContours()** &#xff0c;**cv.drawContours()* 2.什么是轮廓 轮廓可以简单地解释为连接具有相同颜色或强度的所有连续点(沿边界)的曲线。轮廓是用于形状分析以及对象检测…

嵌入式学习——Linux高级编程复习(互斥锁、信号量、管道、信号)——day41

1. 同步和异步 1.1 同步 多个任务在某一时刻,先后执行顺序可以被确定 同步操作要求一系列操作严格按照顺序执行&#xff0c;一个操作只有在前一个操作完成之后才能开始。在计算机编程中&#xff0c;这意味着当一个程序或线程发出一个请求或调用后&#xff0c;它会暂停执行&…

java自动化之java基础03-09java基础之数组

数组 1、定义 数组是一种用于存储固定大小的同类型数据的数据结构 1&#xff09;固定大小 2&#xff09;同类型数据的存储 2、声明数组 1&#xff09;数据类型[] 变量名称&#xff1b; 例如&#xff1a;int[] numsArry; 2&#xff09;数据类型 变量名称[]; 例如&#xf…

27.机会成本

上海市计算机学会竞赛平台 | YACSYACS 是由上海市计算机学会于2019年发起的活动,旨在激发青少年对学习人工智能与算法设计的热情与兴趣,提升青少年科学素养,引导青少年投身创新发现和科研实践活动。https://www.iai.sh.cn/problem/677 题目描述 明天有 𝑛n 门考试,今晚只…

【C++修行之道】类和对象(五)日期类的实现、const成员、取地址及const和取地址操作符重载

目录 一、 日期类的实现 Date.h 1.1 GetMonthDay函数&#xff08;获取某年某月的天数&#xff09; 问&#xff1a;这个函数为什么不和其他的函数一样放在Date.cpp文件中实现呢&#xff1f; 1.2 CheckDate函数&#xff08;检查日期有效性&#xff09;、Print函数&#xff08;…

计算机毕业设计 | SpringBoot宠物医院管理 宠物商城购物系统(附源码)

写在前面 Le Dao宠物医院管理系统是一个超大型的&#xff0c;完成度很高的&#xff0c;集宠物医疗、宠物美容、宠物交易、宠物周边等各种功能于一身的&#xff0c;权限涵盖普通用户、医生、化验师、美容师、仓库主管、采购员等多种角色于一体的大型宠物医疗&#xff0c;购物系…

Java 数据类型 -- Java 语言的 8 种基本数据类型、字符串与数组

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 004 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…

1035 插入与归并(测试点6)

solution 类型判断&#xff1a;插入排序中已排序的部分有序&#xff0c;未排序的和原数组元素相同&#xff1b;否则为归并排序测试点6&#xff1a;对于归并排序的子序列长度&#xff0c;不能简单视为前k个有序则子序列长度就是k 例如该测试用例的归并排序的子序列长度应该为2&…

重新认识Word —— 制作简历

重新认识Word —— 制作简历 PPT的图形减除功能word中的设置调整页边距进行排版表格使用 我们之前把word长排版文本梳理了一遍&#xff0c;其实word还有另外的功能&#xff0c;比如说——制作简历。 在这之前&#xff0c;我们先讲一个小技巧&#xff1a; PPT的图形减除功能 …

记录一次被谷歌封号后又解封的过程

先提前恭祝2024年所有参加高考的学子们都能金榜题名&#xff0c;会的全对&#xff0c;不会的蒙的全对&#xff01; 一、背景 众所周知&#xff0c;谷歌、ios应用市场对app的审查都是极其严格的&#xff0c;开发者稍有不慎就会被谷歌下架应用&#xff0c;乃至封号。我们公司是做…

目标检测应用场景—数据集【NO.36】甘蔗叶片病害识别数据集

写在前面&#xff1a;数据集对应应用场景&#xff0c;不同的应用场景有不同的检测难点以及对应改进方法&#xff0c;本系列整理汇总领域内的数据集&#xff0c;方便大家下载数据集&#xff0c;若无法下载可关注后私信领取。关注免费领取整理好的数据集资料&#xff01;今天分享…

error while loading shared libraries 找不到动态库问题如何解决

在使用 c 或 c 开发应用时&#xff0c;在启动程序时&#xff0c;有时会遇到这个错误&#xff0c;找不到动态库。这个时候&#xff0c;我们使用 ldd 来查看&#xff0c;发现可执行文件依赖的动态库显示为 not found。 1 实验代码 使用如下 3 个文件做实验。 hello.h 中声明了函…

Mysql使用中的性能优化——搭建Mysql的监测服务

大纲 环境安装配置Mysql安装设置root密码新增远程访问账户修改绑定地址重启 新增 MySQL Server Exporter 用户 安装启动mysqld_exporter安装启动新增配置启动直接启动以Service形式启动 安装启动Prometheus创建用户下载并解压修改配置启动 安装启动grafana安装启动 测试参考资料…