数字图像处理与机器视觉:Visual C++与Matlab实现(第2版)
上QQ阅读APP看书,第一时间看更新

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个变换矩阵的级联。

其中,WoldHoldWnewHnew分别表示原图像和新图像的宽和高。

上式的逆变换为:

这样,读者就可以根据上面的逆变换公式,按照算法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中的菜单命令“几何变换→图像旋转”来观察处理效果。