基於雙線性插值的圖像旋轉原理及MATLAB實現(非自帶函數)

1.圖像旋轉的原理

1.1.旋轉矩陣

旋轉一幅圖像(假設這幅圖像大小是矩形的),當然應該從像素點(pixels)開始,在直角座標系中,對點x0=[a0b0]x_0=\begin{bmatrix}a_0\\b_0\\ \end{bmatrix}逆時針旋轉角度θ\thetax1=[a1b1]x_1=\begin{bmatrix}a_1\\b_1\\ \end{bmatrix}的變換公式爲
x1=[cosθsinθsinθcosθ]x0x_1=\begin{bmatrix}cos\theta & -sin\theta \\ sin\theta & cos\theta\\ \end{bmatrix}x_0
那麼對圖像上的每個點調用這個旋轉公式,將舊圖像像素點的RGB值搬移到新圖像像素點,就可以將圖像旋轉到任意位置。
但是問題來了,顯示屏的像素點是有限的,這意味着顯示在顯示屏上的像素點座標必須是整數,旋轉過後的圖像的每個像素點座標難免有非整數的情況,那麼這種情況下我們怎麼處理呢?
我們不妨假設逆時針旋轉θ\theta旋轉後的圖形上所有的像素點都是整點,對於旋轉後的圖形的每個像素點x1x_1,求旋轉前圖形的對應像素點的座標x0x_0,取ω=θ\omega=-\theta爲逆旋轉角度,則旋轉後的像素點和旋轉前的像素點的對應關係爲:
x0=[cosωsinωsinωcosω]x1x_0=\begin{bmatrix}cos\omega & -sin\omega \\ sin\omega & cos\omega\\ \end{bmatrix}x_1
此時x0x_0不一定爲整點,x0x_0的像素值需要做一定的近似。近似的方法有最近鄰插值、雙線性插值等等,在這裏我們就介紹比較實用且不是很複雜的雙線性插值,該插值方法不會產生明顯失真現象。
對於像素點的旋轉座標函數編寫如下:
座標旋轉變換函數:rot.m

function y=rot(p,angle)
%p=[x,y]爲角度制
angle=angle*pi/180;%角度制輸入進行計算
y=[cos(angle) -sin(angle);sin(angle) cos(angle)]*p';
end

1.2.雙線性插值

對於x和y座標非整數的非整點xpx_p,假設它周圍的四個整點座標分別爲x11,x12,x21,x22x_{11},x_{12},x_{21},x_{22}(構成一個矩形)。假設第一維度是x座標,第二維度是y座標。則x11(1)=x21(1)xp(1)x12(1)=x22(1)x_{11}(1)=x_{21}(1)≤x_p(1)≤x_{12}(1)=x_{22}(1)
x11(2)=x12(2)xp(2)x21(2)=x22(2)x_{11}(2)=x_{12}(2)≥x_p(2)≥x_{21}(2)=x_{22}(2)
顯然,即使xpx_p爲整點,仍然存在這樣的四個點x11,x12,x21,x22x_{11},x_{12},x_{21},x_{22}使得上式成立。
在下圖中,P爲非整點,存在4個整點Q12,Q11,Q22,Q21Q_{12},Q_{11},Q_{22},Q_{21}將P點包圍在其中,設縱向比例係數β=yy2y1y2\color{blue}\beta=\frac{y-y_2}{y_1-y_2},橫向比例係數α=xx1x2x1\color{blue}\alpha=\frac{x-x_1}{x_2-x_1}顏色函數F(P)F(P)在四個整點處的值分比爲F12,F11,F22,F21F_{12},F_{11},F_{22},F_{21},則P點的函數值
FP=β[(1α)F11+αF21]+(1β)[(1α)F12+αF22]F_P=\beta[(1-\alpha)F_{11}+\alpha F_{21}]+(1-\beta)[(1-\alpha)F_{12}+\alpha F_{22}]寫成矩陣的形式即爲:
FP=[1αα][F11F12F21F22][β1β]F_P=\begin{bmatrix}1-\alpha & \alpha \end{bmatrix}\begin{bmatrix} F_{11} & F_{12} \\[2ex] F_{21} & F_{22} \end{bmatrix}\begin{bmatrix}\beta \\[2ex] 1-\beta \end{bmatrix}
在這裏插入圖片描述
對於灰度圖像,F(P)F(P)是一維函數,對於RGB圖像,F(P)=[FR(P)FG(P)FB(P)]F(P)=\begin{bmatrix}F_R(P) \\F_G(P) \\ F_B(P) \end{bmatrix}
由於該公式較爲複雜,可以單獨編寫雙線性插值函數,輸入爲一個任意點座標,和圖像每個點的像素;輸出爲該點進行雙線性插值後的顏色函數值。但需要主要的是,若給採集的4個周圍整點,有其中一個超出了圖像邊界,考慮到圖像邊界一般爲白色,則以白色爲替代。檢測點是否在畫布內只需要條件判斷語句就夠了。
檢測是否在畫布內的判斷程序:isinrect.m

function y=isinrect(plt,rect)
if plt(1)>=rect(1) && plt(1)<=rect(2) && plt(2)>=rect(3) && plt(2)<=rect(4)
    y=true;
else
    y=false;
end

雙線性插值函數:linear_interp.m

function y=linear_interp(p,img)
    %p爲需要雙線性插值的點座標(向量)
    x=p(1);y=p(2);
    m=size(img,1);n=size(img,2);
    x1=floor(x);x2=ceil(x);y1=floor(y);y2=ceil(y);%[x,y]四周的四個整點
    left=x-x1;%距左邊線距離
    bottom=y-y1;%距底線距離
    plt=[x1,y2;x2,y2;x1,y2;x2,y2];
    img_rect=[1,m,1,n];%原圖像的矩形框
    pix_rect=zeros(1,4,3);
    for t=1:4
        if isinrect(plt(t,:),img_rect)
            for color=1:3
                pix_rect(1,t,color)=img(plt(t,1),plt(t,2),color);
            end
        else
            pix_rect(1,t,:)=255;%背景色爲白色
        end
    end
    pixels=zeros(1,3);%保存該點的三原色的三個像素
    pix_rect=reshape(pix_rect,2,2,3);
    for color=1:3
        pixels(color)=[bottom,1-bottom]*pix_rect(:,:,color)*[1-left;left];%雙線性像素插值
    end
    y=pixels;
end

1.3.像素點匹配

假設圖像的點都是整點的情況下,新圖像是一個旋轉後的矩形,此時需要給新圖像定界使得新圖像能夠包括在一個旋轉角度爲0°大矩形中。
在這裏插入圖片描述
left=max(x1,x2,x3,x4),right=min(x1,x2,x3,x4)left=max(x_1,x_2,x_3,x_4),right=min(x_1,x_2,x_3,x_4)
top=max(y1,y2,y3,y4),bottom=min(y1,y2,y3,y4)top=max(y_1,y_2,y_3,y_4),bottom=min(y_1,y_2,y_3,y_4)

filename='足球.bmp';%文件的完整路徑名
img=imread(filename);%導入圖像
% subplot(121)
% imshow(img)%展示原圖像
m=size(img,1);n=size(img,2);%統計圖像的長和寬
plt=[0,0;m,0;m,n;0,n];%四個頂點座標
for t=1:4
    plt(t,:)=ceil(rot(plt(t,:),rot_angle));%三個頂點進行旋轉座標變換
end
%新的四個點座標的x和y邊界值
left=min(plt(:,1));right=max(plt(:,1));
bottom=min(plt(:,2));top=max(plt(:,2));
M=right-left;N=top-bottom;%獲取新的圖像大小
new_img=255*ones(M,N,3);%創建新畫布
left=min(plt(:,1));right=max(plt(:,1));
bottom=min(plt(:,2));top=max(plt(:,2));

定界完成後,只需要求出新圖像定界後每個像素點對應的原圖像像素點座標,並按照雙線性插值的方法取得像素值,對應到新圖像點中,即可求出每個新圖像點的像素值,旋轉步驟即完成。要注意的是,如果雙線性插值遇到了原圖像界限外的點,爲保證程序不出錯,可以直接將界限外的點置爲0(相當於非常弱的邊緣虛化效果),或者直接將最外層邊界整點進行最近鄰插值(這種分段算法實現會略微麻煩)。主函數文件代碼如下:
主函數文件:img_process.m

function img_process(rot_angle)
close all
filename='足球.bmp';%文件的完整路徑名
img=imread(filename);%導入圖像
figure
imshow(img)%展示原圖像
m=size(img,1);n=size(img,2);%統計圖像的長和寬
plt=[0,0;m,0;m,n;0,n];%四個頂點座標
for t=1:4
    plt(t,:)=ceil(rot(plt(t,:),rot_angle));%三個頂點進行旋轉座標變換
end
%新的四個點座標的x和y邊界值
left=min(plt(:,1));right=max(plt(:,1));
bottom=min(plt(:,2));top=max(plt(:,2));
M=right-left;N=top-bottom;%獲取新的圖像大小
new_img=255*ones(M,N,3);%創建新畫布
for i=1:M
    for j=1:N
        init_plt=rot([i-1+left,j-1+bottom],-rot_angle);%新圖像對應原圖像的座標
        init_plt=init_plt+1;%還原到Matlab座標系
        new_img(i,j,:)=linear_interp(init_plt,img);
    end
end
figure
imshow(uint8(new_img))%展示旋轉後的新圖像(底色爲白色)

2.實現效果與說明

將上述標紅的4個M文件放在一個文件夾,並更改MATLAB目錄爲該文件夾,並在該文件夾添加一張名爲“足球.bmp”的位圖文件,在命令行輸入img_process(30)即可將該圖像旋轉30°顯示,顯示效果如下:

原圖像 新圖像(旋轉30°)
原圖像 在這裏插入圖片描述

本文從原理上用MATLAB代碼實現了圖像的旋轉,如果想直接調用MATLAB的函數,請查看imrotate函數的相關說明:
new_img=imrotate(initial_img,angle,method, ‘crop’)

  • angle:逆時針旋轉的角度,是角度值
  • method:該參數爲插值方法,其中’bilinear’爲雙線性插值,可選
  • crop:旋轉後增大圖像
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章