![数字图像处理与机器视觉:Visual C++与Matlab实现(第2版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/381/22651381/b_22651381.jpg)
4.6 图像旋转
图像旋转一般是指将图像围绕某一指定点旋转一定的角度。旋转通常也会改变图像的大小。和4.2节中图像平移的处理一样,可以把转出显示区域的图像截去,也可以改变输出图像的大小以扩展显示范围。
4.6.1 以原点为中心的图像旋转
如图4.10所示,点P0(x0, y0)绕原点逆时针旋转角度θ到点P1(x1, y1)。
![](https://epubservercos.yuewen.com/E09B87/11229143803763806/epubprivate/OEBPS/Images/figure_0115_0001.jpg?sign=1739271079-PVs0lEHmBrn0yYHFGZHYHelBIM5yfmqb-0-e5e2a644b7e1ae6a82b44d84790b19f9)
图4.10 旋转变换坐标图
令,则有:sinα=y0/L, cosα=x0/L
![](https://epubservercos.yuewen.com/E09B87/11229143803763806/epubprivate/OEBPS/Images/figure_0115_0003.jpg?sign=1739271079-0w8d5i1eB5JGOj3sIlq0Ld6xBdB5lDba-0-59ec49bfe67645d0c1cc5b74adf9be68)
![](https://epubservercos.yuewen.com/E09B87/11229143803763806/epubprivate/OEBPS/Images/figure_0115_0004.jpg?sign=1739271079-ZdFTrRGdkev1YOf3n4JGDyuc0kCVmcKu-0-4b6516abd8eca9e7b629fa57bdec2d8e)
令L=1,则cosα=x0, sinα=y0
于是有:
![](https://epubservercos.yuewen.com/E09B87/11229143803763806/epubprivate/OEBPS/Images/figure_0115_0005.jpg?sign=1739271079-nhWuXfMpNrzmaGz8F4FlBZgC8t8gddqs-0-49a705d1d2460d91a441f68c754cf64c)
从而得出旋转变换公式为:
![](https://epubservercos.yuewen.com/E09B87/11229143803763806/epubprivate/OEBPS/Images/figure_0115_0006.jpg?sign=1739271079-u3NZ85Ikam7hP1COLbtcbrFajF3RQl2P-0-74969febc53d81cf7e6e063a1d106528)
相应地,其逆运算为:
![](https://epubservercos.yuewen.com/E09B87/11229143803763806/epubprivate/OEBPS/Images/figure_0115_0007.jpg?sign=1739271079-03FA4coRGByEgC3vIBsauvksdWgQNo3L-0-5d54f831b78ffeec9266ad34ddb6d694)
4.6.2 以任意点为中心的图像旋转
在4.6.1小节中给出的旋转是以坐标原点为中心进行的,那么如何围绕任意的指定点来旋转呢?将平移和旋转操作相结合即可,即先进行坐标系平移,再以新的坐标原点为中心旋转,之后将新原点平移回原坐标系的原点。这一过程可归纳为以下3个步骤。
(1)将坐标系I变成II。
(2)将该点顺时针旋转θ角。
(3)将坐标系II变回I。
下面本书就以围绕图像中心的旋转为例,具体说明上述的变换过程。如图4.11所示,坐标系I以图像左上角点为原点,向右为x轴正方向,向下为y轴正方向;而坐标系II是以图像的中心为原点,向右为x轴正方向,向上为y轴正方向。那么坐标系I与坐标系II之间的转换关系如何呢?
![](https://epubservercos.yuewen.com/E09B87/11229143803763806/epubprivate/OEBPS/Images/figure_0116_0001.jpg?sign=1739271079-mn6OrNA8v25kHqabITbjriwoQGlj8iku-0-8a623f7ea1165261eda543a5eeefc745)
图4.11 两种坐标系间的转换关系
设图像的宽为w,高为h,则容易得到:
![](https://epubservercos.yuewen.com/E09B87/11229143803763806/epubprivate/OEBPS/Images/figure_0116_0002.jpg?sign=1739271079-5KNWJz7CWGRjIozPKjEwUTa7qgs5iKzW-0-fa447d2530ce10d0008ac0dc3e35dbda)
相应的逆变换为:
![](https://epubservercos.yuewen.com/E09B87/11229143803763806/epubprivate/OEBPS/Images/figure_0116_0003.jpg?sign=1739271079-9rM1oySZO5YDxNjdVbY4su1kCWg0RDnY-0-1fe565334fbb4b7f7c202940c69f2cd6)
至此,操作者已经实现了上述3个步骤中的第1步和第3步,再加上第2步的旋转变换就得到了围绕图像中心点旋转的最终变换矩阵,该矩阵实际上是3个变换步骤中分别用到的3个变换矩阵的级联。
![](https://epubservercos.yuewen.com/E09B87/11229143803763806/epubprivate/OEBPS/Images/figure_0116_0004.jpg?sign=1739271079-ugMvfNSkZKrgnVONtD1d0cOw4mYDr4NM-0-b146c3776aa80ceaf420289005013c88)
其中,Wold、Hold、Wnew、Hnew分别表示原图像和新图像的宽和高。
上式的逆变换为:
![](https://epubservercos.yuewen.com/E09B87/11229143803763806/epubprivate/OEBPS/Images/figure_0116_0005.jpg?sign=1739271079-tv9PPxhZP4ARN19PEvoa96ULg7DjuDKG-0-49d66a7354186d16f4c158f6a0ea8e8d)
这样,读者就可以根据上面的逆变换公式,按照算法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所示。
![](https://epubservercos.yuewen.com/E09B87/11229143803763806/epubprivate/OEBPS/Images/figure_0117_0001.jpg?sign=1739271079-FwGoj4hvFH6LMs7KMUnYLHQR1QRXAJeq-0-4fa1526e7b84191f12c1814ca359ba6d)
图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中的菜单命令“几何变换→图像旋转”来观察处理效果。