雙線性插值在圖像處理和gis分析中用到還比較多,整理下原理并寫(xiě)了個(gè)簡(jiǎn)單的示例
雙線性插值,又稱為雙線性內(nèi)插。在數(shù)學(xué)上,雙線性插值是有兩個(gè)變量的插值函數(shù)的線性插值,其核心思想是在兩個(gè)方向分別進(jìn)行一次線性插值。
線性插值
根據(jù)定義和名字,可以看出就是兩個(gè)方向的線性插值
線性插值法,是指使用連接兩個(gè)已知量的直線來(lái)確定在這兩個(gè)已知量之間的一個(gè)未知量的值的方法。

假設(shè)我們已知坐標(biāo)(x0,y0)與(x1,y1),要得到[x0,x1]區(qū)間內(nèi)某一位置x在直線上的值。根據(jù)圖中所示,我們得到兩點(diǎn)式直線方程:


可以理解為就是用x和x0,x1的距離作為一個(gè)權(quán)重,用于y0和y1的加權(quán)。
雙線性插值
假如我們想得到未知函數(shù)f在點(diǎn)P= (x,y) 的值,假設(shè)我們已知函數(shù)f在Q11 = (x1,y1)、Q12 = (x1,y2),Q21 = (x2,y1) 以及Q22 = (x2,y2) 四個(gè)點(diǎn)的值。

首先在x方向進(jìn)行線性插值,得到R1和R2,


然后在y方向進(jìn)行線性插值,得到P.

整合后的公式如下

示例
先上效果圖:

畫(huà)了4個(gè)canvas,利用四個(gè)角給定固定值(采用了隨機(jī)數(shù)),計(jì)算畫(huà)布內(nèi)的像素值
創(chuàng)建畫(huà)布
createcanvas('c1', 0, 0);
createcanvas('c2', 220, 0);
createcanvas('c3', 0, 220);
createcanvas('c4', 220, 220);
給定四個(gè)已知量
var v1 = rn();
var v2 = rn();
var v3 = rn();
var v4 = rn();
畫(huà)出第一個(gè)畫(huà)布的四個(gè)角,其他三個(gè)同樣操作
createPixel('c1', 0, 0, v1);
createPixel('c1', 190, 0, v2);
createPixel('c1', 0, 190, v3);
createPixel('c1', 190, 190, v4);
插值出第二個(gè)畫(huà)布的四個(gè)邊的中心點(diǎn)
interpolate('c2', 0, 100);
interpolate('c2', 100, 0);
interpolate('c2', 100, 190);
interpolate('c2', 190, 100);
interpolate('c2', 100, 100);
第三個(gè)就是多畫(huà)了幾個(gè)點(diǎn),直接插值第四個(gè)的全部
interpolateGrid('c4');
核心插值實(shí)現(xiàn)也比較簡(jiǎn)單,套公式即可,給出代碼
function createcanvas(id, x0, y0) {
var canvas = document.createElement('canvas');
canvas.id = id;
canvas.setAttribute("width", 200);
canvas.setAttribute("height", 200);
canvas.style.position = 'absolute';
canvas.style.top = x0 + 'px';
canvas.style.left = y0 + 'px';
document.body.appendChild(canvas);
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#cccccc';
ctx.fillRect(0, 0, 200, 200);
}
function createPixel(id, x, y, value) {
var canvas = document.getElementById(id);
var ctx = canvas.getContext('2d');
var clrRed = value;
ctx.fillStyle = "rgb(" + value + ",0,0)";;
ctx.fillRect(x, y, 10, 10);
}
function rn() {
return Math.round(Math.random() * 255);
}
function interpolate(id, x, y) {
//多次線性插值
// var rx1 = linear(0, v1, 200, v2, x);
// var rx2 = linear(0, v3, 200, v4, x);
// var ry = linear(0, rx1, 200, rx2, y);
//直接雙線性插值
var ry = bilinear(x, y, v1, v2, v3, v4);
createPixel(id, x, y, ry);
}
function linear(x0, y0, x1, y1, x) {
return (x1 - x) / (x1 - x0) * y0 + (x - x0) / (x1 - x0) * y1
}
function bilinear(x, y, g00, g10, g01, g11) {
var Δx = 200;
var Δy = 200;
var rx = Δx - x;
var ry = Δy - y;
var Δv = Δx * Δy
var a = rx * ry,
b = x * ry,
c = rx * y,
d = x * y;
var u = g00 / Δv * a + g10 / Δv * b + g01 / Δv * c + g11 / Δv * d;
return u;
}
function interpolateGrid(id) {
for (let i = 0; i < 190; i++) {
for (let j = 0; j < 190; j++) {
interpolate(id, i, j)
}
}
}
歡迎批評(píng)指正