OpenCV中对的旋转一些思考

本文探讨了在OpenCV中解决图像轮廓旋转问题的三种方法:迭代法、特征椭圆法和PCA主成分分析法。通过实例展示了每种方法的实现过程及计算结果,分析了各自的效率和精度,推荐在特定条件下选择合适的方法。
摘要由CSDN通过智能技术生成

目录

1. 问题描述

2. “旋转”的三种解法

2.1 应用迭代法进行求解

2.2 应用特征椭圆进行求解

2.3 应用PCA主成分分析进行求解

3. 归纳与比较


1.问题描述

数字图像处理是一门很有意思的学问,在现实生活中往往一个很简单的问题在数字图像中有时会非常复杂,旋转便是一类非常有意思的问题。如何在离散图像中高精度、快速求解图像的旋转角度,这个问题我思考了很长时间,下面会使用三种不同的算法逐一计算轮廓的旋转。

如图1-1所示,这是一幅鸟的轮廓:

如果这副图像发生了旋转,会出现什么样的情况呢?如图1-2所示,绿色的线表示旋转后的轮廓,在这里我设置了旋转角度为50°,旋转中心为轮廓的形心。

                                         

这也就是说,给定白色和绿色的两条轮廓,我们需要解出它们的旋转角度(50°);

2.旋转的三种解法

2.1 应用迭代法进行求解

算法的基本参数:

1.给定轮廓相似程度的度量方式,这里我采用了ShapeContextDistance;

2.给定旋转的步长,也就是每次匹配时绿色轮廓旋转的变化量,这里为了实验方便步长为10°;

3.给定迭代的终止条件,这里为了快速迭代,迭代次数为10;

如何迭代:

每次旋转后计算ShapeContextDistance,达到阈值或者达到迭代上限即跳出循环。

code:

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

using namespace std;
using namespace cv;

//计算图像上所有的轮廓,并计算它的质心和对角线长度
void FindBlobs(Mat img, vector<vector<Point>> &contours,
                         vector<Point2f> &MassCentre, vector<float>&DiagonalLength)
{
	//判断图像是否为8位单通道
	if (img.empty() || img.depth() != CV_8UC1)
	{
		cout << "Invalid Input Image!";
		exit(-1);
	}
	//计算轮廓
	vector<Vec4i> hierarchy;
	findContours(img, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
	//计算轮廓的最小外接矩形
	vector<Rect> boundRect(contours.size());
	vector<Moments> mu(contours.size());
	for (size_t i = 0; i < contours.size(); i++)
	{
		//计算外界矩形
		boundRect[i] = boundingRect(Mat(contours[i]));
		//计算轮廓矩
		mu[i] = moments(contours[i], false);
                                             //当binaryImage=true时,所有的非零值都视为1
		//计算质心
		MassCentre.push_back(Point2f(static_cast<float>(mu[i].m10 / mu[i].m00),
                                   static_cast<float>(mu[i].m01 / mu[i].m00)));
		//计算外接矩形的对角距离
		DiagonalLength.push_back((float)norm(boundRect[i].tl() 
                                                         - boundRect[i].br()));
	}
}

//对轮廓进行平移变化
void TransformContour(vector<vector<Point>> contours,
                       vector<vector<Point>> &contours_Trans, Vec2f Translate)
{
	//判断
	if (contours.size() == 0)
	{
		cout << "Invalid input!";
		exit(-1);
	}
	//平移变换
	contours_Trans = contours;
	for (size_t i = 0; i < contours.size(); i++)
	{
		for (int idx = 0; idx < contours[i].size(); idx++)
		{
			contours_Trans[i][idx] = Point(contours[i][idx].x
                             + Translate(0), contours[i][idx].y + Translate(1));
		}
	}
}

//旋转轮廓
//1.基于仿射变化的2阶方阵M计算旋转位置
Point RotatePoint(const Mat &M, const Point &p)
{
	Point2f rp;
	rp.x = (float)(M.at<double>(0, 0)*p.x + M.at<double>(0, 1)*p.y 
                                                          + M.at<double>(0, 2));
	rp.y = (float)(M.at<double>(1, 0)*p.x + M.at<double>(1, 1)*p.y 
                                                          + M.at<double>(1, 2));
	return rp;
}
//2.计算选择轮廓
void RotateContour(vector<vector<Point>> contours,
           vector<vector<Point>> &contours_Rotated, double Angle, Point2f Centre)
{
	//判断
	if (contours.size() == 0)
	{
		cout << "Invalid input!";
		exit(-1);
	}
	//计算仿射矩阵
	Mat M= getRotationMatrix2D(Centre, Angle, 1.0);
	//计算旋转轮廓
	contours_Rotated = contours;
	for (size_t i = 0; i < contours.size(); i++)
	{
		for (int idx = 0; idx < contours[i].size(); idx++)
		{
			contours_Rotated[i][idx] = RotatePoint(M, 
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值