欢迎访问个人网络日志🌹🌹知行空间🌹🌹
线性插值是指使用连接两个已知点的直线来确定同在这个直线上的未知点值的方法。
图片来自于线性插值
如上图,已知坐标 ( x 0 , y 0 ) , ( x 1 , y 1 ) (x_0, y_0),(x_1,y_1) (x0,y0),(x1,y1),要求区间 [ x 0 , x 1 ] [x_0, x_1] [x0,x1]中间一个x位置在直线上的值,使用线性插值的方法如下,两点式直线方程可写为:
x − x 0 x 1 − x 0 = y − y 0 y 1 − y 0 \frac{x-x_0}{x_1-x_0}=\frac{y-y_0}{y_1-y_0} x1−x0x−x0=y1−y0y−y0
记方程左右的等值为
α
\alpha
α,则可得
α
=
x
−
x
0
x
1
−
x
0
\alpha=\frac{x-x_0}{x_1-x_0}
α=x1−x0x−x0,
y
=
(
1
−
α
)
y
0
+
α
y
1
y=(1-\alpha)y_0+\alpha y_1
y=(1−α)y0+αy1
上式可用来计算 y y y。实际上当 x ∉ [ x 0 , x 1 ] x\notin[x_0,x_1] x∈/[x0,x1]且 α ∉ [ 0 , 1 ] \alpha\notin[0,1] α∈/[0,1]时,上式仍然可以使用,这种情况下,这种方法叫作线性外插。
知道线性插值后,双线性插值,又称双线性内插,就是在两条线上分别进行一次线性插值,等到两个中间点,再对中间点进行一次线性插值得到的,如下图:
图片来自双线性插值
现在函数值是和 ( x , y ) (x,y) (x,y)相关的二维函数, z = f ( x , y ) z=f(x, y) z=f(x,y), 可将上图当成是沿z轴方向的俯视图, Q 11 , Q 12 , Q 21 , Q 22 Q_{11}, Q_{12}, Q_{21}, Q_{22} Q11,Q12,Q21,Q22是已知的四个点,双线性插值所做的事情即根据这四个点求中间点 P P P的值,上图中
f
(
Q
11
)
=
f
(
x
1
,
y
1
)
f
(
Q
12
)
=
f
(
x
1
,
y
2
)
f
(
Q
21
)
=
f
(
x
2
,
y
1
)
f
(
Q
22
)
=
f
(
x
2
,
y
2
)
求P需先求中间点 R 1 , R 2 R_1,R_2 R1,R2, R 1 R_1 R1可根据 Q 11 , Q 12 Q_{11},Q_{12} Q11,Q12用线性插值公式来求, R 2 R_2 R2可根据 Q 21 , Q 22 Q_{21},Q_{22} Q21,Q22用线性插值公式来求。
f
(
R
1
)
=
x
2
−
x
x
2
−
x
1
f
(
Q
11
)
+
x
−
x
1
x
2
−
x
1
f
(
Q
21
)
f
(
R
2
)
=
x
2
−
x
x
2
−
x
1
f
(
Q
12
)
+
x
−
x
1
x
2
−
x
1
f
(
Q
22
)
得到 R 1 , R 2 R_1,R_2 R1,R2后,对这两点再应用线性插值即可求 P P P,
f ( P ) = y 2 − y y 2 − y 1 f ( R 1 ) + y − y 1 y 2 − y 1 f ( R 2 ) f(P) = \frac{y_2-y}{y_2-y_1}f(R_1) + \frac{y-y_1}{y_2-y_1}f(R_2) f(P)=y2−y1y2−yf(R1)+y2−y1y−y1f(R2)
已知 ( 2 , 2 ) , ( 2 , 3 ) , ( 3 , 2 ) , ( 3 , 3 ) (2,2),(2,3),(3,2),(3,3) (2,2),(2,3),(3,2),(3,3)四个像素点的值分别为 20 , 15 , 30 , 40 20,15,30,40 20,15,30,40,用双线性插值求其中间点 P ( 2.6 , 2.4 ) P(2.6,2.4) P(2.6,2.4)的像素值的过程如下,
图片来自双线性插值
f
(
R
1
)
=
0.4
×
20
+
0.6
×
30
=
26
f
(
R
2
)
=
0.4
×
15
+
0.6
×
40
=
30
f
(
P
)
=
0.6
×
26
+
0.4
×
30
=
27.6
≈
28
OpneCV Resize方法做比较使用OpenCV的resize方法,插值方法选择双线性插值。将3x3的图像使用双线性插值resize成2x2。
使用OpenCV计算的结果为:
img = np.array([[30, 20, 10],
[10, 40, 60],
[20, 30, 40]], dtype=np.uint8)
img = cv2.resize(img, (2,2), cv2.INTER_LINEAR)
print(img)
# [[25 23]
# [21 42]]
手动计算双线性插值过程,需先将resize后大小为2x2的destination图像对应的点再还原到source源图像上去,然后才能在原图像上应用双线性插值,这里将目标图像点映射到源图像上的坐标计算公式为:
X
=
(
d
s
t
X
+
0.5
)
×
s
r
c
W
i
d
t
h
d
s
t
W
i
d
t
h
−
0.5
Y
=
(
d
s
t
Y
+
0.5
)
×
s
r
c
H
e
i
g
h
t
d
s
t
H
e
i
g
h
t
−
0.5
这个公式可以写成:
s
r
c
X
+
0.5
d
s
t
X
+
0.5
=
s
r
c
W
i
d
t
h
d
s
t
W
i
d
t
h
\frac{srcX + 0.5}{dstX + 0.5} = \frac{srcWidth}{dstWidth}
dstX+0.5srcX+0.5=dstWidthsrcWidth
可理解成将resize后每个像素点中心和原图上对应点开始一半像素的位置对齐。
计算过程为:
图片来自双线性插值
可见与OpenCV resize函数使用INTER_LINEAR方法时的结果相同。
上述原图坐标和resize后图像坐标的映射方式等同于TORCH.NN.FUNCTIONAL.INTERPOLATE函数align_corners=False时的场景,
import torch
import torch.nn.functional as F
t = torch.tensor(img, dtype=torch.float).reshape(1,1,3,3)
it0 = F.interpolate(t, size=2, mode = 'bilinear')
print(it0)
# tensor([[[[25.0000, 23.1250],
# [21.2500, 41.8750]]]])
it0 = F.interpolate(t, size=2, mode = 'bilinear', align_corners=True)
print(it0)
# tensor([[[[30., 10.],
# [20., 40.]]]])
关于align_corners参数的介绍可参考(三)TORCH.NN.FUNCTIONAL.INTERPOLATE使用说明。
关于双线性插值,可以将上述公式 f ( P ) f(P) f(P)展开成 f ( Q i j ) f(Q_{ij}) f(Qij)的加权和,其物理含义可借助下图表示:
欢迎访问个人网络日志🌹🌹知行空间🌹🌹
- 1.https://blog.csdn.net/qq_37541097/article/details/112564822?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164784799816780255299039%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=164784799816780255299039&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~rank_v31_ecpm-1-112564822.nonecase&utm_term=%E5%8F%8C%E7%BA%BF%E6%80%A7&spm=1018.2226.3001.4450#t4
- 2.https://zhuanlan.zhihu.com/p/161540817