线性插值从字面上的意思理解就是,采用线性关系计算新插入的值的大小。更直观的,给定一个一元一次函数 f ( x ) f(x) f(x)以及两个已知的点 f ( x 1 ) , f ( x 2 ) f(x_1),f(x_2) f(x1),f(x2),计算未知点 f ( x ) f(x) f(x)
使用斜率的关系
f ( x 2 ) − f ( x 1 ) x 2 − x 1 = f ( x ) − f ( x 1 ) x − x 1 f ( x ) = ( x 2 − x ) x 2 − x 1 f ( x 1 ) + ( x − x 1 ) x 2 − x 1 f ( x 2 ) \frac{f(x_2)-f(x_1)}{x_2-x_1}=\frac{f(x)-f(x_1)}{x-x_1} \\ f(x)=\frac{(x_2-x)}{x_2-x_1}f(x_1)+\frac{(x-x_1)}{x_2-x_1}f(x_2) x2−x1f(x2)−f(x1)=x−x1f(x)−f(x1)f(x)=x2−x1(x2−x)f(x1)+x2−x1(x−x1)f(x2)
双线性插值也就是在线性插值的基础上进行了两个方向的计算:
1.通过 Q 00 和 Q 01 Q00和Q01 Q00和Q01线性插值计算出 R 0 R0 R0;
2.通过 Q 10 和 Q 11 Q10和Q11 Q10和Q11线性插值计算出 R 1 R1 R1;
3.通过 R 0 和 R 1 R0和R1 R0和R1线性插值计算出 P P P;
整理后可得
f ( R 0 ) = ( f ( Q 01 ) − f ( Q 00 ) ) ( w − w 0 ) w 1 − w 0 + f ( Q 00 ) f ( R 1 ) = ( f ( Q 11 ) − f ( Q 10 ) ) ( w − w 0 ) w 1 − w 0 + f ( Q 10 ) f ( P ) = ( f ( R 1 ) − f ( R 0 ) ) ( h − h 0 ) h 1 − h 0 + f ( R 0 ) f(R0)=\frac{(f(Q01)-f(Q00))(w-w0)}{w1-w0}+f(Q00) \\ f(R1)=\frac{(f(Q11)-f(Q10))(w-w0)}{w1-w0}+f(Q10) \\ f(P)=\frac{(f(R1)-f(R0))(h-h0)}{h1-h0}+f(R0) f(R0)=w1−w0(f(Q01)−f(Q00))(w−w0)+f(Q00)f(R1)=w1−w0(f(Q11)−f(Q10))(w−w0)+f(Q10)f(P)=h1−h0(f(R1)−f(R0))(h−h0)+f(R0)
最终
f ( P ) = ( h − h 1 ) ( w − w 1 ) ( h 1 − h 0 ) ( w 1 − w 0 ) f ( Q 00 ) + ( h 1 − h ) ( w − w 0 ) ( h 1 − h 0 ) ( w 1 − w 0 ) f ( Q 01 ) + ( h − h 0 ) ( w 1 − w ) ( h 1 − h 0 ) ( w 1 − w 0 ) f ( Q 10 ) + ( h − h 0 ) ( w − w 0 ) ( h 1 − h 0 ) ( w 1 − w 0 ) f ( Q 11 ) f(P)=\frac{(h-h1)(w-w1)}{(h1-h0)(w1-w0)}f(Q00)+\frac{(h1-h)(w-w0)}{(h1-h0)(w1-w0)}f(Q01)\\ +\frac{(h-h0)(w1-w)}{(h1-h0)(w1-w0)}f(Q10)+\frac{(h-h0)(w-w0)}{(h1-h0)(w1-w0)}f(Q11) f(P)=(h1−h0)(w1−w0)(h−h1)(w−w1)f(Q00)+(h1−h0)(w1−w0)(h1−h)(w−w0)f(Q01)+(h1−h0)(w1−w0)(h−h0)(w1−w)f(Q10)+(h1−h0)(w1−w0)(h−h0)(w−w0)f(Q11)
细心观察可以发现四个系数之和为1。
要解决图像中的双线性插值的问题,只需要取距离 P P P点最近的四个点就可以直接带入公式求解,有了计算公式,现在只需要搞定 ( h , w ) (h,w) (h,w)从何而来?
直接除以倍数
既然线性插值一般都是要把图像放大,最简单的做法就是把放大后的图像的坐标点除以放大倍数。但是这样会导致几个问题:
解决方案:
使用numpy的linspace可以均匀的将放大后的坐标值映射到原始坐标范围。
import numpy as np
import imageio
import matplotlib.pyplot as plt
def bilinear_interpolation(image,rate=1.1):
h,w,c = img.shape
# 计算放大后的尺寸
new_h = int(h*rate)
new_w = int(w*rate)
# 将放大后的坐标映射到原始坐标范围
h_s = np.linspace(0,h-1,new_h-1)
w_s = np.linspace(0,w-1,new_w-1)
# 创建一个空白的放大后尺寸的图像
new_img = np.zeros([new_h,new_w,c],dtype=np.uint8)
# 逐像素的进行计算
for i in range(new_h-2):
for j in range(new_w-2):
for k in range(c):
# 左上角坐标
h0,w0 = int(h_s[i]),int(w_s[j])
# 获得四个点的像素值
q_00 = img[h0][w0][k]
q_01 = img[h0][w0+1][k]
q_10 = img[h0][w0][k]
q_11 = img[h0+1][w0+1][k]
# 使用公式计算映射点像素值
new_img[i][j][k] = (h_s[i]-h0-1) * (w_s[j]-w0-1) * q_00 \
+ (h0+1-h_s[i]) * (w_s[j]-w0) * q_01 \
+ (h_s[i]-h0) * (w0+1-w_s[j]) * q_10 \
+ (h_s[i]-h0) * (w_s[j]-w0) * q_11
return new_img
img = plt.imread('0.jpg')
dst = bilinear_interpolation(img,1.5)
imageio.imwrite('4.jpg',dst)