1. 程式人生 > 實用技巧 >Matlab實現imrotate函式功能

Matlab實現imrotate函式功能

演算法分析

  1. 開闢新矩陣存放旋轉後的影象。計算公式如下,H為原影象行,W原影象列,a為旋轉角度,a是鈍角時,三角函式需要加上絕對值
DH = H * abs(cos(a)) + W * abs(sin(a));  
DW = H * abs(sin(a)) + W * abs(cos(a));
  1. 計算旋轉後的座標(旋轉方向為逆時針)。利用原座標點與旋轉矩陣相乘,公式如下,x,y為原座標,a為旋轉角度,x',y'為旋轉後的座標

  2. 利用近鄰插值給旋轉後的影象賦上灰度值。由於是根據旋轉後的新矩陣座標映射回原矩陣中的座標求其灰度值,所以對旋轉矩陣求逆矩陣R,原畫素位置記為src,中心點記為center1,旋轉後像素位置記為dst,中心點記為center2,近鄰插值(四捨五入取近似值),整理為以下公式:

                                                       src = round(R * (dst - center2) + center1)
    

若是彩色圖則每個通道都如上賦值

雙線性插值:其中i,j為當前點的座標,u為i座標的偏移量,v為j座標的偏移量

                                        f(i+u,j+v) = (1-u)(1-v)f(i,j)+u(1-v)f(i+1,j)+(1-u)vf(i,j+1)+ uvf(i+1,j+1)

近鄰插值虛擬碼

function outputimg = myimrotate(A,angle)
% 利用近鄰插值法將影象旋轉
% 輸入:A是讀入的影象矩陣,angle是旋轉角度(0-360),angle取正為逆時針旋轉,取負為順時針旋轉
% 輸出:outputimg是輸出的影象矩陣

a = 旋轉角度/180 * pi 
R = 旋轉矩陣
R = 求逆矩陣

[H,W,CH] = 影象的長、寬、通道
%當旋轉角度為鈍角(順時針旋轉)時加上絕對值
DH = 根據步驟1的公式求出新矩陣的行
DW = 根據步驟1的公式求出新矩陣的行
outputimg = 按照DH和DW新開闢一個矩陣
center1 = 原影象中心座標
center2 = 新矩陣中心座標
遍歷新矩陣
          dst = 新矩陣中當前點的座標
          src = 根據步驟3的公式求得當前點對應在原圖上的點的座標
          如果src的座標點在原圖上沒有越界)
             outputimg(i,j,:) = 將各個通道對應點在原圖的畫素值賦給新矩陣
將outputimg型別轉換為uint8便於顯示影象;
end

雙線性插值虛擬碼

function outputimg = myimrotate_bilinear(A,angle)
% 利用雙線性插值法將影象旋轉
% A是讀入的影象矩陣,angle是旋轉角度(0-360),angle取正為逆時針旋轉,取負為順時針旋轉
% outputimg是輸出的影象矩陣

a = 旋轉角度/180 * pi 
R = 旋轉矩陣
R = 逆矩陣

[H,W,CH] = 影象的長、寬、通道
%當旋轉角度為鈍角(順時針旋轉)時加上絕對值
DH = 根據步驟1的公式求出新矩陣的行
DW = 根據步驟1的公式求出新矩陣的行
outputimg = 按照DH和DW新開闢一個矩陣
center1 = 原影象中心座標
center2 = 新矩陣中心座標

遍歷新矩陣
          dst = 新矩陣中的當前點
          src = 根據步驟3的公式求得當前點對應在原圖上的點的座標(行、列)
          %雙線性插值
          a = 對求得的src向下取整
          offset = 計算的src的偏移量
          u = i座標(行)的偏移量
          v = j座標(列)的偏移量
          i = 當前點向下取整之後行座標
          j = 當前點向下取整之後列座標
          如果i,j,並且(i+1)、(j+1)沒有越界
             outputimg(di,dj,:) = 將各個通道對應點根據步驟4公式所求得的在原圖上的畫素值賦給新矩陣
將outputimg型別轉換為uint8便於顯示影象
end

近鄰插值程式碼

function outputimg = myimrotate_neighbor(A,angle)
% 利用近鄰插值法將影象旋轉
% A是讀入的影象矩陣,angle是旋轉角度
% outputimg是輸出的影象矩陣

%角度轉換,求旋轉矩陣的逆矩陣
a = angle / 180 * pi;
R = [cos(a), -sin(a); sin(a), cos(a)]; %旋轉矩陣
R = R'; %求逆矩陣

%根據原圖矩陣生成輸出影象所需畫布矩陣的大小
[H,W,CH] = size(A);
DH = ceil(H * abs(cos(a)) + W * abs(sin(a)));  %當順時針旋轉時加上絕對值
DW = ceil(H * abs(sin(a)) + W * abs(cos(a)));
outputimg = zeros(DH,DW,CH);
center1 = [H;W] / 2;
center2 = [DH;DW] / 2;

for i = 1:DH
       for j = 1:DW
          dst = [i; j];
          %利用的向量的旋轉原理,再與旋轉矩陣相乘
          src = round(R * (dst - center2) + center1); %四捨五入近鄰插值
          % 逆向進行畫素查詢
          if (src(1) >= 1 && src(1) <= H && src(2) >= 1 && src(2) <= W)
             outputimg(i,j,:) = A(src(1), src(2),:); 
          end
       end
end
outputimg = uint8(outputimg);
end

實驗結果

%呼叫示例:
A = imread('cameraman.tif');
B = myimrotate_neighbor(A,30);
subplot(1,2,1),imshow(A),title('原圖');
subplot(1,2,2),imshow(B),title('旋轉30°的影象');

灰度圖逆時針30°旋轉:

彩色圖順時針30°旋轉(等同於逆時針旋轉330°):

雙線性插值程式碼

function outputimg = myimrotate_bilinear(A,angle)
% 利用雙線性插值法將影象旋轉
% A是讀入的影象矩陣,angle是旋轉角度
% outputimg是輸出的影象矩陣


%角度轉換,求旋轉矩陣的逆矩陣
a = angle / 180 * pi;
R = [cos(a), -sin(a); sin(a), cos(a)];
R = R'; 

%根據原圖矩陣生成輸出影象所需畫布矩陣的大小
[H,W,CH] = size(A);
DH = floor(H * cos(a) + W * sin(a));  %向上取整
DW = floor(H * sin(a) + W * cos(a));
outputimg = zeros(DH,DW,CH);
center1 = [H;W] / 2;
center2 = [DH;DW] / 2;

for di = 1:DH
       for dj = 1:DW
          dst = [di; dj];
          %利用的向量的旋轉原理,再與旋轉矩陣相乘
          src = (R * (dst - center2) + center1); 
          %雙線性插值
          a = floor(src); %向下取整
          offset = src - a;  %計算的偏移量
          u = offset(1);  %x的偏移量
          v = offset(2);  %y的偏移量
          i = a(1);
          j = a(2);
          % 逆向進行畫素查詢
          if (src(1) >= 1 && src(1) <= H - 1 && src(2) >= 1 && src(2) <= W - 1)
             outputimg(di,dj,:) = (1-u)*(1-v)*A(i, j, :) + (1 - u) * v * A(i, j + 1, :) + u * (1 - v) * A(i + 1, j, :) + u * v * A(i + 1, j + 1, :); 
          end
       end
end
outputimg = uint8(outputimg);
end
% 呼叫示例:
A = imread('cameraman.tif');
B = myimrotate_bilinear(A,30);
C = myimrotate_neighbor(A,30);
subplot(1,3,1),imshow(A),title('原圖');
subplot(1,3,2),imshow(C),title('近鄰插值旋轉');
subplot(1,3,3),imshow(B),title('雙線性插值旋轉');

實驗結果

實驗分析

  • 對映關係的對應,需要根據旋轉後的開闢的新矩陣找在原圖中的位置,如下圖所示,由原圖去給新影象賦畫素值的時候,有些座標對映過來是包含小數,在原圖上根本找不到,所以得到部分空點(灰度值=0)
  • 新矩陣的開闢,如上圖未根據演算法分析步驟1開闢新矩陣,使得旋轉後的影象不能完整顯示