双线性内插怎么缩小_【图像缩放】双线性插值

本文介绍了图像处理中的双线性内插算法,作为介于最邻近插值和双立方插值之间的折中选择。双线性插值通过计算邻近4个像素点的加权平均值来实现,导致轻微模糊但计算量适中。文中给出了JavaScript代码实现,并提及该算法在实际应用中的常见用途。
摘要由CSDN通过智能技术生成

前言

图像处理中有三种常用的插值算法:

最邻近插值

双线性插值

双立方(三次卷积)插值

本文介绍其中的双线性插值

如果想先看效果和源码,可以拉到最底部

何时进行双线性插值

相比于最邻近插值的粗糙以及双立方插值的计算量大,双线性插值的效果比较折中

计算量不是那么巨大

效果也还可以

一般可以作为应用中的默认处理算法

需要注意的是,使用双线性插值后有明显的模糊效果(低通滤波)

数学理论

双线性插值只涉及到邻近的4个像素点,如图

3d4965c2bea51b478e8b917260467c0b.png

简单分析如下:

目标插值图中的某像素点(distI, distJ)在原图中的映射为(i + v, j + u)

(i + v, j + u)处值的计算就是邻近4个像素点的分别在x轴和y轴的权值和

插值公式

设f(i, j)为(i, j)坐标点的值(灰度值)

u为列方向的偏差

v为行方向的偏差

那么插值公式如下(最终F(i + v, j + u)处的实际值)

F(i + v, j + u) = partV + partV1;

partV = v * ((1 - u) * f(i + 1, j) + u * f(i + 1, j + 1));

partV1 = (1 - v) * ((1 - u) * f(i, j) + u * f(i, j + 1));

或展开为:

F(i + v, j + u) = f(0, 0)(1 - v)(1 - u) + f(0, 1)(1 - v)(u) + f(1, 0)(v)(1 - u) + f(1, 1)(v)(u)

上式中,分别是四个坐标点对x和y方向进行插值,简单的说

u越接近0,(i, j)与(i + 1, j)的权值越大

v越接近0,(i, j)与(i, j + 1)的权值越大

代码实现

以下是JavaScript代码的完整实现

function getRGBAValue(data, srcWidth, srcHeight, row, col) {

let newRow = row;

let newCol = col;

if (newRow >= srcHeight) {

newRow = srcHeight - 1;

} else if (newRow < 0) {

newRow = 0;

}

if (newCol >= srcWidth) {

newCol = srcWidth - 1;

} else if (newCol < 0) {

newCol = 0;

}

let newIndex = (newRow * srcWidth) + newCol;

newIndex *= 4;

return [

data[newIndex + 0],

data[newIndex + 1],

data[newIndex + 2],

data[newIndex + 3],

];

}

function scale(data, width, height, newData, newWidth, newHeight) {

// 计算压缩后的缩放比

const scaleW = newWidth / width;

const scaleH = newHeight / height;

const dstData = newData;

const filter = (dstCol, dstRow) => {

// 源图像中的坐标(可能是一个浮点)

const srcCol = Math.min(width - 1, dstCol / scaleW);

const srcRow = Math.min(height - 1, dstRow / scaleH);

const intCol = Math.floor(srcCol);

const intRow = Math.floor(srcRow);

// 计算u和v

const u = srcCol - intCol;

const v = srcRow - intRow;

// 1-u与1-v

const u1 = 1 - u;

const v1 = 1 - v;

// 真实的index,因为数组是一维的

let dstI = (dstRow * newWidth) + dstCol;

// rgba,所以要乘以4

dstI *= 4;

const rgba00 = getRGBAValue(

data,

width,

height,

intRow + 0,

intCol + 0,

);

const rgba01 = getRGBAValue(

data,

width,

height,

intRow + 0,

intCol + 1,

);

const rgba10 = getRGBAValue(

data,

width,

height,

intRow + 1,

intCol + 0,

);

const rgba11 = getRGBAValue(

data,

width,

height,

intRow + 1,

intCol + 1,

);

for (let j = 0; j <= 3; j += 1) {

const partV = v * ((u1 * rgba10[j]) + (u * rgba11[j]));

const partV1 = v1 * ((u1 * rgba00[j]) + (u * rgba01[j]));

dstData[dstI + j] = partV + partV1;

}

};

for (let col = 0; col < newWidth; col += 1) {

for (let row = 0; row < newHeight; row += 1) {

filter(col, row);

}

}

}

export default function bilinearInterpolation(imgData, newImgData) {

scale(imgData.data,

imgData.width,

imgData.height,

newImgData.data,

newImgData.width,

newImgData.height);

return newImgData;

}

运行效果

可参考同系列中的双立方插值中的效果图

开源项目

这个项目里用JS实现了几种插值算法,包括(最邻近值,双线性,三次卷积-包括两种不同实现等)

附录

博客

初次发布2016.11.02于我个人博客上面

参考资料

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值