使用雙線性插值法放大圖像(matlab實現)

雙線性插值的概念及公式能夠參考百度,這裏僅對算法原理進行簡單的說明:算法

雙線性插值計算公式:函數

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)  ui

這個公式代表瞭如何利用矩陣中的四個像素值計算新的像素值,這些新的像素值就組成了放大後的圖像。spa

下圖是如何將3x3的圖像放大爲4x4的圖像:code

 

原圖像表示爲3x3的矩陣(像素值處在黑線的交叉點上),如何計算4x4矩陣的值呢?(像素值處在紅色虛線交叉點及紅線與黑線的交點上)blog

好比新圖像B的第一列與原圖像A的第一列的對應關係是:索引

B(1,1) = A(1,1)it

B(1,2) = A(1,1.66667)io

B(1,3) = A(1,2.33334)function

B(1,4) = A(1,3.00001)

 

應用上面的公式,實際上就是用A的含有小數點的位置的像素值來計算B的像素值,但含有小數點位的像素是不存在的,這裏稱爲虛擬位置。

 

用原圖像A的值就能計算出放大後B的值,是否是很神奇?

實際上能夠這樣認爲:雙線性插值就是把放大後的圖像再壓縮到原來圖像的尺寸大小,計算原圖像中虛擬的像素值,等同於計算放大後圖像的像素值,

對於本例來講,B圖像的步長至關於A圖像步長的(3-1)/(4-1)=0.66667倍。下面咱們就能夠利用這個比率來對應B中像素位置與A中虛擬像素位置的關係。

B(1,1) = A(1,1)                    (1-1)*0.66667+1=1

B(1,2) = A(1,1.66667)         (2-1)*0.66667+1=1.66667

B(1,3) = A(1,2.33334)         (3-1)*0.66667+1=2.33334

B(1,4) = A(1,3.00001)         (4-1)*0.66667+1=3.00001

根據上面的對應關係,咱們就能夠用代碼實現了。

如今還有一個問題:

咱們計算虛擬像素值是須要周圍四個原像素值,好比上列中的(下圖中紅圈圈住的部分)

A(1,3) = (1-0)(1-0)A(1,3) + (1-0)0A(1,4) + 0(1-0)A(2,3) + 00A(2,4)

顯然這裏的A(1,4)和A(2,4)是沒法索引到得,由於原圖像是3x3的矩陣。

爲了解決這個問題,在A的最後一行,與最後一列分別加上0,這樣A就變成了4x4的矩陣。

圖示中擴展的0行0列的元素位置用紅色的座標標示,紅色斜箭頭把須要用到擴展A矩陣的虛擬像素點位置都標了出來。

實驗結果:

原圖像:

放大四倍後的圖像:


 

代碼實現:

主程序代碼:

clear ; close all; clc
image = imread('bird.png');  %載入圖像的值
r = image(:,:,1);     %因爲真彩圖是紅藍綠三個像素的疊加
g = image(:,:,2);     %這裏把r,g,b分離出來單獨調用函數計算
b = image(:,:,3);     %計算完成後再進行組裝
%這裏須要手動設置放大的倍數
w = 4;   %w放大的是豎直方向
l = 4;   %l放大的是水平方向

r = extenRGB(r,w,l);  %調用函數計算放大後的r值
g = extenRGB(g,w,l);  %調用函數計算放大後的g值
b = extenRGB(b,w,l);  %調用函數計算放大後的b值
%下面把計算完成後的rgb再組裝起來
outRGB(:,:,1) = r;
outRGB(:,:,2) = g; 
outRGB(:,:,3) = b;

outRGB = uint8(outRGB);%格式轉換,不然沒法顯示

imshow(outRGB);        %顯示放大後的圖像
 
 

 主程序調用的函數:

%像素放大計算函數 extenRGB()
function Output = extenRGB(A,w,l)

% A矩陣分別表明r,g,b矩陣
[m,n] = size(A);      %讀取A的行和列 
A = [A;zeros(1,n)];   %在A的最後一行加入兩行0
A = [A zeros(m+1,1)]; %在A的最後一列加入兩列0
%這樣A就變成(m+1)x(n+1)的矩陣,這是爲了解決索引A矩陣時的邊界溢出問題

ini_u = (m-1)/(w*m-1); %步長比,若是把原來的一步A(1,1)到A(2,1)看作1,那麼計算放大後的
ini_v = (n-1)/(l*n-1); %圖像B(2,1)至關於計算A(1+ini_u,1),即每步加ini_u
         

Output = zeros(w*m,l*n);            %初始化輸出矩陣
for j = 1:l*n;                      %左邊兩個語句的功能是:z_u,z_v向左取整,u,v取小數,原理以下
    z_v = floor((j-1)*ini_v+1);     %好比A爲3x3的矩陣,要放大爲Output是4x4大小,即放大了4/3倍, 
      v = (j-1)*ini_v+1 - z_v;      %新的一步的距離至關於原來的(3-1)/(4-1)=0.66667
    for i = 1:w*m;                  %Output(1,1) = A(1,1)       %(1-1)*0.66667+1=1
        z_u = floor((i-1)*ini_u+1); %Output(1,2) = A(1,1.66667) %(2-1)*0.66667+1=1.66667
          u = (i-1)*ini_u+1 - z_u;  %Output(1,3) = A(1,2.33334) %(3-1)*0.66667+1=2.33334
                                    %Output(1,4) = A(1,3.00001) %(4-1)*0.66667+1=3.00001
                                    
                                   

%===================下面是雙線性插值的代碼實現================================   
        Output(i,j) = (1 - u)*(1 - v)*A(z_u,     z_v    ) + ...
                      (1 - u)* v     *A(z_u,     z_v + 1) + ...
                       u     *(1 - v)*A(z_u + 1, z_v    ) + ...
                       u     * v     *A(z_u + 1, z_v + 1);
    end
end
       
相關文章
相關標籤/搜索