双线性插值法(bilinear interpolation)
前面讲解了最近邻插值法缩放图像以及不足之处,本篇介绍另外一种插值法,介绍双线性插值法之前先介绍线性插值。
1. 线性插值
线性插值是指插值函数为一次多项式的插值方式,其在插值节点上的插值误差为零。线性插值可以用来近似代替原函数,也可以用来计算得到查表过程中表中没有的数值。如图所示现在已知y=f(x)的两个点坐标分别是(x0,y0),(x1,y1),现在在区间(x0,x1)内给定任意x,如何求y,线性插值法采用图中红点的y值代替f(x)的y值。假设x处的直线上的红点坐标为(x,Y),那么Y约等于y。根据图可以得到公式:
用y0,y1表示得到
公式很好记,将分式看做权重系数。
2. 双线性插值法
双线性插值法也叫双线性内插,其核心思想是在两个方向分别进行一次线性插值。双线性插值作为数值分析中的一种插值算法,广泛应用在信号处理,数字图像和视频处理等方面。
如坐标图所示,用横纵坐标代表图像像素的位置,f(x,y)代表该像素点(x,y)的彩色值或灰度值。
将图像放大或缩小,目的像素dst对应的原像素src中的坐标转换公式如下,公式很好理解,可参考上一章最近邻插值法。
srcX=dstX*(srcWidth/dstWidth)
srcY=dstY*(srcHeight/dstHeight)
上式中,dstX与dstY为目标图像的某个像素的横纵坐标,dstWidth与dstHeight为目标图像的长与宽;srcWidth与srcHeight为原图像的宽度与高度。srcX,srcY为目标图像在该点(dstX,dstY)对应的原图像的坐标。
现在假设目标图像的像素点(x’,y’)映射到原图像中是(x,y),也就是图中的P点。设Q11 = (x1, y1)、Q12 = (x1, y2)、Q21 = (x2, y1) 、 Q22 = (x2, y2),图中Q11,Q12,Q21,Q22分别为距离P点的最近的四个点。分别在X方向进行两次插值,最后在y方向进行插值即可得到目标图像的像素值。公式如下:
先计算X方向(也可以先计算Y方向,再计算X方向)的线性插值:
再在y方向进行线性插值得到f(P):
经过公式的进一步化简可以得到:
由于是最近的点,所以Q的四个点的坐标之间相差1,故进一步化简为:
现假设x=i+u,y=j+v,i,j为整数,u,v为小数。得到下式:
下面为本人自己设计的例子与具体计算过程:
将图像放大两倍(对像素数扩大2倍),以?处的像素为例:
右边图中问号的坐标为(5,4),映射到原图像的像素点的坐标为
srcX=dstX*(srcWidth/dstWidth)=5*(4/8)=2.5
srcY=dstY*(srcHeight/dstHeight)=4*(4/8)=2
(srcX,srcY)=(2+0.5,2+0),u=0.5,v=0,映射的src坐标及对应的最近的四个Q点下如图所示。若x=i+u,y=j+v。则可以得到红色框的像素及其周围四个Q点(i,j)、(i+1,j)、(i,j+1)、(i+1,j+1),即可以得到?处的像素值。
每个像素点的RGB对应如下:
204,255,153 153,255,153 102,255,153 0,255,153
204,255,102 153,255,102 102,255,102 0,255,0
204,255,51 153,255,51 102,255,51 51,204,51
204,204,0 153,204,0 102,153,0 0,153,0
Q11(2,2),Q21(2,3),Q12(3,2),Q22(3,3),P(2.5,2)
采用双线性插值法得到红色框处的像素值:
R=0.5*102+0.5*51=51+25.5=76.5
G=0.5*255+0.5*204=127.5+102=229.5
B=0.5*51+0.5*51=25.5+25.5=51
由于颜色表示范围为0-255整数,R可以用127代替或128代替,B也是。所以问号处的颜色应该为:
然后以同样的方式计算得到所有的像素值,放大后的图像对比如下:
当出现i或j为边界坐标时,会出现(i+1,j)、(i,j+1)、(i+1,j+1)的点在实际的图中不存在,此时可以用(i,j)、(i-1,j)、(i,j-1)、(i-1,j-1)。如果srcX与srcY是整数,则其中一个点是(i,j),剩余的3个点其实无所谓,因为u,v为0。f(p)=f(i,j)
3. 代码实现
python实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | from matplotlib import pyplot as plt import numpy as np def bilinear_interpolation(srcimage_vector,dstwidthtimes ,dstheighttimes ): print ( "原始图像" ,srcimage_vector) srcHeight = srcimage_vector.shape[ 0 ] srcWidth = srcimage_vector.shape[ 1 ] print ( "srcHeight" ,srcHeight) print ( "srcWidth" ,srcWidth) dstWidth, dstHeight = int (dstwidthtimes * srcWidth), int (dstheighttimes * srcHeight) # 定义一个三维矩阵存储目标图像,每个像素由RGB三种颜色组成,shape接受一个元组,可以创建多维矩阵 dstVector = np.zeros(shape = (dstHeight, dstWidth, 3 ), dtype = int ) # 默认是float64 # 遍历目标图像的每一个像素 for dstY in range ( 0 ,dstHeight): for dstX in range ( 0 ,dstWidth): Q = [( 0 , 0 )] * 4 # Q11=Q12=Q21=Q22=0 Qdict = {} # 坐标换算 dstX_srcX = dstX * (srcWidth / dstWidth) # python中/表示除法,//表示整除 dstY_srcY = dstY * (srcHeight / dstHeight) u = round (dstX_srcX % 1 , 2 ) v = round (dstY_srcY % 1 , 2 ) if int (dstX_srcX) = = srcWidth - 1 : positionX = [ int (dstX_srcX) - 1 , int (dstX_srcX)] # 左右范围 else : positionX = [ int (dstX_srcX), int (dstX_srcX) + 1 ] #左右范围 if int (dstY_srcY) = = srcHeight - 1 : positionY = [ int (dstY_srcY) - 1 , int (dstY_srcY)] # 上下范围 else : positionY = [ int (dstY_srcY), int (dstY_srcY) + 1 ] #上下范围 k = 0 for m in range ( 0 , 2 ): # 得到Q的四个点坐标,分别是Q11,Q12,Q21,Q22 for n in range ( 0 , 2 ): Q[k] = (positionX[m], positionY[n]) Qdict[Q[k]] = srcimage_vector[positionY[n], positionX[m]] k = k + 1 # 通过四个点计算得到dst的像素值 dstVector[dstY][dstX] = Qdict[Q[ 0 ]] * ( 1 - u) * ( 1 - v) + Qdict[Q[ 1 ]] * ( 1 - u) * (v) + Qdict[Q[ 2 ]] * (u) * ( 1 - v) + Qdict[Q[ 3 ]] * (u) * (v) print (dstVector) ax = plt.gca() # 获取到当前坐标轴信息 ax.xaxis.set_ticks_position( 'top' ) # 将X坐标轴移到上面 plt.imshow(dstVector) # 显示数组 plt.show() plt.imsave( 'shaungxianxing.jpg' , dstVector.astype(np.uint8)) # matplotlib保存图像的时候,只接受浮点数或者unit8的整数类型 if __name__ = = "__main__" : # imagePath = r'songshu.jpg' imagePath = r 'cup.jpg' # imagePath = r'aoyunwuhuan.jpg' image_vector = plt.imread(imagePath) # dstwidth,dstheight用倍数表示,表示是src图像的多少倍 # dstwidth, dstheight=1.5,1.5 dstwidth, dstheight = 0.2 , 0.2 bilinear_interpolation(image_vector,dstwidth,dstheight) |
C++实现:后面补充。
4.效果
自己制作的奥运五环
原图双线性插值法放大2倍后的图像
邻近法放大2倍后的图像
网上找的松鼠:
原图
放大2倍后
缩小0.2倍后
手机拍的图
原图
缩小0.2倍
结论:通过图可以看出,双线性插值法,锯齿状比邻近法效果好多了,但是也会伴随着图片的变模糊。
5.存在问题及改进:
关于中心问题,后面补充
小结:由于采用线性权重计算新的像素值,所以双线性插值法与最近邻不同,会产生中间值,也就是会产生新的像素值。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)