昨天和今天学习了《Computer Vision:Algorithms and Applications》中第二章“Image formation”前半部分,主要是如何表示2D、3D图像中的点、线、面等,以及如何用公式推导出2D图形的几何变换,如位移、旋转、放缩、仿射变换、投射等,如下图所示:
一、图像旋转方法简介
其中的图像旋转是一种常用的数字图像处理技术。由于旋转后图像像素点坐标不再是整数,所以旋转后必须对新的像素点灰度值进行插值运算。目前常用的方法有最近邻插值法、线性插值法和样条插值法。文献介绍,最近邻法速度快,方法简单,但生成图像效果较差;样条插值法计算精度高,效果好,但计算复杂,速度较慢;线性插值法(E.g. 双线性插值法)效果较好,运行时间较短。另外,实现赋值的方法分为正向映射法和反向映射法:正向映射法是指,从原始图像坐标出发,计算出在旋转图像上坐标,然后将原始图像该坐标的灰度值赋给对应旋转图像该坐标点;反向映射法则反之。
本文将分别采用基于最近邻取值的正向映射法、基于最近邻取值的反向映射法、基于双线性插值的反向映射法实现图像旋转,并对比三种方法的效果。
二、本文方法
1. 基于最近邻取值的正向映射法
这种方法最简单,也最直观,先考虑图像旋转原理:
以顺时针旋转为例来堆到旋转变换公式。如下图所示。
旋转前:
x0=rcosb;y0=rsinb
旋转a角度后:
x1=rcos(b-a)=rcosbcosa+rsinbsina=x0cosa+y0sina
y1=rsin(b-a)=rsinbcosa-rcosbsina=-x0sina+y0cosa
正向映射即根据原图的坐标推导出旋转图像对应点坐标,然后直接将原图坐标灰度值赋给x1,y1
2.基于最近邻取值的反向映射法
旋转前:
x1=rcosc;y1=rsinc
旋转a角度后:
x0=rcos(c+a)=rcosccosa-rsincsina=x1cosa-y1sina
y0=rsin(c+a)=rsinccosa+rcoscsina=-x1sina+y1cosa
反向映射即已知旋转后图像坐标,通过公式推导出原始图像上对应坐标,将该坐标对应灰度值赋给旋转后坐标。因为计算得到的y0, x0非整数,最近邻方法即将与(Xo,Yo)距离最近的像素的灰度值作为(Xo,Yo)的灰度值赋给(X1,Y1)点。
3.基于双线性插值的反向映射法
在计算(Xo,Yo)的灰度值时,采用如下方法计算:
三、实验对比
三种实验结果的对比图如下:
可见,双线性插值法获得的旋转图像更平滑,接近真实图像。
三种方法的matlab代码如下
1 Image=imread('E:\1.jpg');
2
3 %X,Y为其行列数
4 angle=30;
5 %角度任意的一个数 表示30度
6 pai=3.1415929657;
7 Angle=pai*angle/180;
8 %转换一下角度的表示方法。
9 [Y,X,Z]=size(Image);
10 %原图显示
11 subplot(2,2,1);
12 imshow(Image);
13 title('原图像');
14
15 %
16 %计算四个角点的新坐标,确定旋转后的显示区域
17 LeftBottom(1,1)=(Y-1)*sin(Angle);
18 LeftBottom(1,2)=(Y-1)*cos(Angle);
19
20 LeftTop(1,1)=0;
21 LeftTop(1,2)=0;
22
23 RightBottom(1,1)=(X-1)*cos(Angle)+(Y-1)*sin(Angle);
24 RightBottom(1,2)=-(X-1)*sin(Angle)+(Y-1)*cos(Angle);
25
26 RightTop(1,1)=(X-1)*cos(Angle);
27 RightTop(1,2)=-(X-1)*sin(Angle);
28
29 %计算显示区域的行列数
30 Xnew=max([LeftTop(1,1),LeftBottom(1,1),RightTop(1,1),RightBottom(1,1)])-min([LeftTop(1,1),LeftBottom(1,1),RightTop(1,1),RightBottom(1,1)]);
31 Ynew=max([LeftTop(1,2),LeftBottom(1,2),RightTop(1,2),RightBottom(1,2)])-min([LeftTop(1,2),LeftBottom(1,2),RightTop(1,2),RightBottom(1,2)]);
32
33 % 分配新显示区域矩阵
34 ImageNewForward=zeros(round(Ynew),round(Xnew),3)+255;
35 ImageNewIntersection=zeros(round(Ynew),round(Xnew),3)+255;
36 ImageNew1nn=zeros(round(Ynew),round(Xnew),3)+255;
37
38 %计算原图像各像素的新坐标:正向映射法
39 for indexX=0:(X-1)
40 for indexY=0:(Y-1)
41 Yn=1+round(-indexX*sin(Angle)+indexY*cos(Angle))+round(abs(min([LeftTop(1,2),LeftBottom(1,2),RightTop(1,2),RightBottom(1,2)])));
42 Xn=round(indexX*cos(Angle)+indexY*sin(Angle))+round(abs(min([LeftTop(1,1),LeftBottom(1,1),RightTop(1,1),RightBottom(1,1)])))+1;
43 ImageNewForward(Yn,Xn,1)=Image(indexY+1,indexX+1,1);
44 ImageNewForward(Yn,Xn,2)=Image(indexY+1,indexX+1,2);
45 ImageNewForward(Yn,Xn,3)=Image(indexY+1,indexX+1,3);
46 end
47 end
48
49 %%反向映射法
50 for indexY=1:round(Ynew)
51 for indexX=1:round(Xnew)
52 Y1=indexY-round(abs(min([LeftTop(1,2),LeftBottom(1,2),RightTop(1,2),RightBottom(1,2)])));
53 X1=indexX-round(abs(min([LeftTop(1,1),LeftBottom(1,1),RightTop(1,1),RightBottom(1,1)])));
54 Yoo=X1*sin(Angle)+Y1*cos(Angle);
55 Xoo=X1*cos(Angle)-Y1*sin(Angle);
56 Yo=round(Yoo);
57 Xo=round(Xoo);
58 if 1<Xo&&Xo<X&&1<Yo&&Yo<Y
59 %最近邻法
60 ImageNew1nn(indexY,indexX,1)=Image(Yo,Xo,1);
61 ImageNew1nn(indexY,indexX,2)=Image(Yo,Xo,2);
62 ImageNew1nn(indexY,indexX,3)=Image(Yo,Xo,3);
63
64 %双线性插值法
65 left=floor(Xoo);
66 right=ceil(Xoo);
67 up=floor(Yoo);
68 down=ceil(Yoo);
69
70 upmid1=(1-Xoo+left)*Image(up,left,1)+(Xoo-left)*Image(up,right,1);
71 downmid1=(1-Xoo+left)*Image(down,left,1)+(Xoo-left)*Image(down,right,1);
72 upmid2=(1-Xoo+left)*Image(up,left,2)+(Xoo-left)*Image(up,right,2);
73 downmid2=(1-Xoo+left)*Image(down,left,2)+(Xoo-left)*Image(down,right,2);
74 upmid3=(1-Xoo+left)*Image(up,left,3)+(Xoo-left)*Image(up,right,3);
75 downmid3=(1-Xoo+left)*Image(down,left,3)+(Xoo-left)*Image(down,right,3);
76 central1=(1-Yoo+up)*upmid1+(Yoo-up)*downmid1;
77 central2=(1-Yoo+up)*upmid2+(Yoo-up)*downmid2;
78 central3=(1-Yoo+up)*upmid3+(Yoo-up)*downmid3;
79
80 ImageNew(indexY,indexX,1)=central1;
81 ImageNew(indexY,indexX,2)=central2;
82 ImageNew(indexY,indexX,3)=central3;
83
84 else
85 ImageNew(indexY,indexX,:)=255;
86 end
87 end
88 end
89
90 %显示
91 subplot(2,2,2);
92 ImageNewForward=uint8(ImageNewForward);
93 imshow(ImageNewForward);
94 promp=['旋转角度为:' int2str(angle) '度图像 正向映射法'];
95 title(promp);
96
97 subplot(2,2,3);
98 ImageNew1nn=uint8(ImageNew1nn);
99 imshow(ImageNew1nn);
100 promp=['旋转角度为:' int2str(angle) '度图像 最近邻插值法'];
101 title(promp);
102
103 subplot(2,2,4);
104 ImageNew=uint8(ImageNew);
105 imshow(ImageNew);
106 promp=['旋转角度为:' int2str(angle) '度图像 双线性插值法'];
107 title(promp);
1. 《Computer Vision:Algorithms and Applications》,pp30-40
2. 曹佃国, 陈浩杰,李鹏, "基于 Matlab 的双线性插值算法在图像旋转中的应用".