双线性插值在图像处理和gis分析中用到还比较多,整理下原理并写了个简单的示例
双线性插值,又称为双线性内插。在数学上,双线性插值是有两个变量的插值函数的线性插值,其核心思想是在两个方向分别进行一次线性插值。
线性插值
根据定义和名字,可以看出就是两个方向的线性插值
线性插值法,是指使用连接两个已知量的直线来确定在这两个已知量之间的一个未知量的值的方法。
假设我们已知坐标(x0,y0)与(x1,y1),要得到[x0,x1]区间内某一位置x在直线上的值。根据图中所示,我们得到两点式直线方程:
可以理解为就是用x和x0,x1的距离作为一个权重,用于y0和y1的加权。
双线性插值
假如我们想得到未知函数f在点P= (x,y) 的值,假设我们已知函数f在Q11 = (x1,y1)、Q12 = (x1,y2),Q21 = (x2,y1) 以及Q22 = (x2,y2) 四个点的值。
首先在x方向进行线性插值,得到R1和R2,
然后在y方向进行线性插值,得到P.
整合后的公式如下
示例
先上效果图:
画了4个canvas,利用四个角给定固定值(采用了随机数),计算画布内的像素值
创建画布
createcanvas('c1', 0, 0);
createcanvas('c2', 220, 0);
createcanvas('c3', 0, 220);
createcanvas('c4', 220, 220);
给定四个已知量
var v1 = rn();
var v2 = rn();
var v3 = rn();
var v4 = rn();
画出第一个画布的四个角,其他三个同样操作
createPixel('c1', 0, 0, v1);
createPixel('c1', 190, 0, v2);
createPixel('c1', 0, 190, v3);
createPixel('c1', 190, 190, v4);
插值出第二个画布的四个边的中心点
interpolate('c2', 0, 100);
interpolate('c2', 100, 0);
interpolate('c2', 100, 190);
interpolate('c2', 190, 100);
interpolate('c2', 100, 100);
第三个就是多画了几个点,直接插值第四个的全部
interpolateGrid('c4');
核心插值实现也比较简单,套公式即可,给出代码
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)
}
}
}
欢迎批评指正