图像处理之计算物体的方向(C++)
创作时间:
作者:
@小白创作中心
图像处理之计算物体的方向(C++)
引用
CSDN
1.
https://blog.csdn.net/qq_45045175/article/details/139243169
在图像处理领域,计算物体的方向是一个常见的需求,例如在自动驾驶、机器人视觉和工业检测中。本文将介绍两种常用的方法:PCA(主成分分析)和Hu矩,帮助读者理解其原理并掌握具体的实现方法。
一、PCA获取物体主要方向
1. 原理
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算法的应用
热门推荐
装饰工程质量纠纷怎么解决
养肝从吃开始:四个饮食方法助力肝脏健康
AI工具:最受欢迎与最佳体验的探索
清凉琴苑:古琴指法如盖楼,宜慢不宜快
2024年广东省博物馆藏品管理业务培训在广州东莞成功举办
哀兵必胜,伤残的国足,反而有可能主场对阵澳大利亚拿分
高墙内的团圆:一盏灯,照亮归途
江南环境的自然景观和居住体验如何?这些因素如何影响居民的生活质量?
胃部肿瘤切除术后饮食指南:从流质到正常饮食的科学调理
什么是“缠腰龙”?不要慌!带状疱疹做好5点预防,降低患病风险
常见的三种高分子材料3D打印技术:FDM、SLS、SLA
未成年人办理身份证需要监护人陪同吗?
中国银行前2月收53张罚单,涉及金额超1100万元
孩子扁桃体和腺样体肥大,用不用切除?听听医生怎么说
吃什么补脾虚?10大必吃食物推荐
广西的奇怪习俗:人去世安葬了,为何几年后又挖出来重新安葬?
追溯英雄时代:吉尔伽美什与轩辕,谁更早?
谷歌DeepMind优化AI模型新思路,计算效率与推理能力兼得
研发团队中的角色定义和分工
生活与法︱舞蹈兴趣班闭店停业,没上几节课的消费者该吃哑巴亏吗?
材料化学表征检测方法大全
重庆长江三峡黄金游轮四日游攻略游记_长江黄金游船旅游线路推荐
如何找到并应对网络犯罪的法律策略
“身残志坚”的6位残疾艺人,个个才华横溢,有的不到1岁就失明
喀什市有哪些不可错过的旅游景点和特色体验?
解析一本二本大学差异:选拔标准与教育前景对比
申花背水一战,能否逆袭神户?亚冠精英联赛东亚区第8轮前瞻!
气膜体育馆建设解析:成本、因素与投资前景
职业健康体检项目及周期的法律规范与实施
甲鱼的养殖方法及注意事项(甲鱼养殖技术)