http://www.cnblogs.com/mlv5/archive/2012/02/02/2336321.html
昨天和今天學習了《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 11 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 的雙線性插值算法在圖像旋轉中的應用".