基于Python實(shí)現(xiàn)二維圖像雙線性插值
在對二維數(shù)據(jù)進(jìn)行 resize / mapping / 坐標(biāo)轉(zhuǎn)換等操作時,經(jīng)常會將原本的整數(shù)坐標(biāo)變換為小數(shù)坐標(biāo),對于非整數(shù)的坐標(biāo)值一種直觀有效的插值方式為雙線性插值。
插值簡介
雙線性插值,又稱為雙線性內(nèi)插。在數(shù)學(xué)上,雙線性插值是有兩個變量的插值函數(shù)的線性插值擴(kuò)展,其核心思想是在兩個方向分別進(jìn)行一次線性插值。
雙線性插值作為數(shù)值分析中的一種插值算法,廣泛應(yīng)用在信號處理,數(shù)字圖像和視頻處理等方面。
假設(shè)我們出現(xiàn)了需要在四個相鄰正方形整數(shù)點(diǎn)(A,B,C,D)坐標(biāo)中間(正方形范圍內(nèi))選擇一個點(diǎn)(a,b)取近似值的情形。
此時我們已知的是四個點(diǎn)的數(shù)值VA?,VB?,VC?,VD?,給定小數(shù)坐標(biāo)E(a,b),0≤a,b≤1,如何插值求解E點(diǎn)的數(shù)值呢,解決類似問題的方法統(tǒng)稱為插值,上圖展示公式為雙線性插值的計算方法。
最近鄰法 (Nearest Interpolation)
一種最簡便的方法為最近鄰法,直接取與當(dāng)前點(diǎn)距離最近的點(diǎn)的值作為插值結(jié)果:

其中 roundroundround 為四舍五入的取整操作,方法簡便速度極快,但往往不夠精細(xì)
雙三次插值 (Bicubic interpolation)
雙三次插值是用原圖像中16(4*4)個點(diǎn)計算新圖像中1個點(diǎn),效果比較好,但是計算代價過大。
雙線性插值 (Bilinear Interpolation)
使用一個點(diǎn)進(jìn)行插值過于粗暴,16個點(diǎn)又過于繁瑣,那就使用EEE?點(diǎn)周圍4個點(diǎn)的數(shù)值來近似求解,這是一種平衡了計算代價和插值效果的折中方案,也是各大變換庫的默認(rèn)插值操作。
雙線性插值
通過觀察上述動圖(可以動手挪一挪)可以清晰地看到,雙線性插值本質(zhì)就是把四個角落的數(shù)值按照正方形面積的比例線性加權(quán)后的結(jié)果。
好吧一句話已經(jīng)把數(shù)學(xué)的核心部分講完了
那么既然理解了本質(zhì),數(shù)學(xué)公式就好寫了:

python實(shí)現(xiàn)
在實(shí)現(xiàn)時當(dāng)然 for 循環(huán)大法可以解決一切問題,但總歸是不太優(yōu)雅,我們嘗試使用 numpy 操作完成雙線性插值
假設(shè)原始圖像 image,變換后的小數(shù)坐標(biāo) X 矩陣 x_grid,Y 矩陣 y_grid,那么可以使用如下的 bilinear_by_meshgrid 函數(shù)快速雙線性插值,已經(jīng)處理好了邊界,可以放心使用。
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該函數(shù)集成在我自己的python庫 mtutils 中,可以通過:
pip install mtutils
直接安裝,之后可以直接引用:
from mtutils import bilinear_by_meshgrid
以上就是基于Python實(shí)現(xiàn)二維圖像雙線性插值的詳細(xì)內(nèi)容,更多關(guān)于Python雙線性插值的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python基于最小二乘法實(shí)現(xiàn)曲線擬合示例
這篇文章主要介紹了Python基于最小二乘法實(shí)現(xiàn)曲線擬合,涉及Python基于numpy及scipy庫進(jìn)行曲線擬合操作相關(guān)運(yùn)算技巧,需要的朋友可以參考下2018-06-06
使用Python腳本來控制Windows Azure的簡單教程
這篇文章主要介紹了使用Python腳本來控制Windows Azure的簡單教程,由于微軟官方提供了Python SDK,使得用戶自己用Python控制Azure成為了可能,需要的朋友可以參考下2015-04-04
Python如何實(shí)現(xiàn)拆分?jǐn)?shù)據(jù)集
這篇文章主要介紹了Python如何實(shí)現(xiàn)拆分?jǐn)?shù)據(jù)集問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09
報錯No?module?named?numpy問題的解決辦法
之前安裝了Python,后來因?yàn)榫毩?xí)使用Python寫科學(xué)計算的東西,又安裝了Anaconda,但是安裝Anaconda之后又出現(xiàn)了一個問題,下面這篇文章主要給大家介紹了關(guān)于報錯No?module?named?numpy問題的解決辦法,需要的朋友可以參考下2022-08-08
Python如何讀取16進(jìn)制byte數(shù)據(jù)
這篇文章主要介紹了Python如何讀取16進(jìn)制byte數(shù)據(jù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05

