js双线性插值双三次插值法实现
js 双线性插值双三次插值法实现
介绍
在⽹页中利⽤canvas进⾏绘图时,遇到⼀个问题,原始的数据分辨率很⼩,⽽图⽚要放⼤到整个⽹页,所以需要把数据进⾏插值放⼤。学习了双线性插值和三次内插法插值,两种⽅式实现效果不同,都⽤js代码实现了⼀下,下⾯给⼤家分享⼀下
双线性插值
原理
双线性插值即在x和y两个⽅向上,对数据各进⾏⼀次线性插值。
原始数据的矩阵,即⼀个⼆维数组,⼤⼩为a*b,⽬标矩阵⼤⼩为m*n,m、n⽐a、b可以⼤(放⼤),也可以⼩(缩⼩),当然⽐例也可以不⼀样, 取决于你插值后的数据需要多⼤。
基本思想为,遍历⽬标矩阵的坐标,如x*y这个点,到这个点在原始矩阵中对应的位置,称为映射点,
然后到这个映射点P在原始矩阵中周围的四个点,然后根据映射点P到这个四个点的x和y⽅向上的坐标的距离,进⾏两次线性插值,得到映射点的值即可。
js 二维数组
如上图所⽰,p点为⽬标矩阵中x*y点在原始矩阵中映射的位置,它周围最近的有Q12,Q11,Q21,Q22四个点,现在x⽅向进⾏线性插值,得到R1和R2两个点的值,再在y⽅向进⾏⼀次线性插值,得到P点的值。
注意:⽤双线性插值放⼤数据后,如果放⼤倍数过⼤,⽣成图⽚后发现有着明显的马赛克现象
实现代码参考后⾯js代码
双三次插值法
原理
双三次插值⼜称⽴⽅卷积插值。三次卷积插值是⼀种更加复杂的插值⽅式。该算法利⽤待采样点周围16个点的灰度值作三次插值,不仅考虑到4 个直接相邻点的灰度影响,⽽且考虑到各邻点间灰度值变化率的影响。具体的原理可参考下⾯博客:
基本原理就是,先到⽬标矩阵中点在源数据矩阵中的映射点P,然后到P点周围16个点,然后根据P点坐标距离16个点的x和y⽅向的距离,利⽤BiCubic函数算出每个点的权重,最后每个点乘以权重后,加起来即可得到P的值。
BiCubic函数:
其中,a取-0.5时,BiCubic函数具有如下形状:
取a=-0.5时,放⼤的数据挺好,⽣成的图⽚⾮常平滑,也保留了很多细节。
具体为什么要⽤这个函数,我也没有深⼊研究,不过利⽤该⽅法放⼤数据后,⽣成图⽚效果很好,没有马赛克现象
js实现
/
**
* 数据处理⼯具类(也可以⾃⼰直接定义⽅法,不⽤class)
*/
class DataUtil {
constructor(){}
}
/**
* 数据插值
* @param w ⽬标矩阵宽度
* @param h ⽬标矩阵⾼度
* @param data 源数据矩阵(⼆维数组)
* @param type 插值⽅式,1:双线性插值,2:双三次插值法
* @param type 插值⽅式,1:双线性插值,2:双三次插值法
*/
DataUtil.scaleData=function(w, h, data, type =2){
let t1 =new Date().getTime();
let dw = data[0].length;
let dh = data.length;
let resData =new Array(h);
for(let j =0; j < h; j++){
let line =new Array(w);
for(let i =0; i < w; i++){
let v;
if(type ===2){
// 双三次插值法
v = DataUtil.cubicInterpolation(w, h, i, j, data);
}else if(type ===1){
// 双线性插值
v = DataUtil.interpolation(w, h, i, j, data);
}else{
throw new Error('scale data, type not supported(type must be 1 or 2)'); }
line[i]= und(v);
}
resData[j]= line;
}
let t2 =new Date().getTime();
console.log("数据插值耗时:",(t2 - t1));
return resData;
}
/**
* 双线性插值
* @param sw ⽬标矩阵的宽度
* @param sh ⽬标矩阵的⾼度
* @param x_ ⽬标矩阵中的x坐标
* @param y_ ⽬标矩阵中的y坐标
* @param data 源数据矩阵(⼆维数组)
*/
DataUtil.interpolation=function(sw, sh, x_, y_, data){
let t1 =new Date().getTime();
let w = data[0].length;
let h = data.length;
let x =(x_ +0.5)* w / sw -0.5;
let y =(y_ +0.5)* h / sh -0.5;
let x1 = Math.floor(x);
let x2 = Math.floor(x +0.5);
let y1 = Math.floor(y);
let y2 = Math.floor(y +0.5);
x1 = x1 <0?0: x1;
y1 = y1 <0?0: y1;
x1 = x1 < w -1? x1 : w -1;
y1 = y1 < h -1? y1 : h -1;
x2 = x2 < w -1? x2 : w -1;
y2 = y2 < h -1? y2 : h -1;
// 取出原矩阵中对应四个点的值
let f11 = data[y1][x1];
let f21 = data[y1][x2];
let f12 = data[y2][x1];
let f22 = data[y2][x2];
// 计算该点的值
let xm = x - x1;
let ym = y - y1;
let r1 =(1- xm)* f11 + xm * f21;
let r2 =(1- xm)* f12 + xm * f22;
let value =(1-ym)* r1 + ym * r2;
return value;
}
/**
* 双三次插值法
* @param sw ⽬标矩阵的宽度
* @param sh ⽬标矩阵的⾼度
* @param x_ ⽬标矩阵中的x坐标
* @param y_ ⽬标矩阵中的y坐标
* @param data 源数据矩阵(⼆维数组)
*/
DataUtil.cubicInterpolation=function(sw, sh, x_, y_, data){
let w = data[0].length;
let h = data.length;
// 计算缩放后坐标对应源数据上的坐标
let x = x_ * w / sw;
let y = y_ * h / sh;
// 计算x和y⽅向的最近的4*4的坐标和权重
let wcx = CubicWeight(x);
let wcy = CubicWeight(y);
// 权重
let wx = wcx.weight;
let wy = wcy.weight;
// 坐标
let xs = dinate;
let ys = dinate;
let val =0;
// 遍历周围4*4的点,根据权重相加
for(let j =0; j <4; j++){
let py = ys[j];
py = py <0?0: py;
py = py > h -1? h -1: py;
for(let i =0; i <4; i++){
let px = xs[i];
px = px <0?0: px;
px = px > w -1? w -1: px;
// 该点的值
let dv = data[py][px];
// 该点的权重
let w_x = wx[i];
let w_y = wy[j];
// 根据加权加起来
val +=(dv * w_x * w_y);
}
}
return val;
}
/**
* 双三次插值法中,基于BiCubic基函数,计算源坐标v,最近的4*4的坐标和坐标对应的权重 * @param v ⽬标矩阵中坐标对应在源矩阵中坐标值
*/
*/
let a =-0.5;
// 取整
let nv = Math.floor(v);
// 坐标差值集合
let xList =new Array(4);
// 坐标集合
let xs =new Array(4);
// 最近的4个坐标差值
xList[0]= nv - v -1;
xList[1]= nv - v
xList[2]= nv - v +1;
xList[3]= nv - v +2;
//
xs[0]= nv -1;
xs[1]= nv;
xs[2]= nv +1;
xs[3]= nv +2;
// 计算权重
let ws =new Array(4);
for(let i =0; i <4; i++){
let val = Math.abs(xList[i]);
let w =0;
// 基于BiCubic基函数的双三次插值
if(val <=1){
w =(a +2)* val * val * val -(a +3)* val * val +1;
}else if(val <2){
w = a * val * val * val -5* a * val * val +8* a * val -4* a; }
ws[i]= w;
}
return{
weight: ws,
coordinate: xs
};
}
项⽬中有上述源码,和使⽤案例

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。