天天看點

ISP——圖像插值算法

文章目錄

    • 空間映射關系
      • 前向映射
      • 反向映射
    • 鄰域插值
      • 代碼如下:
    • 雙線性插值
      • 代碼如下:
    • 雙三次插值
      • 代碼如下:
    • 總結
    • 提示

內插補點算法作為一種最常用的算法,在圖像放大、旋轉等多種變換中都有用到。由于圖像進行某種變換後新的圖像的像素并非完全和原始圖像的像素一一對應,是以導緻新的圖像中會出現很多“空穴”,這是就需要對這些“空穴”進行填補。所謂插值算法也就是填補的方式。本文主要通過造輪子的方式通過圖像放大來介紹三種最常見的插值算法:鄰域插值、雙線性插值和雙三次插值。希望對各位了解插值算法有所幫助。

空間映射關系

在開始正式介紹插值之前,需要先介紹一下空間坐标的映射關系。

前向映射

前向映射就是從原圖像坐标計算出目标圖像坐标。用一下公式表示

g ( x ’ , y ’ ) = f ( a ( x , y ) , b ( x , y ) ) g(x’,y’) = f(a(x,y), b(x,y)) g(x’,y’)=f(a(x,y),b(x,y))

反向映射

反向映射從結果圖像的坐标計算原圖像的坐标。用一下公式表示

g ( a ’ ( x , y ) , b ’ ( x , y ) ) = f ( x , y ) ; g(a’(x,y), b’(x,y)) = f(x,y); g(a’(x,y),b’(x,y))=f(x,y);

一般在圖像縮放是使用反向映射的方式,通過新的圖像的點坐标求出在原始圖像中的位置,然後通過原始圖像周圍的點的值來填充,即插值算出該點的值。

鄰域插值

鄰域插值也叫最近鄰插值,是指将目标圖像中的點,對應到原圖像中後,找到最相鄰的整數點,作為插值後的輸出。

ISP——圖像插值算法

如圖所示,P為新圖像中的點經過反向映射後在原始圖像中的位置。最近鄰的意思就是P點原始圖像中的哪個點最近,就用該點的值指派給P。程式設計時的主要思路就是通過P點坐标的小數位進行四舍五入,求出最近的點,然後直接把該點的值指派過去就好了。

代碼如下:

%% --------------------------------
%% author:wtzhu
%% date: 20210131
%% fuction: 鄰域插值
%% --------------------------------

clc,clear,close all;
% 讀取圖檔
orgImage = imread('lena.bmp');
figure;imshow(orgImage);title('org image');

% 擷取長寬
[width, height] = size(orgImage);
m = width / 2;
n =  height / 2;
smallImage = zeros(m,n);
% 降采樣,将原圖縮減為原來的1/2
for i=1:m
    for j=1:n
        smallImage(i,j) = orgImage(2*i,2*j);
    end
end
figure;imshow(uint8(smallImage));title('small image');

% 插值時需要特殊處理四周最外圈的行和列,本算法中将其向外擴充一圈,用最外圈的值填充
headRowMat = smallImage(1,:);%取f的第1行
tailRowMat = smallImage(m,:);%取f的第m行
% 行擴充後,列擴充時需要注意四個角需要單獨擴充進去,不然就成了十字架形的
headColumnMat = [smallImage(1,1), smallImage(:,1)', smallImage(m,1)];
tailColumnMat = [smallImage(1,n), smallImage(:,n)', smallImage(m,n)];
expandImage = [headRowMat; smallImage; tailRowMat];
expandImage = [headColumnMat; expandImage'; tailColumnMat];
expandImage = uint8(expandImage');
figure;imshow(expandImage);title('expand image');

% 按比例放大
[smallWidth, smallHeight] = size(smallImage);
% 設定放大系數
magnification = 2;
newWidth = magnification * smallWidth;
newHeight = magnification * smallHeight;
% 建立一個新的矩陣,用于承接變換後的圖像
newImage = zeros(newWidth, newHeight);

% 循環計算出新圖像的像素值
for i = 1 : newWidth
   for j = 1: newHeight
       detaX = rem(i, magnification) / magnification;
       floorX = floor(i / magnification) + 1;
       detaY = rem(j, magnification) / magnification;
       floorY = floor(j / magnification) + 1;
       if detaX < 0.5 && detaY < 0.5
            newImage(i, j) = expandImage(floorX, floorY);
       elseif detaX < 0.5 && detaY >= 0.5
            newImage(i, j) = expandImage(floorX, floorY + 1);
       elseif detaX >= 0.5 && detaY < 0.5
            newImage(i, j) = expandImage(floorX + 1, floorY);
       else
            newImage(i, j) = expandImage(floorX + 1, floorY + 1);
       end
   end
end
figure;imshow(uint8(newImage));title('NeighborhoodInterpolation');
           
ISP——圖像插值算法

雙線性插值

雙線性插值算法就是在最近鄰插值算法的基礎上,用周圍的四個點通過線性插值的方式計算出該點的值。

ISP——圖像插值算法

如圖,就是先通過A1和A2兩個點通過線性插值的方式計算出B1的值,然後通過A3和A4計算出B2的值,然後通過B1和B2計算出P點的值。通過三維圖可能更容易了解

ISP——圖像插值算法

算法推導過程:

首先通過A和B計算出N的值有方程:

ISP——圖像插值算法

通過C和D求出M的值:

ISP——圖像插值算法

最後通過M和N求出O的值:

ISP——圖像插值算法

綜合式(1)、(2)、(3)得:

Z = ( Z C − Z A ) ∗ X + ( Z B − Z A ) ∗ Y + ( Z D + Z A − Z B − Z C ) ∗ X ∗ Y + Z A Z=(Z_{C}-Z_{A})*X + (Z_{B}-Z_{A})*Y + (Z_{D}+Z_{A}-Z_{B}-Z_{C})*X*Y + Z_{A} Z=(ZC​−ZA​)∗X+(ZB​−ZA​)∗Y+(ZD​+ZA​−ZB​−ZC​)∗X∗Y+ZA​

代碼如下:

%% --------------------------------
%% author:wtzhu
%% date: 20210202
%% fuction: 雙線性插值
%% f(x,y) = [f(1,0)-f(0,0)]*x+[f(0,1)-f(0,0)]*y+[f(1,1)+f(0,0)-f(1,0)-f(0,1)]*xy+f(0,0)
%% x,y都是歸一化的值
%% --------------------------------

clc,clear,close all;
% 讀取圖檔
orgImage = imread('lena.bmp');
figure;imshow(orgImage);title('org image');

% 擷取長寬
[width, height] = size(orgImage);
m = width / 2;
n =  height / 2;
smallImage = zeros(m,n);
% 降采樣,将原圖縮減為原來的1/2
for i=1:m
    for j=1:n
        smallImage(i,j) = orgImage(2*i,2*j);
    end
end
figure;imshow(uint8(smallImage));title('small image');

% 插值時需要特殊處理四周最外圈的行和列,本算法中将其向外擴充一圈,用最外圈的值填充
headRowMat = smallImage(1,:);%取f的第1行
tailRowMat = smallImage(m,:);%取f的第m行
% 行擴充後,列擴充時需要注意四個角需要單獨擴充進去,不然就成了十字架形的
headColumnMat = [smallImage(1,1), smallImage(:,1)', smallImage(m,1)];
tailColumnMat = [smallImage(1,n), smallImage(:,n)', smallImage(m,n)];
expandImage = [headRowMat; smallImage; tailRowMat];
expandImage = [headColumnMat; expandImage'; tailColumnMat];
expandImage = uint8(expandImage');
figure;imshow(expandImage);title('expand image');

% 按比例放大
[smallWidth, smallHeight] = size(smallImage);
% 設定放大系數
magnification = 2;
newWidth = magnification * smallWidth;
newHeight = magnification * smallHeight;
% 建立一個新的矩陣,用于承接變換後的圖像
newImage = zeros(newWidth, newHeight);

% f(x,y) = [f(1,0)-f(0,0)]*x+[f(0,1)-f(0,0)]*y+[f(1,1)+f(0,0)-f(1,0)-f(0,1)]*xy+f(0,0)
for i = 1 : newWidth
   for j = 1: newHeight
       detaX = rem(i, magnification) / magnification;
       floorX = floor(i / magnification) + 1;
       detaY = rem(j, magnification) / magnification;
       floorY = floor(j / magnification) + 1;
       newImage(i, j) = (expandImage(floorX + 1,floorY) - expandImage(floorX,floorY)) * detaX + ... 
                        (expandImage(floorX, floorY + 1) - expandImage(floorX, floorY)) * detaY + ...
                        (expandImage(floorX+1, floorY+1) + expandImage(floorX, floorY) - ...
                            expandImage(floorX+1, floorY) - expandImage(floorX, floorY+1)) * detaX * detaY + ...
                        expandImage(floorX, floorY);
   end
end
figure;imshow(uint8(newImage));title('BilinearInterpolation');


           
ISP——圖像插值算法

雙三次插值

在滿足Nyquist 條件下,從離散信号x(nTs)可恢複連續信号可恢複連續信号x(t) :

x ( t ) = ∑ i = − ∞ + ∞ x ( n T s ) sin ⁡ c ( π T S ( t − n T s ) ) x(t)=\sum_{i=-\infty}^{+\infty} x\left(n T_{s}\right) \sin c\left(\frac{\pi}{T_{S}}\left(t-n T_{s}\right)\right) x(t)=i=−∞∑+∞​x(nTs​)sinc(TS​π​(t−nTs​))

ISP——圖像插值算法

那麼就聯想到圖像是否也能通過這種方式複原。

考慮到計算量,我們隻取-2到2這個區間的點來計算

ISP——圖像插值算法

然後我們通過

S ( x ) = [ 1 − 2 ∣ x ∣ 2 + ∣ x ∣ 3 ∣ x ∣ < 1 4 − 8 ∣ x ∣ + 5 ∣ x ∣ 2 − ∣ x ∣ 3 1 ≤ ∣ x ∣ ≤ 2 0 ∣ x ∣ > 2 S(x)=\left[\begin{array}{cc} 1-2|x|^{2}+|x|^{3} & |x|<1 \\ 4-8|x|+5|x|^{2}-|x|^{3} & 1 \leq|x| \leq 2 \\ 0 & |x|>2 \end{array}\right. S(x)=⎣⎡​1−2∣x∣2+∣x∣34−8∣x∣+5∣x∣2−∣x∣30​∣x∣<11≤∣x∣≤2∣x∣>2​

來分段拟合曲線,進而求出待求點的值。

代碼如下:

%% --------------------------------
%% author:wtzhu
%% date: 20210202
%% fuction: 雙三次内插法
%% --------------------------------
clc,clear,close all;
orgImage = imread('lena.bmp');
[width, height] = size(orgImage);%将圖像隔行隔列抽取元素,得到縮小的圖像f
figure; imshow(orgImage); title('org image');%顯示原圖像

m = width/2;
n = height/2;
smallImage = zeros(m, n);
for i = 1: m
    for j = 1: n
        smallImage(i, j) = orgImage(2*i, 2*j);
    end
end
figure;imshow(uint8(smallImage));title('small image');%顯示縮小的圖像


magnification = 2;%設定放大倍數
a = smallImage(1,:);%取f的第1行
c = smallImage(m,:);%取f的第m行
%将待插值圖像矩陣前後各擴充兩行兩列,共擴充四行四列到f1
b = [smallImage(1,1), smallImage(1,1), smallImage(:,1)', smallImage(m,1), smallImage(m,1)];
d = [smallImage(1,n), smallImage(1,n), smallImage(:,n)', smallImage(m,n), smallImage(m,n)];
a1 = [a; a; smallImage; c; c];
b1 = [b; b; a1'; d; d];
expandImage = double(b1');

newImage = zeros(magnification*m,magnification*n);
for i = 1:magnification * m%利用雙三次插值公式對新圖象所有像素指派
    u = rem(i, magnification)/magnification;
    i1 = floor(i/magnification) + 2;%floor()向左取整,floor(1.3)=floor(1.7)=1
    A = [sw(1+u) sw(u) sw(1-u) sw(2-u)];
    for j = 1:magnification*n
        v = rem(j, magnification)/magnification; j1=floor(j/magnification)+2;
        C = [sw(1+v); sw(v);  sw(1-v); sw(2-v)];
        B = [expandImage(i1-1,j1-1) expandImage(i1-1,j1) expandImage(i1-1,j1+1) expandImage(i1-1,j1+2); 
             expandImage(i1,j1-1) expandImage(i1,j1) expandImage(i1,j1+1) expandImage(i1,j1+2);
             expandImage(i1+1,j1-1) expandImage(i1+1,j1) expandImage(i1+1,j1+1) expandImage(i1+1,j1+2);
             expandImage(i1+2,j1-1) expandImage(i1+2,j1) expandImage(i1+2,j1+1) expandImage(i1+2,j1+2)];
        newImage(i,j) = (A*B*C);
    end
end
%顯示插值後的圖像
figure,imshow(uint8(newImage));title('BicubicInterpolation');
           
%% --------------------------------
%% author:wtzhu
%% date: 20210202
%% fuction: 雙三次插值算法sin函數的拟合函數
%% --------------------------------
function A = sw(w1)
w = abs(w1);
if w < 1 && w >= 0
   A = 1 - 2 * w^2 + w^3;  
elseif w >= 1 && w < 2
   A = 4 - 8 * w + 5 * w^2 - w^3;
else
   A = 0;
end
           
ISP——圖像插值算法

能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-koHoR6JW-1626620126797)(.\images\7.jpg)]

總結

通過分析三種算法可以看出,最鄰近方式最簡單,計算量小,但是插值效果一般;

雙三次插值算法的計算量最大,但是插值出來的效果最好;

雙線性插值算法則介于兩者之間。

提示

  1. 為了友善下載下傳,本項目沒有更新到github,用的gitee,可以在ISPAlgorithmStudy: ISP算法學習彙總,主要是論文總結 (gitee.com)倉庫中擷取相關的資料代碼等。
  2. 本期B站有視訊同步講解,LSC_哔哩哔哩_bilibili,可以關注B站,後續會有更多算法的視訊講解同步;
  3. 知乎專欄ISP圖像處理 - 知乎 (zhihu.com)也會有算法簡介同步;

繼續閱讀