雙線性插值不僅可以resize圖片(解決最近鄰鋸齒狀問題),還可以代替反捲積(本質也是resize)。
記錄下原理:
雙線性插值
假設源圖像大小爲mxn,目標圖像爲axb。那麼兩幅圖像的邊長比分別爲:m/a和n/b。注意,通常這個比例不是整數,編程存儲的時候要用浮點型。目標圖像的第(i,j)個像素點(i行j列)可以通過邊長比對應回源圖像。其對應座標爲(i*m/a,j*n/b)。顯然,這個對應座標一般來說不是整數,而非整數的座標是無法在圖像這種離散數據上使用的。雙線性插值通過尋找距離這個對應座標最近的四個像素點,來計算該點的值(灰度值或者RGB值)。
若圖像爲灰度圖像,那麼(i,j)點的灰度值的數學計算模型是:
f(x,y)=b1+b2x+b3y+b4xy
其中b1,b2,b3,b4是相關的係數。關於其的計算過程如下如下:
如圖,已知Q12,Q22,Q11,Q21,但是要插值的點爲P點,這就要用雙線性插值了,首先在x軸方向上,對R1和R2兩個點進行插值,這個很簡單,然後根據R1和R2對P點進行插值,這就是所謂的雙線性插值。
附:維基百科--雙線性插值:
雙線性插值,又稱爲雙線性內插。在數學上,雙線性插值是有兩個變量的插值函數的線性插值擴展,其核心思想是在兩個方向分別進行一次線性插值。
假如我們想得到未知函數 f 在點 P=\left( x, y\right) 的值,假設我們已知函數 f 在 Q_{11} = \left( x_1, y_1 \right), Q_{12} = \left( x_1, y_2 \right), Q_{21} = \left( x_2, y_1 \right), 及 Q_{22} = \left( x_2, y_2 \right) 四個點的值。
首先在 x 方向進行線性插值,得到
f(R_1) \approx \frac{x_2-x}{x_2-x_1} f(Q_{11}) + \frac{x-x_1}{x_2-x_1} f(Q_{21}) \quad\mbox{Where}\quad R_1 = (x,y_1),
f(R_2) \approx \frac{x_2-x}{x_2-x_1} f(Q_{12}) + \frac{x-x_1}{x_2-x_1} f(Q_{22}) \quad\mbox{Where}\quad R_2 = (x,y_2).
然後在 y 方向進行線性插值,得到
f(P) \approx \frac{y_2-y}{y_2-y_1} f(R_1) + \frac{y-y_1}{y_2-y_1} f(R_2).
這樣就得到所要的結果 f \left( x, y \right),
f(x,y) \approx \frac{f(Q_{11})}{(x_2-x_1)(y_2-y_1)} (x_2-x)(y_2-y) + \frac{f(Q_{21})}{(x_2-x_1)(y_2-y_1)} (x-x_1)(y_2-y)
+ \frac{f(Q_{12})}{(x_2-x_1)(y_2-y_1)} (x_2-x)(y-y_1) + \frac{f(Q_{22})}{(x_2-x_1)(y_2-y_1)} (x-x_1)(y-y_1).
如果選擇一個座標系統使得 f 的四個已知點座標分別爲 (0, 0)、(0, 1)、(1, 0) 和 (1, 1),那麼插值公式就可以化簡爲
f(x,y) \approx f(0,0) \, (1-x)(1-y) + f(1,0) \, x(1-y) + f(0,1) \, (1-x)y + f(1,1) xy.
或者用矩陣運算表示爲
f(x,y) \approx \begin{bmatrix}1-x & x \end{bmatrix} \begin{bmatrix}f(0,0) & f(0,1) \\f(1,0) & f(1,1) \end{bmatrix} \begin{bmatrix}1-y \\y \end{bmatrix}
這種插值方法的結果通常不是線性的,線性插值的結果與插值的順序無關。首先進行 y 方向的插值,然後進行 x 方向的插值,所得到的結果是一樣的。
opencv和Matlab中的雙線性插值
這部分的前提是,你已經明白什麼是雙線性插值並且在給定源圖像和目標圖像尺寸的情況下,可以用筆計算出目標圖像某個像素點的值。當然,最好的情況是你已經用某種語言實現了網上一大堆博客上原創或轉載的雙線性插值算法,然後發現計算出來的結果和matlab、openCV對應的resize()函數得到的結果完全不一樣。
那這個究竟是怎麼回事呢?
其實答案很簡單,就是座標系的選擇問題,或者說源圖像和目標圖像之間的對應問題。
按照網上一些博客上寫的,源圖像和目標圖像的原點(0,0)均選擇左上角,然後根據插值公式計算目標圖像每點像素,假設你需要將一幅5x5的圖像縮小成3x3,那麼源圖像和目標圖像各個像素之間的對應關係如下:
只畫了一行,用做示意,從圖中可以很明顯的看到,如果選擇右上角爲原點(0,0),那麼最右邊和最下邊的像素實際上並沒有參與計算,而且目標圖像的每個像素點計算出的灰度值也相對於源圖像偏左偏上。
那麼,讓座標加1或者選擇右下角爲原點怎麼樣呢?很不幸,還是一樣的效果,不過這次得到的圖像將偏右偏下。
最好的方法就是,兩個圖像的幾何中心重合,並且目標圖像的每個像素之間都是等間隔的,並且都和兩邊有一定的邊距,這也是matlab和openCV的做法。
如果你不懂我上面說的什麼,沒關係,只要在計算對應座標的時候改爲以下公式即可,
int x=(i+0.5)*m/a-0.5
int y=(j+0.5)*n/b-0.5
代替
int x=i*m/a
int y=j*n/b