内插是在诸如放大、收缩、旋转和几何校正等任务中广泛应用的基本工具。
从根本上看,内插是用已知数据来估计未知位置的数值的处理。用一个简单的例子开始讨论该话题。假设一副图像大小为500X500的像素放大到1.5倍到750X750像素。一种简单的放大方法是创建一个假想的750X750网格,它与原始图像有相同的间隔,然后将其收缩,使它准确的与原图像匹配。显然,收缩 后的750X750网格的像素间隔要小于原始图像的像素间隔。为了对覆盖的每一个点赋以灰度值,在原始图像中寻找最接近的像素,并把该像素的灰度赋给750X750网格中的新像素。当完成对网格中覆盖的所有点的灰度赋值后,就把图像扩展到原来规定的大小,得到放大后的图像。
上述讨论的方法称为最邻近内插值,这种方法把原图像中最近邻的灰度值赋给了每个新位置。这种方法简单,但这种方法有产生不希望的认为缺陷的倾向,如某些直边缘的严重失真。由于这一原因,实际上该方法并不常用。更实用的方法是双线性内插,该方法中,用4个最近邻去估计给定位置的灰度,令(x,y)为想要赋以灰度值的位置的坐标,并令v(x,y)表示灰度值。对于双线性内插来说,赋值公式如下:
v(x,y)=ax+by+cxy+d
4个系数可由4个用(x,y)点最近邻点写出的未知方程确定。双线性插值给出了比最近邻内插好的多的结果,但随之而来的是计算量的增加。
复杂度较高的是双三次内插,它包括16个最近邻点。
其中16个系数可由16个用(x,y)点最近邻点写出的未知方程确定。通常双三次插值在保持细节方面比双线性内插相对要好。
双线性插值
假设源图像大小为mxn,目标图像为axb。那么两幅图像的边长比分别为:m/a和n/b。注意,通常这个比例不是整数,编程存储的时候要用浮点型。目标图像的第(i,j)个像素点(i行j列)可以通过边长比对应回源图像。其对应坐标为(i*m/a,j*n/b)。显然,这个对应坐标一般来说不是整数,而非整数的坐标是无法在图像这种离散数据上使用的。双线性插值通过寻找距离这个对应坐标最近的四个像素点,来计算该点的值(灰度值或者RGB值)。
若图像为灰度图像,那么(i,j)点的灰度值的数学计算模型是:
f(x,y)=b1+b2x+b3y+b4xy
其中b1,b2,b3,b4是相关的系数。关于其的计算过程如下如下:
如图,已知Q12,Q22,Q11,Q21,但是要插值的点为P点,这就要用双线性插值了,首先在x轴方向上,对R1和R2两个点进行插值,这个很简单,然后根据R1和R2对P点进行插值,这就是所谓的双线性插值。
双线性插值,又称为双线性内插。在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值。
假如我们想得到未知函数f 在点P=(x,y)的值,假设我们已知函数f在Q11=(x1,y1),Q12=(x1,y2),Q21=(x2,y1),Q22=(x2,y2),四个点的值。
首先在 x 方向进行线性插值,得到
然后在 y 方向进行线性插值,得到
这样就得到所要的结果f(x,y)
如果选择一个坐标系统使得 f的四个已知点坐标分别为 (0, 0)、(0, 1)、(1, 0) 和 (1, 1),那么插值公式就可以化简为:
这种插值方法的结果通常不是线性的,线性插值的结果与插值的顺序无关。首先进行 y 方向的插值,然后进行 x 方向的插值,所得到的结果是一样的。
按照网上一些博客上写的,源图像和目标图像的原点(0,0)均选择左上角,然后根据插值公式计算目标图像每点像素,假设你需要将一幅5x5的图像缩小成3x3,那么源图像和目标图像各个像素之间的对应关系如下:
只画了一行,用做示意,从图中可以很明显的看到,如果选择右上角为原点(0,0),那么最右边和最下边的像素实际上并没有参与计算,而且目标图像的每个像素点计算出的灰度值也相对于源图像偏左偏上。
那么,让坐标加1或者选择右下角为原点怎么样呢?很不幸,还是一样的效果,不过这次得到的图像将偏右偏下。
最好的方法就是,两个图像的几何中心重合,并且目标图像的每个像素之间都是等间隔的,并且都和两边有一定的边距。
如果你不懂我上面说的什么,没关系,只要在计算对应坐标的时候改为以下公式即可,
int x=(i+0.5)*m/a-0.5
int y=(j+0.5)*n/b-0.5
代替
int x=i*m/a
int y=j*n/b
利用上述公式,将得到正确的双线性插值结果。
原始图像
双线性插值的锯齿边
双三次插值无锯齿边
具体双三次插值不做详细分析。在MATLAB下运算,双三次插值的速度明显比双线性插值慢很多。
版权所有权归卿萃科技 杭州FPGA事业部,转载请注明出处
作者:杭州卿萃科技ALIFPGA
原文地址:杭州卿萃科技FPGA极客空间 微信公众号
扫描二维码关注杭州卿萃科技FPGA极客空间
图像中的插值