当前位置:C++技术网 > 资讯 > opencv编程:16 图像绕任意点进行旋转

opencv编程:16 图像绕任意点进行旋转

更新时间:2016-05-30 22:52:01浏览次数:1+次

  以下图为例,图像的原点坐标是在左上角,若以图中的点(x,y)为中心进行图像旋转,可以将图像坐标进行平移,使得点(x,y)平移到图像坐标原点,即左移x距离,上移y距离,然后进行图像旋转,旋转后的图像右移x距离,下移y距离,便可得到以点(x,y)为中心进行旋转的图像。

下面以图像中心点为例分别介绍三种以任意点进行图像旋转的方法:opencv中的函数处理,几何旋转,基于插值的几何旋转。

opencv函数处理

示例代码
Mat image=imread("chuli.jpg");
int dx=image.cols/2;   //计算图像中心
int dy=image.rows/2;
double pi=3.141592653589793;
double angle=pi/12;  //旋转角度

float map[6];
Mat map_matrix;
map_matrix=getRotationMatrix2D(Point(dx,dy),-15,1.0);  //旋转中心,角度,缩放比例
Mat src(image.rows,image.cols,CV_8UC3);
warpAffine(image,src,map_matrix,Size(image.cols,image.rows));
namedWindow("src");
imshow("src",src);
waitKey(0);

使用opencv封装的函数做旋转处理很方便,可以指定任意中心,只需更改一下getRotationMatrix2D()中第一个参数的中心点坐标即可。

变换效果:

                

几何旋转

  之前在介绍以原点为中心进行图像旋转的时候,做了不创建新的图像在原图像上进行旋转的变换,需要考虑映射后的像素点不会对原图中未进行变换的点造成影响。在原图上以任意点为中心进行旋转,要考虑的问题比较多,中心点上方与下方涉及到的像素覆盖情况要分别考虑。这里的示例,是创建新的图像,原图像的旋转映射到新的图像中,不必考虑映射到的像素点会覆盖原图中为进行变换的点。

示例代码
Mat image=imread("chuli.jpg");
Mat dst(image.rows,image.cols,CV_8UC3,Scalar(0));  //创建新图像
int dx=image.cols/2;   //计算图像中心
int dy=image.rows/2;
double pi=3.141592653589793;
double angle=pi/12;
int x,y,x1,y1;  //x,y是原图中图像的像素点坐标;x1,y1是映射后的像素点坐标

for (x=0;x<image.cols;x++)
{
	for (y=0;y<image.rows;y++)
	{
		x1=(x-dx)*cos(angle)-(y-dy)*sin(angle)+dx;
		y1=(y-dy)*cos(angle)+(x-dx)*sin(angle)+dy;
		if (x1>=0 && x1<image.cols && y1>=0 && y1<image.rows)//舍弃映射超出图像大小的点
		{
			dst.at<Vec3b>(Point(x1,y1))=image1.at<Vec3b>(Point(x,y));
		}
	}
}
namedWindow("Initial");
imshow("Initial",dst);
waitKey(0);

变换效果如下,由于原图中有些像素点会映射到同一个点,新图中有些点是映射不到的,所以映射后的图像上会有一些黑点,下面的插值方法可以避免这一问题。

                                   

插值旋转 

  以任意点为中心的插值旋转方法是将新创建的图像映射回原图,计算出新图中每个点对应原图中的像素值,对于映射后超出范围的点值置为0,映射后不是整数像素的点,去临近的整数像素点的值近似表示采样点的像素值。

示例代码
Mat image=imread("chuli.jpg");
Mat dst1(image.rows,image.cols,CV_8UC3,Scalar(0)); //创建新图像
int dx=image.cols/2; //计算图像中心
int dy=image.rows/2;
double pi=3.141592653589793;
double angle=pi/12;
int x,y,x1,y1; //x,y是原图中图像的像素点坐标;x1,y1是映射后的像素点坐标

for ( x1=0;x1<dst1.cols;x1++)
{
	for ( y1=0;y1<dst1.rows;y1++)
	{
		x = (x1-dx)*cos(angle) + (y1-dy)*sin(angle)+dx;
		y = (y1-dy)*cos(angle) - (x1-dx)*sin(angle)+dy;
		if (x>=0 && x<image.cols && y>=0 && y<image.rows)//映射后超出原图范围的点舍弃
		{
			dst1.at<Vec3b>(Point(x1,y1)) = image.at<Vec3b>(Point(x,y));
		}
	}
}
namedWindow("dst1");
imshow("dst1",dst1);
waitKey(0);

变换效果如下,可以解决图像中有黑点的问题,但图像边缘有锯齿状,这跟选择的插值方法有关。