Python实现二维图像双线性插值:原理与高效代码

Oliver
Oliver
发布时间:2026-10-15 | 4人浏览过
原创

本文详解二维图像双线性插值的数学原理及其在Python中的高效实现。通过对比最近邻与双三次插值,阐述双线性插值在计算成本与效果间的平衡。提供基于NumPy meshgrid的完整代码示例,处理边界问题,适用于图像Resize、坐标映射等场景。

在对二维数据进行 resize、mapping 或坐标转换等操作时,整数坐标常需变换为小数坐标。针对非整数坐标值,双线性插值是一种直观且有效的处理方法。

插值简介

双线性插值(又称双线性内插)在数学上属于两个变量的插值函数的线性插值扩展。其核心思想是分别在两个方向上各执行一次线性插值。

作为数值分析中的经典算法,双线性插值广泛应用于信号处理、数字图像及视频处理等领域。

假设需要在四个相邻正方形整数点 A、B、C、D 所围成的区域内,选取一点 (a,b) 进行近似取值。

已知四个顶点的数值分别为 VA、VB、VC、VD,给定小数坐标 E(a,b),其中 0≤a,b≤1,求解 E 点数值的方法统称为插值。双线性插值的计算逻辑即基于此原理展开。

最近邻法 (Nearest Interpolation)

最简便的方法是最近邻法,即直接选取距离当前点最近的整数点的数值作为插值结果。

其中 round 为四舍五入取整操作。该方法速度极快,但精度往往不够精细。

双三次插值 (Bicubic interpolation)

双三次插值利用原图像中 16 个(4*4)点来计算新图像中的一个点,效果较好,但计算代价过大。

双线性插值 (Bilinear Interpolation)

仅使用一个点进行插值过于粗糙,而使用 16 个点又过于繁琐。双线性插值利用目标点周围 4 个点的数值进行近似求解,在计算代价与插值效果之间取得了平衡,因此成为各大变换库的默认插值方式。

双线性插值

通过观察相关动图可知,双线性插值的本质是将四个角落的数值按照正方形面积的比例进行线性加权。

一句话概括,即数学核心部分已阐明。

理解本质后,数学公式的推导便顺理成章。

python实现

虽然 for 循环可以解决问题,但不够优雅。我们可以尝试使用 NumPy 操作来高效完成双线性插值。

假设原始图像为 image,变换后的小数坐标 X 矩阵为 x_grid,Y 矩阵为 y_grid,则可使用如下 bilinear_by_meshgrid 函数快速实现双线性插值。该函数已处理边界情况,可直接使用。

def bilinear_by_meshgrid(image, x_grid, y_grid):

    #               Ia, Wd                          Ic, Wb
    #           (floor_x, floor_y)              (ceil_x, floor_y)   
    #
    #                               (x, y)
    #
    #               Ib , Wc                         Id, Wa
    #           (floor_x, ceil_y)               (ceil_x, ceil_y)   
    #

    assert image.shape == x_grid.shape == y_grid.shape
    assert image.ndim == 2
    H, W = image.shape[:2]

    floor_x_grid = np.floor(x_grid).astype('int32')
    floor_y_grid = np.floor(y_grid).astype('int32')
    ceil_x_grid = floor_x_grid + 1
    ceil_y_grid = floor_y_grid + 1

    if np.max(ceil_x_grid) > W -1 or  np.max(ceil_y_grid) > H -1 or np.min(floor_x_grid) < 0 or np.min(floor_y_grid) < 0:
        print("Warning: index value out of original matrix, a crop operation will be applied.")

        floor_x_grid = np.clip(floor_x_grid, 0, W-1).astype('int32')
        ceil_x_grid = np.clip(ceil_x_grid, 0, W-1).astype('int32')
        floor_y_grid = np.clip(floor_y_grid, 0, H-1).astype('int32')
        ceil_y_grid = np.clip(ceil_y_grid, 0, H-1).astype('int32')

    Ia = image[ floor_y_grid, floor_x_grid ]
    Ib = image[ ceil_y_grid, floor_x_grid ]
    Ic = image[ floor_y_grid, ceil_x_grid ]
    Id = image[ ceil_y_grid, ceil_x_grid ]

    wa = (ceil_x_grid - x_grid) * (ceil_y_grid - y_grid)
    wb = (ceil_x_grid - x_grid) * (y_grid - floor_y_grid)
    wc = (x_grid - floor_x_grid) * (ceil_y_grid - y_grid)
    wd = (x_grid - floor_x_grid) * (y_grid - floor_y_grid)

    assert np.min(wa) >=0 and np.min(wb) >=0 and np.min(wc) >=0 and np.min(wd) >=0
    
    W = wa + wb + wc + wd
    assert np.sum(W[:, -1]) + np.sum(W[-1, :]) == 0
    
    wa[:-1, -1] = ceil_y_grid[:-1, -1] - y_grid[:-1, -1]
    wb[:-1, -1] = y_grid[:-1, -1] - floor_y_grid[:-1, -1]
    
    wb[-1, :-1] = ceil_x_grid[-1, :-1] - x_grid[-1, :-1]
    wd[-1, :-1] = x_grid[-1, :-1] - floor_x_grid[-1, :-1]
    
    wd[-1, -1] = 1
    
    W = wa + wb + wc + wd
    assert np.max(W) == np.min(W) == 1
    
    res_image = wa*Ia + wb*Ib + wc*Ic + wd*Id

    return res_image

该函数已集成在作者的 Python 库 mtutils 中,可通过以下方式安装:

pip install mtutils

安装后,可直接引用该模块:

from mtutils import bilinear_by_meshgrid

以上即为基于 Python 实现二维图像双线性插值的详细内容,更多关于 Python 双线性插值的资料可关注本站其他相关文章。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表