首頁 > 軟體

基於Python實現二維影象雙線性插值

2022-06-11 18:00:47

在對二維資料進行 resize / mapping / 座標轉換等操作時,經常會將原本的整數座標變換為小數座標,對於非整數的座標值一種直觀有效的插值方式為雙線性插值。

插值簡介

雙線性插值,又稱為雙線性內插。在數學上,雙線性插值是有兩個變數的插值函數的線性插值擴充套件,其核心思想是在兩個方向分別進行一次線性插值。

雙線性插值作為數值分析中的一種插值演演算法,廣泛應用在訊號處理,數位影像和視訊處理等方面。

假設我們出現了需要在四個相鄰正方形整數點(A,B,C,D)座標中間(正方形範圍內)選擇一個點(a,b)取近似值的情形。

此時我們已知的是四個點的數值VA​,VB​,VC​,VD​,給定小數座標E(a,b),0≤a,b≤1,如何插值求解E點的數值呢,解決類似問題的方法統稱為插值,上圖展示公式為雙線性插值的計算方法。

最近鄰法 (Nearest Interpolation)

一種最簡便的方法為最近鄰法,直接取與當前點距離最近的點的值作為插值結果:

其中 roundroundround 為四捨五入的取整操作,方法簡便速度極快,但往往不夠精細

雙三次插值 (Bicubic interpolation)

雙三次插值是用原影象中16(4*4)個點計算新影象中1個點,效果比較好,但是計算代價過大。

雙線性插值 (Bilinear Interpolation)

使用一個點進行插值過於粗暴,16個點又過於繁瑣,那就使用EEE​點周圍4個點的數值來近似求解,這是一種平衡了計算代價和插值效果的折中方案,也是各大變換庫的預設插值操作。

雙線性插值

通過觀察上述動圖(可以動手挪一挪)可以清晰地看到,雙線性插值本質就是把四個角落的數值按照正方形面積的比例線性加權後的結果。

好吧一句話已經把數學的核心部分講完了

那麼既然理解了本質,數學公式就好寫了:

python實現

在實現時當然 for 迴圈大法可以解決一切問題,但總歸是不太優雅,我們嘗試使用 numpy 操作完成雙線性插值

假設原始影象 image,變換後的小數座標 X 矩陣 x_grid,Y 矩陣 y_grid,那麼可以使用如下的 bilinear_by_meshgrid 函數快速雙線性插值,已經處理好了邊界,可以放心使用。

def bilinear_by_meshgrid(image, x_grid, y_grid):

    #               Ia, Wd                          Ic, Wb
    #           (floor_x, floor_y)              (ceil_x, floor_y)   
    #
    #                               (x, y)
    #
    #               Ib , Wc                         Id, Wa
    #           (floor_x, ceil_y)               (ceil_x, ceil_y)   
    #

    assert image.shape == x_grid.shape == y_grid.shape
    assert image.ndim == 2
    H, W = image.shape[:2]

    floor_x_grid = np.floor(x_grid).astype('int32')
    floor_y_grid = np.floor(y_grid).astype('int32')
    ceil_x_grid = floor_x_grid + 1
    ceil_y_grid = floor_y_grid + 1

    if np.max(ceil_x_grid) > W -1 or  np.max(ceil_y_grid) > H -1 or np.min(floor_x_grid) < 0 or np.min(floor_y_grid) < 0:
        print("Warning: index value out of original matrix, a crop operation will be applied.")

        floor_x_grid = np.clip(floor_x_grid, 0, W-1).astype('int32')
        ceil_x_grid = np.clip(ceil_x_grid, 0, W-1).astype('int32')
        floor_y_grid = np.clip(floor_y_grid, 0, H-1).astype('int32')
        ceil_y_grid = np.clip(ceil_y_grid, 0, H-1).astype('int32')

    Ia = image[ floor_y_grid, floor_x_grid ]
    Ib = image[ ceil_y_grid, floor_x_grid ]
    Ic = image[ floor_y_grid, ceil_x_grid ]
    Id = image[ ceil_y_grid, ceil_x_grid ]

    wa = (ceil_x_grid - x_grid) * (ceil_y_grid - y_grid)
    wb = (ceil_x_grid - x_grid) * (y_grid - floor_y_grid)
    wc = (x_grid - floor_x_grid) * (ceil_y_grid - y_grid)
    wd = (x_grid - floor_x_grid) * (y_grid - floor_y_grid)

    assert np.min(wa) >=0 and np.min(wb) >=0 and np.min(wc) >=0 and np.min(wd) >=0
    
    W = wa + wb + wc + wd
    assert np.sum(W[:, -1]) + np.sum(W[-1, :]) == 0
    
    wa[:-1, -1] = ceil_y_grid[:-1, -1] - y_grid[:-1, -1]
    wb[:-1, -1] = y_grid[:-1, -1] - floor_y_grid[:-1, -1]
    
    wb[-1, :-1] = ceil_x_grid[-1, :-1] - x_grid[-1, :-1]
    wd[-1, :-1] = x_grid[-1, :-1] - floor_x_grid[-1, :-1]
    
    wd[-1, -1] = 1
    
    W = wa + wb + wc + wd
    assert np.max(W) == np.min(W) == 1
    
    res_image = wa*Ia + wb*Ib + wc*Ic + wd*Id

    return res_image

該函數整合在我自己的python庫 mtutils 中,可以通過:

pip install mtutils

直接安裝,之後可以直接參照:

from mtutils import bilinear_by_meshgrid

以上就是基於Python實現二維影象雙線性插值的詳細內容,更多關於Python雙線性插值的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com