什么是双线性插值?进来看看呗!(附code实现)
Date: 2020/02/15
Author: CW
前言:
在上一篇文(关于转置卷积的这些点,你get到了没?)中整理了转置卷积(Transposed Convolution)相关知识点,与之对应,在传统上采样方法中,最常亮相的当属双线性插值(Bilinear Interpolation)了。因此,CW决定梳理下这方面的知识,记录到本文中,方便日后快速回顾,并且落实到代码层面,用2种方式实现双线性插值,供大家参考学习。
Outline
i). 概念 —— 双线性插值?什么东东?
ii). 计算 —— 数学公式来一波!
iii). 代码 —— talk is cheap, show me the code!
概念 —— 双线性插值?什么东东?
双线性插值?能吃吗(⊙o⊙)…
好好学习,别光想着吃...
好了,认真起来,在CV领域,通常需要改变原图尺寸(缩放)以方便进行一些后处理,那么缩放后目标图像的每个像素点就需要计算出对应的像素值,双线性插值就是干这个的(缩小和放大都适用)。
计算 —— 数学公式来一波!
那么,具体如何计算呢?如同我们人类一般,血缘关系决定了我们的近亲关系,双线性插值也是利用类似的思想,对于目标图像的每个像素点,找到它在原图上最近的周围四个点,通过一定的计算方式得到对应的像素值。
在具体解释双线性插值的计算方法前,先来了解下线性插值。
所谓线性插值,就是利用线性(函数)性质进行插值计算,那么你可能会好奇,既然有“双”线性插值,那是不是应该有“单”线性插值?嗯,还真是这样,单线性插值是在一个方向上计算插值,而双线性插值是在两个方向分别进行插值计算。
单线性插值如上图,已知(x0, y0)和(x1, y1),需要对(x0, x1)区间内的某点x对应的y值进行插值计算,利用线性性质,不难得出以下解:
单线性插值计算有初中(还是小学?)数学基础的朋友,应该都很好理解吧,设一条直线经过(x0, y0)和(x1, y1),计算x在这条直线上对应的y值,实质上是用x与x0、x1的距离作为权重分别用于y0和y1的加权。
好了,现在该双线性插值出场了,与以上类似,本质上就是在两个方向上分别做以上的线性插值。
双线性插值如上图,已知函数 f (在图像处理中,f代表像素值)在 Q11 (x1, y1)、Q12 (x1, y2)、Q21 (x2, y1) 以及 Q22 (x2, y2) 这4个点的值,要计算函数 f 在点 P (x, y) 的值。
首先,在x方向进行插值计算,得到函数 f 在R1 (x, y1) 和R2 (x, y2) 两点的值:
双线性插值(x方向)接着在y方向进行插值计算:
双线性插值(y方向)最后,综合x、y方向上插值计算的结果,得到:
双线性插值(x+y方向)在图像处理中,通常选择P点周围相邻的4个点进行插值计算,即这4个点在x或y方向上坐标值相差1,那么上式分母便化为1:
哎呀!写了那么多,有个重要点居然忘了!我们已经知道上图的P点是目标图像的某像素点(记为P')映射到原图像的点,那么对于P' (,),还没说P点坐标(x, y)是怎么得到的呢...
我们想得简单点,直接利用缩放比例计算得到。假设原图的高和宽分别为和,目标图的高和宽分别为和,那么点P的坐标(x, y)由以下计算得到:
x = , y = (宽对应横坐标,高对应纵坐标)
看似简洁了事,完美无缺,但是通常想得太简单都会导致一些问题,这里恰恰就有问题——可能导致目标图像中心跟原图中心不对齐。
为啥中心点会不对齐呢,原因是我们虽然称它为像素“点”,但其实人家是一个边长为1的正方形。因此,对于坐标为(h, w)的像素点,它的中心(代表该值的位置)实际上是(h+0.5, w+0.5),这样,P点(x, y)的计算公式转化为:
x = , y =
代码 —— talk is cheap, show me the code!
直男不多说,必须撸起代码,以下是使用numpy(np)实现的案例,先来个最直接的写法:
双线性插值常规实现方式 双线性插值函数调用以上是按照我们上一节所讲的直观实现方式,可读性好,易理解,也没毛病。
但是可以看到,我们是一个个点来计算像素值的,在调用方法的时候,有3个for循环!看起来难免不太优雅,而且遇到大分辨率图像时,耗时也不短,那么怎样把以上变成优雅的白富美呢?
认真想想,图像本质是矩阵,涉及矩阵的数学计算当然是用矩阵运算来得合适,一起来看看:
双线性插值矩阵实现方式(i)注意以上 hp_src 和 wp_src 最终变为 shape 是 (h_dst, w_dst) 的2维矩阵,分别代表目标图像每点对应到原图的纵、横坐标。
双线性插值矩阵实现方式(ii)上图 f_xx 代表周围相邻4点的像素值矩阵(3维),原先它们的 shape为(h_dst, w_dst, channel),而后变为 (channel, h_dst, w_dst), 或许你会疑惑为啥要对它们的维度重排列成这样,不急,看完下图你应该就知道了。
双线性插值矩阵实现方式(iii)看到没有,f_xx最终要和相应的权重wt_xx相乘,而wt_xx是通过hx_src和wx_src计算出来的权重矩阵,是2维矩阵,因此需要将f_xx的维度进行重排,将通道数放在前面,每个通道都是一个2维矩阵,才能和wt_xx权重矩阵有效相乘。当然,加权求和计算完毕后,别忘了重新排列维度,转换回来,让通道数放在最后面。
说了那么多,到底work不work呢?哈哈哈,当然不会忽悠你,来看看效果:
原图分辨率300x300 放大为分辨率500x500的目标图#最后
当前疫情严重,大家还是尽量少出门,待在家里好好学习,对自己对他人都好,大家要团结起来,按国家政府指示做好本分,共同抗击疫情,早日结束这场斗争。
这次的疫情,使我的心更加静了一些,宅家不出门的这段时间,我每天都会对所做之事和所学之识进行思考、记录、总结和复盘,以往的我过于浮躁,没有沉下心来好好回顾自己,希望新的一年里自己能更多地成长,愿大家也一样。
参考: