图像处理之计算物体的方向(C++)

news2025/2/25 17:38:03

图像处理之计算物体的方向(C++)


文章目录

  • 图像处理之计算物体的方向(C++)
  • 前言
  • 一、PCA获取物体主要方向
    • 1.原理
    • 2.代码实现
  • 二、Hu矩获取物体主要方向
    • 1.原理
    • 2.代码实现
  • 总结


前言

在图像处理中,物体的方向(倾斜角度)计算的应用非常常见,总结如下方法:PCA获得物体的主要方向以及Hu矩计算物体的主要方向。


一、PCA获取物体主要方向

1.原理

PCA的主要思想是寻找到数据的主轴方向,由主轴构成一个新的坐标系,这里的维数可以比原维数低,然后数据由原坐标系向新的坐标系投影(可以理解为一根轴最能代表物体的方向(红色),另外一根轴最不能代表物体的方向(绿色)),这个投影的过程就可以是降维的过程。(具体推导略,可以参考其他博客)
PCA

2.代码实现

#include <opencv.hpp>
#include <iostream>

struct Orientation
{
	cv::Point centroid;	//重心
	double angle;		//倾斜角度
};

/*
* @param const std::vector<cv::Point>& pts 轮廓点集
* @param Orientation& orientation	物体的主要方向结果
* @brief 计算物体的主要方向
*/
void pca_getOrientation(const std::vector<cv::Point>& pts, Orientation& orientation)
{
	// 构建pca数据,将轮廓信息转换为Mat数据结构,后续pca处理需要Mat数据结构
	cv::Mat contoursMat(pts.size(), 2, CV_64FC1);
	for (int i = 0; i < pts.size(); i++)
	{
		contoursMat.at<double>(i, 0) = pts[i].x;
		contoursMat.at<double>(i, 1) = pts[i].y;
	}

	// 执行pca分析
	cv::PCA pca(contoursMat, cv::Mat(), 0);
	// 获得最主要分量(均值),即图像轮廓中心
	orientation.centroid = cv::Point(pca.mean.at<double>(0, 0), pca.mean.at<double>(0, 1));
	//存储特征向量
	cv::Point2d eigen_vecs= cv::Point2d(pca.eigenvectors.at<double>(0, 0), pca.eigenvectors.at<double>(0, 1));
	orientation.angle = atan2(eigen_vecs.y, eigen_vecs.x);
	std::cout << orientation.angle <<std:: endl;
}

int main()
{
	// 读取图片
	std::string filepath = "F://work_study//algorithm_demo//orientation.jpg";
	cv::Mat src = cv::imread(filepath, cv::IMREAD_GRAYSCALE);
	if (src.empty())
	{
		return -1;
	}

	cv::Mat dst;
	cv::threshold(src, dst, 10, 255, cv::THRESH_BINARY_INV);

	// 寻找轮廓
	std::vector<std::vector<cv::Point>> contours;
	std::vector<cv::Vec4i> hierarchy;
	cv::findContours(dst, contours, hierarchy,cv::RETR_LIST, cv::CHAIN_APPROX_NONE);
	cv::cvtColor(dst, dst, cv::COLOR_GRAY2BGR);

	// 轮廓分析
	for (size_t i = 0; i < contours.size(); i++)
	{
		cv::drawContours(dst, contours, i, cv::Scalar(0, 255, 0), 2, 8, hierarchy, 0);
		Orientation orien;
		pca_getOrientation(contours[i], orien);
		cv::circle(dst, orien.centroid, 3, cv::Scalar(255, 0, 0),-1);
		cv::line(dst, orien.centroid, orien.centroid + cv::Point(200, 200 * tan(orien.angle)),cv::Scalar(255,0,0),2);
	}
	cv::imshow("dst", dst);
	cv::waitKey(0);
	return 0;
}

结果图

二、Hu矩获取物体主要方向

1.原理

如果把图像看成是一块质量密度不均匀的薄板,其图像的灰度分布函数f(x,y)就是薄板的密度分布函数,则其各阶矩有着不同的含义,如零阶矩表示它的总质量;一阶矩表示它的质心;二阶矩又叫惯性矩,表示图像的大小和方向。
一阶矩
二阶矩
研究表明,只有基于二阶矩的不变矩对二维物体的描述才是真正的与旋转、平移和尺度无关的。较高阶的矩对于成像过程中的误差,微小的变形等因素非常敏感,所以相应的不变矩基本上不能用于有效的物体识别。即使是基于二阶矩的不变矩也只能用来识别外形相差特别大的物理,否则他们的不变矩会因为很相似而不能识别。
**在OpenCV中,还可以很方便的得到Hu不变距,Hu不变矩在图像旋转、缩放、平移等操作后,仍能保持矩的不变性,所以有时候用Hu不变距更能识别图像的特征。**不变矩能够描述图像整体特征就是因为它具有平移不变形、比例不变性和旋转不变性等性质。

2.代码实现

#include <opencv.hpp>
#include <iostream>

struct Orientation
{
	cv::Point centroid;	//重心
	double angle;		//倾斜角度
};

int main()
{
	// 读取图片
	std::string filepath = "F://work_study//algorithm_demo//orientation.jpg";
	cv::Mat src = cv::imread(filepath, cv::IMREAD_GRAYSCALE);
	if (src.empty())
	{
		return -1;
	}

	cv::Mat dst;
	cv::threshold(src, dst, 10, 255, cv::THRESH_BINARY_INV);

	// 寻找轮廓
	std::vector<std::vector<cv::Point>> contours;
	std::vector<cv::Vec4i> hierarchy;
	cv::findContours(dst, contours, hierarchy,cv::RETR_LIST, cv::CHAIN_APPROX_NONE);
	cv::cvtColor(dst, dst, cv::COLOR_GRAY2BGR);

	// 轮廓分析
	// 计算每个轮廓所有矩
	std::vector<cv::Moments> mu(contours.size());    // 创建一个vector,元素个数为contours.size()
	for (int i = 0; i < contours.size(); i++)
	{
		mu[i] = moments(contours[i], false);   // 获得轮廓的所有最高达三阶所有矩
	}
	// 计算轮廓的质心
	std::vector<Orientation> oriens(contours.size());
	for (size_t i = 0; i < contours.size(); i++)
	{
		cv::drawContours(dst, contours, i, cv::Scalar(0, 255, 0), 2, 8, hierarchy, 0);
		Orientation orien;
		cv::Point2d center(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);		 // 质心的 X,Y 坐标:(m10/m00, m01/m00)
		// 计算方向
		double a = mu[i].m20 / mu[i].m00 - center.x * center.x;
		double b = 2*(mu[i].m11 / mu[i].m00 - center.x * center.y);
		double c = mu[i].m02 / mu[i].m00 - center.y * center.y;
		orien.angle = atan2(b, (a - c))/2;
		orien.centroid = cv::Point(static_cast<int>(center.x), static_cast<int>(center.y));   // 质心的 X,Y 坐标:(m10/m00, m01/m00)
		cv::circle(dst, orien.centroid, 3, cv::Scalar(255, 0, 0), -1);
		cv::line(dst, orien.centroid, orien.centroid + cv::Point(200, 200 * tan(orien.angle)),cv::Scalar(255,0,0),2);
	}
	cv::imshow("dst", dst);
	cv::waitKey(0);
	return 0;
}

总结

本文总结了两种计算物体主要方向的方法,分别是PCA以及HU矩实现的计算物体主要方向,欢迎大家有问题交流。

参考资料:
opencv学习——Moments()函数,计算物体形状方向
图像的矩,以及利用矩求图像的重心,方向

[opencv实战——PCA算法的应用 (https://www.cnblogs.com/xyf327/p/14824106.html#!comments)

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

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

相关文章

YOLOv10介绍与推理--图片和视频演示(附源码)

导 读 本文主要对YOLOv10做简单介绍并给出推理图片和视频的步骤演示。 YOLOv10简介 YOLOv10是清华大学的研究人员在Ultralytics Python包的基础上&#xff0c;引入了一种新的实时目标检测方法&#xff0c;解决了YOLO 以前版本在后处理和模型架构方面的不足。通过消除非最大抑…

快速排序算法备考

快排模板 快速排序(快排) (C语言实现)_c语言快速排序_Brant_zero2022的博客-CSDN博客 快排使用递归来实现 关键思想:划分 //划分 int partion(int A[],int L,int R){int midA[L];while(L<R){//每一次划分:左边元素<枢轴元素<右边元素//R往前找&#xff0c;直到找到一…

ROS for LabVIEW:实现LabVIEW与ROS的无缝集成

ROS for LabVIEW是由Tufts大学开发的一套VI集合&#xff0c;旨在实现LabVIEW与ROS&#xff08;Robot Operating System&#xff09;的无缝集成。ROS是一个灵活的机器人软件框架&#xff0c;而LabVIEW则是一种强大的图形化编程工具。这个工具包的推出使得LabVIEW用户能够直接与R…

Neo4j安装部署及python连接neo4j操作

Neo4j安装部署及python连接neo4j操作 Neo4j安装和环境配置 安装依赖库&#xff1a; sudo apt-get install wget curl nano software-properties-common dirmngr apt-transport-https gnupg gnupg2 ca-certificates lsb-release ubuntu-keyring unzip -y 增加Neo4 GPG key&…

短视频真人配音:成都科成博通文化传媒公司

短视频真人配音&#xff1a;情感传递的新维度 随着数字化媒体的飞速发展&#xff0c;短视频已经成为人们日常生活中不可或缺的一部分。而在这个视觉盛宴的时代&#xff0c;真人配音的加入为短视频注入了新的活力&#xff0c;不仅丰富了内容形式&#xff0c;更使得情感传递达到…

Java面试八股之Synchronized锁升级的原理

Synchronized锁升级的原理 Synchronized锁升级是Java为了提高并发性能而引入的一项优化措施&#xff0c;这一机制主要发生在JDK 1.6及之后的版本中。Synchronized锁升级旨在减少锁带来的性能开销&#xff0c;通过从低开销的锁逐步升级到高开销的锁&#xff0c;以适应不同的竞争…

【吊打面试官系列】Java高并发篇 - 线程的调度策略?

大家好&#xff0c;我是锋哥。今天分享关于 【线程的调度策略?】面试题&#xff0c;希望对大家有帮助&#xff1b; 线程的调度策略? 线程调度器选择优先级最高的线程运行&#xff0c;但是&#xff0c;如果发生以下情况&#xff0c;就会终止线程的运行&#xff1a; 1、线程体…

I.MX6ULL的蜂鸣器实验-GPIO输入实验

系列文章目录 驱动开发中引入私有数据的原因 I.MX6ULL的蜂鸣器实验-GPIO输入实验 系列文章目录一、前言二、按键输入简介三、硬件原理四、程序编写4.1主要编写内容4.2程序编写前提工作4.3编写gpio驱动模块4.4编写按键KEY驱动模块 五、编译下载验证5.1 编写 Makefile 和链接脚本…

C++ 头文件优化

C 是一种灵活的语言&#xff0c;所以需要一种积极的方法来分析和减少编译时依赖。一种常见的达到这个目的的方法是&#xff0c;将依赖从头文件里转移到源代码文件里。实现这个目的的方法叫做提前声明。 简而言之&#xff0c;这些声明告诉编译器某个函数接受和返回哪些参数&…

用友NC linkVoucher SQL注入漏洞复现

0x01 产品简介 用友NC是由用友公司开发的一套面向大型企业和集团型企业的管理软件产品系列。这一系列产品基于全球最新的互联网技术、云计算技术和移动应用技术,旨在帮助企业创新管理模式、引领商业变革。 0x02 漏洞概述 用友NC /portal/pt/yercommon/linkVoucher 接口存在…

YOLOv8+PyQt5鸟类检测系统完整资源集合(yolov8模型,从图像、视频和摄像头三种路径识别检测,包含登陆页面、注册页面和检测页面)

资源包含可视化的鸟类检测系统&#xff0c;基于最新的YOLOv8训练的鸟类检测模型&#xff0c;和基于PyQt5制作的可视化鸟类检测系统&#xff0c;包含登陆页面、注册页面和检测页面&#xff0c;该系统可自动检测和识别图片或视频当中出现的各种鸟类&#xff0c;以及自动开启摄像头…

腾盾科创无人机亮相第二十四届新疆农机博览会引发观展热潮

5月25日&#xff0c;第二十四届新疆农业机械博览会、2024“一带一路”智慧农业大会&#xff08;以下简称新疆农机博览会&#xff09;在新疆国际会展中心开幕。展会现场多种农牧业的新装备、新技术集中亮相&#xff0c;其中首次在新疆农机博览会上亮相的腾盾科创无人机产品引发观…

视觉语言模型详解【VLM】

视觉语言模型&#xff08;Visual Language Models&#xff09;是可以同时从图像和文本中学习以处理许多任务的模型&#xff0c;从视觉问答到图像字幕。在这篇文章中&#xff0c;我们将介绍视觉语言模型的主要组成部分&#xff1a;概述&#xff0c;了解它们的工作原理&#xff0…

MySQL事务篇2:InnoDB引擎

InnoDB是MySQL的默认存储引擎&#xff0c;支持ACID事务、行级锁定和外键约束&#xff0c;通过多版本并发控制&#xff08;MVCC&#xff09;实现高并发性能。InnoDB使用聚簇索引存储数据&#xff0c;具备崩溃恢复能力&#xff0c;确保数据一致性和完整性。其主要特性包括数据和索…

谷粒商城实战(029 业务-订单支付模块-支付宝支付2)

Java项目《谷粒商城》架构师级Java项目实战&#xff0c;对标阿里P6-P7&#xff0c;全网最强 总时长 104:45:00 共408P 此文章包含第305p-第p310的内容 代码编写 前端代码 这里使用的是jsp 在这里引用之前配置的各种支付信息 在AlipayConfig.java里 这里是调用阿里巴巴写…

【onnx问题解决】关键词:found at least two devices、torch.onnx.export

关键词&#xff1a;Expected all tensors to be on the same device, but found at least two devices, cpu and cuda:0! 报错&#xff1a; [34m[1mONNX:[0m export failure ❌ 3.8s: Expected all tensors to be on the same device, but found at least two devices, cpu an…

【R语言】获取任意颜色的HTML 颜色代码、十六进制颜色代码、 RGB代码

网站来源&#xff1a; https://htmlcolorcodes.com/ 界面如下所示&#xff1a; 通过鼠标任意选择不同的颜色&#xff0c;就能获取该色的十六进制代码、RGB代码等。 除此之外&#xff0c;还提供了一些常用颜色的便捷选项,如下&#xff1a; 任意选择一种颜色&#xff0c;即可出…

Java开发快速入门

Java执行流程分析 .java文件 **(源文件)** ---javac编译--->.class文件 **(字节码文件)** ---java运行--->结果 运行的本质: .java文件称之为源文件 .class文件称之为字节码文件 什么是编译 javac Hello.java 1. 有了java源文件, 通过编译器将其编译成JVM可以识别的…

【吊打面试官系列】Java高并发篇 - AQS 支持几种同步方式 ?

大家好&#xff0c;我是锋哥。今天分享关于 【AQS 支持几种同步方式 &#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; AQS 支持几种同步方式 &#xff1f; 1、独占式 2、共享式 这样方便使用者实现不同类型的同步组件&#xff0c;独占式如 ReentrantLock&…

C语言动态顺序表结构的创建、初始化结构、尾插、尾删、头插、头删、指定位置插入、指定位置删除、找指定数值下标等的介绍

文章目录 前言一、 结构创建二、 初始化结构三、 打印动态顺序表四、 销毁动态顺序表五、 尾插六、尾删七、 头插八、 头删九、指定位置插入十、指定位置删除十一、找指定数值下标总结 前言 C语言动态顺序表结构的创建、初始化结构、尾插、尾删、头插、头删、指定位置插入、指…