基于Python实现二维图像双线性插值

 更新时间:2022年06月11日 14:36:11   作者:为为为什么  
双线性插值,又称为双线性内插。在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值。本文将用Python实现二维图像双线性插值,感兴趣的可以了解下

在对二维数据进行 resize / mapping / 坐标转换等操作时,经常会将原本的整数坐标变换为小数坐标,对于非整数的坐标值一种直观有效的插值方式为双线性插值。

插值简介

双线性插值,又称为双线性内插。在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值。

双线性插值作为数值分析中的一种插值算法,广泛应用在信号处理,数字图像和视频处理等方面。

假设我们出现了需要在四个相邻正方形整数点(A,B,C,D)坐标中间(正方形范围内)选择一个点(a,b)取近似值的情形。

此时我们已知的是四个点的数值VA​,VB​,VC​,VD​,给定小数坐标E(a,b),0≤a,b≤1,如何插值求解E点的数值呢,解决类似问题的方法统称为插值,上图展示公式为双线性插值的计算方法。

最近邻法 (Nearest Interpolation)

一种最简便的方法为最近邻法,直接取与当前点距离最近的点的值作为插值结果:

其中 roundroundround 为四舍五入的取整操作,方法简便速度极快,但往往不够精细

双三次插值 (Bicubic interpolation)

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

双线性插值 (Bilinear Interpolation)

使用一个点进行插值过于粗暴,16个点又过于繁琐,那就使用EEE​点周围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双线性插值的资料请关注脚本之家其它相关文章!

相关文章

  • PyQt5基本控件使用详解:单选按钮、复选框、下拉框

    PyQt5基本控件使用详解:单选按钮、复选框、下拉框

    这篇文章主要介绍了PyQt5基本控件使用:单选按钮、复选框、下拉框,本文中的内容和实例也基本回答了开篇提到的问题。需要的朋友可以参考下
    2019-08-08
  • numpy.concatenate函数用法详解

    numpy.concatenate函数用法详解

    本文主要介绍了numpy.concatenate函数用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • 浅析python的优势和不足之处

    浅析python的优势和不足之处

    在本篇内容中小编给大家整理了关于分析python的优势和不足的分析,有需要的朋友们参考下。
    2018-11-11
  • 在Python中使用AOP实现Redis缓存示例

    在Python中使用AOP实现Redis缓存示例

    本篇文章主要介绍了在Python中使用AOP实现Redis缓存示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • 详解Python中__new__方法的作用

    详解Python中__new__方法的作用

    Python类中有些方法名、属性名的前后都添加__双下画线,这种方法、属性通常属于Python的特殊方法和特殊属性。本文将聊聊构造方法__new__实际程序的应用场景,感兴趣的可以了解一下
    2022-03-03
  • Python采用raw_input读取输入值的方法

    Python采用raw_input读取输入值的方法

    这篇文章主要介绍了Python采用raw_input读取输入值的方法,对初学者有很好的学习借鉴价值,需要的朋友可以参考下
    2014-08-08
  • Python还能这么玩之用Python做个小游戏的外挂

    Python还能这么玩之用Python做个小游戏的外挂

    玩过电脑游戏的同学对于外挂肯定不陌生,但是你在用外挂的时候有没有想过外挂怎么制作出来的呢?现在来看一下怎么制作一个外挂,首先说下,这里的游戏外挂的概念,和那些大型网游里的外挂可不同,不能自动打怪,主要为了提高一下编程技术,需要的朋友可以参考下
    2021-06-06
  • python里将list中元素依次向前移动一位

    python里将list中元素依次向前移动一位

    这篇文章主要介绍了python里将list中元素依次向前移动一位,以及使用racket 5.2.1实现此功能的代码,希望对大家有所帮助
    2014-09-09
  • Python函数参数的4种方式

    Python函数参数的4种方式

    本文主要介绍了Python函数参数的4种方式,主要包括必选参数,默认参数,可选参数,关键字参数,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • 用Python解析身份证号获取年龄和性别的实现方法

    用Python解析身份证号获取年龄和性别的实现方法

    身份证号码包含了丰富的信息,包括生日和性别,Python提供了处理和解析身份证号的功能,让我们能够从中提取出相关的信息,本文将介绍如何利用Python解析身份证号,获取持有者的年龄和性别信息,感兴趣的朋友可以参考下
    2023-12-12

最新评论