原理
何为线性插值?
插值就是在两个数之间插入一个数,线性插值原理图如下
在位置 x 进行线性插值,插入的值为f(x)
各种插值法
插值法的第一步都是相同的,计算目标图(dstImage)的坐标点对应原图(srcImage)中哪个坐标点来填充,计算公式为:
srcX = dstX * (srcWidth / dstWidth) srcY = dstY * (srcHeight / dstHeight)
(dstX,dstY)表示目标图像的某个坐标点,(srcX,srcY)表示与之对应的原图像的坐标点。srcWidth/dstWidth 和 srcHeight/dstHeight 分别表示宽和高的放缩比。
那么问题来了,通过这个公式算出来的 srcX, scrY 有可能是小数,但是原图像坐标点是不存在小数的,都是整数,得想办法把它转换成整数才行。
不同插值法的区别就体现在 srcX, scrY 是小数时,怎么将其变成整数去取原图像中的像素值。
- 最近邻插值(Nearest-neighborInterpolation):看名字就很直白,四舍五入选取最接近的整数。这样的做法会导致像素变化不连续,在目标图像中产生锯齿边缘。计算速度最快,但是效果最差。
- 双线性插值(Bilinear Interpolation):双线性就是利用与坐标轴平行的两条直线去把小数坐标分解到相邻的四个整数坐标点。权重与距离成反比。效果略逊于双三次插值,速度比双三次插值快,属于一种平衡美,在很多框架中属于默认算法。
- 双三次插值(Bicubic Interpolation):与双线性插值类似,只不过用了相邻的16个点。但是需要注意的是,前面两种方法能保证两个方向的坐标权重和为1,但是双三次插值不能保证这点,所以可能出现像素值越界的情况,需要截断。效果最好,但是计算代价过大。
借用下图从视觉上来理解双线性插值,黑点上的双线期插值是附近四个点的加权和,权值是四个点对应的颜色矩形在总面积中的占比。比如左上角黄点 ( x 1 , y 2 ),对应的是右下较大的黄色矩阵面积。
Python实现
from PIL import Image import matplotlib.pyplot as plt import numpy as np import math def BiLinear_interpolation(img,dstH,dstW): scrH,scrW,_ = img.shape img = np.pad(img,((0,1),(0,1),(0,0)),'constant') retimg = np.zeros((dstH,dstW,3),dtype=np.uint8) for i in range(dstH): for j in range(dstW): scrx = (i+1)*(scrH/dstH)-1 scry = (j+1)*(scrW/dstW)-1 x=math.floor(scrx) y=math.floor(scry) u=scrx-x v=scry-y retimg[i,j]=(1-u)*(1-v)*img[x,y] + u*(1-v)*img[x+1,y] + (1-u)*v*img[x,y+1] + u*v*img[x+1,y+1] return retimg im_path='wave.jpg' image=np.array(Image.open(im_path)) image2=BiLinear_interpolation(image, image.shape[0]*2, image.shape[1]*2) image2=Image.fromarray(image2.astype('uint8')).convert('RGB') image2.save('out.jpg')