4.6 图像旋转
图像旋转一般是指将图像围绕某一指定点旋转一定的角度。旋转通常也会改变图像的大小。和4.2节中图像平移的处理一样,可以把转出显示区域的图像截去,也可以改变输出图像的大小以扩展显示范围。
4.6.1 以原点为中心的图像旋转
如图4.10所示,点P0(x0, y0)绕原点逆时针旋转角度θ到点P1(x1, y1)。
图4.10 旋转变换坐标图
令,则有:sinα=y0/L, cosα=x0/L
令L=1,则cosα=x0, sinα=y0
于是有:
从而得出旋转变换公式为:
相应地,其逆运算为:
4.6.2 以任意点为中心的图像旋转
在4.6.1小节中给出的旋转是以坐标原点为中心进行的,那么如何围绕任意的指定点来旋转呢?将平移和旋转操作相结合即可,即先进行坐标系平移,再以新的坐标原点为中心旋转,之后将新原点平移回原坐标系的原点。这一过程可归纳为以下3个步骤。
(1)将坐标系I变成II。
(2)将该点顺时针旋转θ角。
(3)将坐标系II变回I。
下面本书就以围绕图像中心的旋转为例,具体说明上述的变换过程。如图4.11所示,坐标系I以图像左上角点为原点,向右为x轴正方向,向下为y轴正方向;而坐标系II是以图像的中心为原点,向右为x轴正方向,向上为y轴正方向。那么坐标系I与坐标系II之间的转换关系如何呢?
图4.11 两种坐标系间的转换关系
设图像的宽为w,高为h,则容易得到:
相应的逆变换为:
至此,操作者已经实现了上述3个步骤中的第1步和第3步,再加上第2步的旋转变换就得到了围绕图像中心点旋转的最终变换矩阵,该矩阵实际上是3个变换步骤中分别用到的3个变换矩阵的级联。
其中,Wold、Hold、Wnew、Hnew分别表示原图像和新图像的宽和高。
上式的逆变换为:
这样,读者就可以根据上面的逆变换公式,按照算法4.1中的描述来实现围绕图像中心的旋转变换。类似地,可以进一步得出以任意点为中心的旋转变换。
4.6.3 图像旋转的实现
图像旋转变换的效果受具体插值方法的影响较为明显,本节给出的旋转的实现均采用最近邻插值,在4.7节中将给出采用不同的插值算法时图像旋转变换的效果比较。
1.MATLAB实现
可通过4.6.2中学习的方法设置适当的变换结构TFORM,从而调用imtransform ()函数来实现以任意点为中心的图像旋转。此外,MATLAB还专门提供了围绕图像中心的旋转变换函数imrotate(),其调用方式如下。
B=imrotate(A, angle, method, 'crop');
• A是要旋转的图像。
• angle为旋转角度,单位为度,如为其指定一个正值,则imrotate()函数按逆时针方向旋转图像。
• 可选参数method为imrotate()函数指定的插值方法。
• 'crop’选项会裁剪旋转后增大的图像,使得到的图像和原图大小一致。
下面给出图像旋转的MATLAB编码实现。
% 围绕中心点的图像旋转 A=imread('girl.bmp'); %最近邻插值法逆旋转30°,并剪切图像 B=imrotate(A,30, 'nearest', 'crop'); subplot(1,2,1), imshow(A); title(’原图像’); subplot(1,2,2), imshow(B); title(’逆时针旋转30°');
程序运行结果如图4.12所示。
图4.12 旋转变换效果图
2.Visual C++实现
利用Visual C++实现以原点为中心的图像的旋转代码如下。
/******************* void CImgProcess::Rotate(CImgProcess * pTo, float ang) 功能: 以原点为中心的图像旋转 注: 围绕左上顶点顺时针旋转,图像范围不变 参数: CImgProcess * pTo:处理后得到的图像的CImgProcess指针 float ang:顺时针旋转角度,单位度,要求ang>=0 && ang<=360 返回值: 无 *******************/ void CImgProcess::Rotate(CImgProcess* pTo, float ang) { int nHeight = pTo->GetHeight(); int nWidth = pTo->GetWidthPixel(); int i, j; //目标图像坐标 int u, v; //源图像坐标 for(i=0; i<nWidth; i++) { for(j=0; j<nHeight; j++) { u=int(i*cos(ang*PI/180)+j*sin(ang*PI/180)+0.5); v=int(j*cos(ang*PI/180)-i*sin(ang*PI/180)+0.5); if(u<nWidth && v<nHeight && u>=0 && v>=0) pTo->SetPixel(i, j, GetPixel(u, v)); else pTo->SetPixel(i, j, RGB(0,0,0)); }//for j }//for i }
Rotate()函数的调用方式如下所示。
// 调用Rotate()函数实现图像旋转 imgInput.Rotate(&imgOutput, iRotateAngle); // 将结果返回给文档类 pDoc->m_Image = imgOutput;
读者可以通过示例程序DIPDemo中的菜单命令“几何变换→图像旋转”来观察处理效果。