当前位置:C++技术网 > 资讯 > opencv编程:14 实现图像旋转

opencv编程:14 实现图像旋转

更新时间:2016-05-09 19:47:57浏览次数:1+次

  旋转一般是指将图像围绕某一指定点旋转一定的角度,图像旋转后会有一部分图像转出显示区域,可以截图那部分,也可以改变图像的尺寸使得图像显示完全。

  如下图,点P0(x0,y0)绕原点逆时针旋转一定角度到点P1(x1,y1).

                          

  这里以绕原点进行旋转为例。在图像处理时,图像的坐标系原点是左上角的起始点,所以理解图像旋转时,要将坐标系转化为图像坐标系。

opencv函数旋转变换
  opencv中进行图像旋转的方法,旋转所使用的是角度,角度值为正数时是逆时针旋转,为负数时是顺时针旋转。

Opencv函数的代码
Mat image=imread("chuli.jpg");
float map[6];
Mat map_matrix;   //变换矩阵
map_matrix=getRotationMatrix2D(Point(0,0),-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自带的方法,是要利用旋转中心、旋转角度和缩放尺度来建立一个变换矩阵,通过变换矩阵对图像进行旋转。这个方法不改变图像的大小,用黑色来填充图像边界外的区域,丢弃超出显示区域外的部分。这里要进行顺时针旋转,所以角度是负数。

opencv函数旋转结果,左边图像为原图

                         

几何变换旋转

  结合上述旋转变换图示,利用正余弦函数为每个像素点映射一个新位置,映射后的非整数像素位置取为整数像素处理。C++中的正余弦使用的是弧度,弧度值为正数表示逆时针旋转,负数表示顺时针旋转。

不改变图像尺寸旋转变换

  这里不改变图像尺寸的方法是直接在原图像上旋转,这就要考虑像素值覆盖的情况,即先旋转的像素不能把未旋转的像素覆盖掉。所以要根据旋转方向选取行变换还是列变换,从哪一行或哪一列开始变换。下面的例子是顺时针旋转,为避免像素覆盖,使用列变换,列x=0是起始变换列。

示例代码
Mat image=imread("chuli.jpg");
int x1,y1,i,j;
double pi=3.14159265358979323846264;
double angle=pi/12;  //弧度
for (i=0;i<image.cols;i++)
{
	for (j=0;j<image.rows;j++)
	{
		x1=i*cos(angle) - j*sin(angle);   //旋转后的x坐标
		y1=j*cos(angle) + i*sin(angle);   //旋转后的y坐标
		if (x1>=0 && x1<image.cols && y1>=0 && y1<image.rows)   //丢掉超出区域的点
		{
			image.at<Vec3b>(Point(x1,y1))=image.at<Vec3b>(Point(i,j));
		}
		image.at<Vec3b>(Point(i,j))=0;    //旋转后的像素设为黑色
	}
}
namedWindow("tatote");
imshow("tatote",image);
waitKey(0);

 在这个方法中,把旋转后的像素设为黑色,这样就可以在原图像上只显示旋转后的图像,除去了旋转后图像边界外的区域,超出显示区域的部分不显示。

  下图是不改变尺寸的图像几何旋转结果,与opencv函数处理结果相比,图像上有一些黑点,这是因为做了旋转变换之后的像素点被设为黑色,而后面做旋转变换的点未必会映射到所有已设为黑色的像素点的位置,所以有些像素被设为了黑色。

                                        

改变图像尺寸的几何旋转变换

 上面是不改变图像尺寸的旋转方法,图像会有一部分无法显示。改变图像尺寸,可以让旋转图像整体都显示出来,也比较直观。

 首先,要建立一幅新图像,图像的大小要根据原图像尺寸与旋转角度进行计算,计算方式如下图描述,

在上图中,旋转角度是a,绕左上角的点逆时针旋转,根据几何性质,计算新图像的尺寸是,

对于本文中使用的图像,如下图所示,

                         

  黑色框表示新建图像的边缘,棕色框表示原图像顺时针旋转后的边界,红色竖线表示原图像左边界所在的直线。红色竖线左边的部分是图像旋转后超出原边界所在直线的区域,为了将旋转后的图像完全显示在新建的图像中,旋转后的像素点的x坐标要进行右移,右移的距离是左边超出部分的宽度。

示例代码
Mat image=imread("chuli.jpg");
int x2,y2,i,j;
double pi=3.14159265358979323846264;
double angle=pi/12;
int dx = (int)(image.cols*cos(angle) + image.rows*sin(angle)); //新图像的宽度
int dy = (int)(image.cols*sin(angle) + image.rows*cos(angle)); //新图像的长度
Mat dst(dy,dx,CV_8UC3,Scalar(0));  //新建图像,填充为黑色
for (i=0;i<image.cols;i++)
{
	for (j=0;j<image.rows;j++)
	{
		x2=i*cos(angle) - j*sin(angle) + image.rows*sin(angle);//x坐标右移
		y2=j*cos(angle) + i*sin(angle);
		dst.at<Vec3b>(Point(x2,y2))=image.at<Vec3b>(Point(i,j));
	}
}
namedWindow("dst");
imshow("dst",dst);
waitKey(0);

  这种方法可以不考虑是进行列变换还是行变换,因为是将变换位置映射到了新的图像中。

 改变尺寸图像几何旋转结果图如下,这种方法变换后的图像同样也是有一些黑点,原因也是一些黑点无法被映射到。