. e+ ^$ } K9 @ K+ u( I1 F6 V5 A( o0 f5 z4 f' n
3.代码实现 " d, v; J/ ]* ]6 B) x! i( C1 uimport torch 7 ^0 a' k* t7 i" oimport torch.nn as nn2 H/ L' w n& O; D: |0 p
from torchvision import transforms& m( \5 F* {( S. X6 r
. c/ N! Q4 }, `# o3 N, }
]8 j( x! Q, ]
img=torch.randint(10,size=(1,4,4),dtype=torch.float32) ' i; O5 x; V3 Q0 k4 ~( H% s0 }print(img)) c5 A( y: g! B- `5 s) R
print('---'*5)! e3 a" L/ H1 @; O
bilinear_interpolation=transforms.Resize(size=(8,8), $ n9 d! Z& x% m' P& P3 u! Z interpolation=transforms.InterpolationMode.BILINEAR) : X) ^- X( d( E$ ?resize_img=bilinear_interpolation(img)+ R& z4 B8 U/ J2 P2 a4 `, _7 A/ i" |* N, e
print(resize_img) 2 W _+ F7 m; f$ M; `( R1 8 ~4 ~" f. a3 M1 d) B2' A' F/ j$ L+ t
38 t# y5 w) i' ?+ ?+ V! F% \* [
4: W b" I: b% Y- F- w6 o
5 # [5 B. P7 Y0 @, F, u5 ~, d61 f6 x' {5 z+ A4 z1 H! b
7; [; f5 E0 Q3 A
81 F5 R# G/ u9 S. Y; n
9 + S6 Z/ t. _" j- L, v10 0 P0 h( a7 [5 c0 s& I( Y11! q0 i- o( E+ C8 \
12 E8 ~4 `0 u) g. q8 d- j
三、双三次插值(Bicubic Interpolation)% }7 T- ^2 ?. W
1.相关介绍, V5 N+ G; g1 l
双三次插值又称为双立方插值,可比双线性插值方法产生边缘更平滑的插值结果,可产生效果更好、更精确的插值结果,但是速度较慢。6 W$ @1 ^9 k0 y3 Q2 N2 v- E' u
插值过程中,图中点(x,y)=(i+u,j+v)的值通过矩形网格中该点邻近的16个点加权平均得到,相对该点而言16个点的坐标依次为{(i-1,j-1),(i-1,j),(i-1,j+1),(i-1,j+2),…,(i,j),…,(i+2,j-1),(i+2,j),(i+2,j+1),(i+2,j+2)},此时需要分别沿着X、Y方向使用一个多项式插值三次函数计算对应结果。 4 V9 r+ y! t3 a+ L k; ]7 E# z插值公式为:$ p7 Y5 c$ a% N# ]6 {# n$ E" H2 J
( N; m. U) ~% y& [我们使用aij表示每个邻近点,fij表示原图中点aij的像素值,wi、wj分别表示该点在对应方向的权重。比如,a00表示矩形网格中左上角的第一个点,以此类推,我们第一步工作就是通过Bicubic函数计算所有的权重,然后进行所需的插值计算。 # N$ R7 a1 h! W构造的Bicubic函数如下:9 m" |2 }6 K. }* a. V: I+ X
- p' k) b, _% f6 f1 h3 i7 T) U
其中a=-0.5时,函数形状如下:, C* B7 y. z! h* ]1 E9 K! E* g
7 i1 s2 Q" @* p. X* ^基本知识已经了解了,接下来我们看看插值过程的具体步骤怎么实现,分别使用Dst、Src表示目标图像和原图,需要知道Dst中的点A(dst_x,dst_y)像素值应为多少,A(dst_x,dst_y)对应原图中的点为P(src_x,src_y)=P(x,y): T! W- P8 g9 o/ d- ~% n , h3 V* X# @8 M G J" U6 e! J! n1 i1)使用文章开头的公式,通过dst_x,dst_y计算出src_x,src_y,此时一般src_x,src_y是小数,可记为src_x=i+u,src_y=j+v,以(i,j)及周围的16个邻近点构成矩形网格;# y4 @/ a( `( R- Y, R7 F
2)因为Bicubic函数是一维函数,所以我们需要分别沿着X、Y方向计算每个点对应的权重,每个点权重记为wij(w_x,w_y),计算过程为:1 G8 R4 S: {7 d% ?& x* @7 v
" g7 {' O9 r5 Y6 H; u* n7 P4 ~
明确该点X、Y方向与P点之间的距离lij(l_x,l_y),如a00(i-1,j-1)与P(i+u,j+v)之间距离为l00(i+u-i+1,j+v-j+1)=l00(u+1,v+1),a33(i+2,j+2)与P(i+u,j+v)之间距离为l33(i+2-i-u,j+2-j-v)=l33(2-u,2-v); $ D* U& o W. P- A所以每个邻近点对应的权重为w(w_x,w_y)=w(W(l_x),W(l_y)),此处W指Bicubic函数; 7 n. k" O- ^4 `: }1 E7 F9 P3)得到每个点对应的权重后,通过插值公式即可得到插值结果B(dst_x,dst_y);$ X5 b; p& k( k1 Y
. h$ P+ D, O' h$ m
很容易计算从a00到a33共16个点到P点的距离l(l_x,l_y)为: " H7 F# V: X/ w5 z* O$ [0 ?9 q& ?# K3 Z- Q( X0 t. A& Z$ E
比如a00与P之间的距离为:l00(l_0,l_0)=l00(u+1,v+1),a33与P之间的距离为:l33(l_3,l_3)=l33(2-u,2-v),到这里大家应该理解双三次插值的过程了吧!8 g/ Z K6 L( M% c% e0 ]
-------------------------------------------------------------------------------------------------------------------------- , O+ a9 F$ c) f& E2 v其实在插值计算时还可以使用矩阵表示,如下:0 _$ F( x/ d4 ~7 ?
6 }; P" k# [ k# }+ z; x" X U5 m/ V- Z 4 L3 ~# _( O5 R! l* O ^6 x其中f(i+u,j+v)即为要计算的值,而A、C分别表示权重也就是第一种方式中的w_x,w_y,B为原图中16个邻近点构成的矩阵,计算权重的函数使用S(x)去近似。 # O* ?; S6 t" ~4 \: c7 V& d/ F 5 l$ Q" R2 W# k9 C- O2.举个例子 ( I& S- h2 k, O3 J" Q' W输入为Src:5×5,输出为Dst:10×10,我们去求Dst中点(5,5)的值:( Q/ v1 n4 [% T3 m
" v8 ]* d9 O* I" B( i' w/ g
我手动实现上述矩阵运算方式的计算过程(计算结果总是和Pytorch内置函数计算出的结果存在一定偏差,我也是很纳闷):2 `; s. K* {/ v7 ^! t
; N: M* K& ?; u, i* {* t
import numpy as np / W2 ~1 I6 C. A4 b3 Nimport math9 s+ a) U) h( f