1、介紹雙線性插值算法前先講下線性插值(Linear Interpolate):
在數學中,線性插值是一種曲線擬合方法,利用線性多項式在已知數據點的離散集合范圍內構造新的數據點。
兩個已知點之間的線性插值:
已知兩點由坐標(x0,y0)和(x1,y1)給出,線性插值就是兩點之間的直線。對於區間(x0,x1)中的x值,由方程給出沿直線的y值


已知2點(x0, y0)、(x1, y1),
設線性方程:f(x) = ax + b
則有:
y0 = f(x0) = a * x0 + b;
y1 = f(x1) = a * x1 + b;
=>
y1 - y0 = a (x1 - x0)
得:a = (y1 - y0) / (x1 - x0),a是斜率
y0 = a * x0 + b = (y1 - y0) / (x1 - x0) * x0 + b
b = (x1 * y0 - x0 * y1) / (x1 - x0)
=>
y = f(x) = (y1 - y0) / (x1- x0) * x +(x1 * y0 - x0 * y1) / (x1 - x0)
應用舉例:D3.js的d3.interpolateRgb顏色插值原理應該用的是線性插值算法,根據RGB3個分量值的范圍(0-255)分別進行線性插值。
2、雙線性插值(Bilinear Interpolate)
在數學上,雙線性插值是線性插值的拓展,是針對2維直線網格上的2個自變量函數z = f(x, y)的插值,涉及到2元函數,要復雜點。
主要思想是先在一個方向上執行線性插值,再在另一個方向上操作一次。雖然樣本值和樣本位置中的每一步插值是線性的,但是整體上是非線性的。

注:紅色點是原有的數據點,綠色點是我們想要插值的結果。
算法思路:
令我們要找的未知值的函數關系 f 和相應坐標(x, y), 假設已知的4個點是Q11 = (x1, y1),Q12=(x2, y2),Q21=(x2, y1), Q22=(x2, y2)。
首先在x軸上做線性插值,得到如下式子:

分析:
點R1是在Q11與Q21之間在x軸上進行一次線性插值的結果,y值都是y1不變。
f(x, y1) ≈ a * f(Q11) + b * f(Q21)
a = (x2 - x) / (x2 - x1), b = (x - x1) / (x2 - x1),這2個系數是如何確定的?
我認為和點的(x, y)位置相關,Q11、Q21對點R1的值f(x, y1)的影響程度取決於它們和R1點的距離值,也就是|x - x1|和|x2 - x|,誰與點R1距離近,影響程度越大,也就是相應的系數越大。
總的距離為| x2 - x1|,即點Q11與Q21之間的距離D, R1距離Q11為d1 = |x - x1|, R1距離Q21為d2 = |x2 - x|,且R1位於Q11與Q21之間,即 x1 < x < x2, 當d1減小時,d2會變大,而此時Q11的相關系數a應該變大,Q21的相關系數b應變小,觀察發現d1/D會隨着d1變小而變小,d2 = D-d1, d2/D會隨着d1變小而變大,因此a = d2/D = (x2 - x) / (x2 - x1),b = (x - x1) / (x2 - x1),這樣a * f(Q11)在隨R1靠近點Q11而變大,b * f(Q21)隨R11遠離Q21而變小,滿足條件。
我們繼續在y軸上插值得到估算式子:

注:先在x軸還是y軸上插值的最終結果是一致的,順序不影響插值結果。
上面的代數式比較繁,我們可以用矩陣來求解,以達到化繁為簡。
設二元函數如下:

代入四個已知點,系數a0,a1,a2,a3可以通過解線性系統得到:

若一個解用f(Q)表示,我們可以寫成:

推導:
a0 + a1 * x + a2 * y + a3 * xy = b11 * f(Q11) + b12 * f(Q12) + b21 * f(Q21) + b22 * f(Q22)
=>

=>
=>
=>
=>
=>
得出最終式子:
(5)
系數可以通過解線性系統獲得。
若用一個坐標系來表示Q11 =(0,0)、Q12 =(0,1)、Q21 =(1, 0)、Q22 =(1, 1)四個已知的點,則插值公式可以簡化為:

上面的式子可以直接把坐標代入式子(3)得到,也可以解式子(5)矩陣求得系數b11、b12、b21、b22,再代入(4)得到,計算過程如下(復習下線性代數):
復習:矩陣A的逆矩陣A^-1可以用高斯若爾當消元法;A*A^-1 = I(單位矩陣); (A^-1)^T = (A^T)^-1。
得:b11 = (1 - x) * (1 - y), b12 = y * (1 - y) , b21 = x * (1 - y) , b22 = xy
f(x, y) = b11 * f(Q11) + b12 * f(Q12) + b21 * f(Q21) + b22 * f(Q22) = (1 - x) * (1 - y) * f(0, 0) + y * (1 - x) * f(0, 1) + x * (1 - y) * f(1, 0) + xy * f(1, 1), 整理即為式(6)
3、雙線性插值算法應用:對NCEP氣象數據使用雙線性插值以增加數據的稠密度,改善繪制的氣象圖譜效果。
溫度分布圖繪制:
/** * 直接根據原始數據繪制,不插值 */ private void drawGridsWithoutInterpolation(){ int x = 0, xMax = this.imgWidth, y = 0, yMax = this.imgHeight; int nx = this.entity.getNx(); int ny = this.entity.getNy(); double lo1 = this.entity.getLo1(); double lo2 = this.entity.getLo2(); double la1 = this.entity.getLa1(); double la2 = this.entity.getLa2(); double deltLO = lo2 - lo1; double deltLA = la2 - la1; Double[] data = this.entity.getData(); double[] color = {0, 0, 0, 0}; //Transparent black for(int i=x; i<xMax; i++) { for(int j=y; j<yMax; j++){ Point p = CRSutil.toPoint(i, j); p = p.add(this.pixelOrigin); LngLat lnglat = this.crs.pixelPointToLngLat(p); double lng = lnglat.lng; double lat = lnglat.lat; int col = (int) Math.floor((lng -lo1)/deltLO * nx); int row = (int) Math.floor((lat -la1)/deltLA * ny); if(col<0) { col = 0; } if(col>=xMax){ col = xMax-1; } if(row<0){ row = 0; } if(col>=yMax){ row = yMax - 1; } int index = row * nx + col; double value = data[index]; color = this.scale.getPointColor(value, OVERLAY_ALPHA); drawGrid(i, j, color); drawGrid(i+1, j, color); drawGrid(i, j+1, color); drawGrid(i+1, j+1, color); } } }
/** * 先插值再繪制 */ private void interpolateField() { int x = 0, xMax = this.imgWidth, y = 0, yMax = this.imgHeight; Double scalar = 0d; double[] color = {0, 0, 0, 0}; //Transparent black for(int i=x; i<xMax; i+=2) { for(int j=y; j<=yMax; j+=2) { Point p = CRSutil.toPoint(i, j); p = p.add(this.pixelOrigin); LngLat lnglat = this.crs.pixelPointToLngLat(p); if(this.entity.getMeteoType().equals(MeteoTypeEnum.WIND)){ //TODO }else{ scalar = interpolate(lnglat, this.grid); if(scalar==null){ continue; } color = this.scale.getPointColor(scalar, OVERLAY_ALPHA); // logger.info(scalar+"--"+color[0]+","+color[1]+","+color[2]+","+color[3]); drawGrid(i, j, color); drawGrid(i+1, j, color); drawGrid(i, j+1, color); drawGrid(i+1, j+1, color); } } } }
效果圖對比: