- m6 Y9 G& `4 N1 H8 o& `" L5 Y明确该点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);1 j0 B7 f: V" j
所以每个邻近点对应的权重为w(w_x,w_y)=w(W(l_x),W(l_y)),此处W指Bicubic函数;% b3 {2 H& f( e4 n3 u( m
3)得到每个点对应的权重后,通过插值公式即可得到插值结果B(dst_x,dst_y);# V6 n/ @* p' h5 m8 J# ?1 d l
1 h% y# u/ i5 H7 V. W
很容易计算从a00到a33共16个点到P点的距离l(l_x,l_y)为: 3 c0 R: }, P2 g& S. L9 m4 N Q6 P. d9 ]: o* R
比如a00与P之间的距离为:l00(l_0,l_0)=l00(u+1,v+1),a33与P之间的距离为:l33(l_3,l_3)=l33(2-u,2-v),到这里大家应该理解双三次插值的过程了吧! + u7 \8 T. A7 M--------------------------------------------------------------------------------------------------------------------------) a! t d' {& K3 n1 k! k: j8 P' M1 @
其实在插值计算时还可以使用矩阵表示,如下:6 M% ~5 Q3 R$ }% ^1 n$ n5 S q( [ q
/ q) v4 y$ h$ V! k) f' d
5 r Z }7 B& F7 V. Q其中f(i+u,j+v)即为要计算的值,而A、C分别表示权重也就是第一种方式中的w_x,w_y,B为原图中16个邻近点构成的矩阵,计算权重的函数使用S(x)去近似。 3 a, j$ l M( S i+ Y' @0 Z$ `2 \% F1 i2 M t/ i' E; ^( Y
2.举个例子- R# n. n/ T: [& I, \4 w
输入为Src:5×5,输出为Dst:10×10,我们去求Dst中点(5,5)的值: : r" ?. g. o3 u6 |4 O6 E( e w; F4 }# t& h我手动实现上述矩阵运算方式的计算过程(计算结果总是和Pytorch内置函数计算出的结果存在一定偏差,我也是很纳闷): . @$ B* q* i! Z: Q2 x& U& P& m, I. G& _( d
import numpy as np ) K3 z P* z1 U! K! ]8 u; |; Vimport math& u; W5 _$ A- D5 W) L
9 x- c' Y5 {3 H! ?
src_w=src_h=56 z. L+ K1 H; X
dst_w=dst_h=10( P. j$ [# Y! h4 J9 D, V; ]. g
, [0 e& u% f w7 R! ^5 {& ]dst_x=dst_y=56 ^8 x6 N5 r% F$ a* n
src_x=dst_x*(src_h/dst_h)1 W4 t$ N: E0 G! V( {5 F
src_y=dst_y*(src_w/dst_w)0 J2 x' T$ V. z
* J5 P8 I! z9 d1 ]0 u% G4 {( W. l- Ii=math.floor(src_x)7 o3 x7 X" }$ M) t
j=math.floor(src_y)( \. l1 ?" c) G$ Q9 T
7 ?; {! |' C, f* o8 ?0 w: G" Q5 C8 Y
u=src_x-i , d; Q3 c! G# k' }2 cv=src_y-j. X# x% y, ^; K' A& y% Z1 F
# print(i,j,u,v)- c6 j' U/ q* q0 H$ K! J: v: v
# l_x=np.array([[1.5,0.5,0.5,1.5]]) " g7 ]+ S8 |1 c/ A% f' N. b# l_y=np.array([[1.5,0.5,0.5,1.5]]) & R. j2 e5 c8 ?: x) {/ Ybase=[1,0,-1,-2] $ `/ P% F7 o2 ~: o3 ?* s: X% Z4 ^& o! Z( R% K* y
9 C. H- U, q; G8 B* z& l" @, Z' E
def l_(r): 4 R0 F s4 P/ d a=np.zeros((1,4)) 5 E3 z- t6 s5 ^! e" \) \ for j in range(4):; E0 I X8 P9 \8 A: n' I
a[0,j]=r+base[j]$ w4 Y: g+ i9 y: O l4 ~& L( j
return a ! i' H( U# U' G2 E7 f! j$ |/ { " y p2 P: m/ }/ M0 m / s! }, O+ g+ ol_x,l_y=l_(u),l_(v)8 z8 _ c/ I7 t, {; z! V S+ b
# print(l_x)" C# q2 a# h+ G e7 L! v
# print(l_y) $ T2 Y) d' w( l2 C" z: V) T9 q B0 @. T& a
# # print(l_x.shape) $ g" W" o9 r& C8 ~8 o# / s$ w1 _; C+ ]8 d; l1 x2 b#8 Y% P( B, o2 y" a0 i! v0 ]! j
def S_x(l_): 3 a$ y* }3 H* i7 } s=np.zeros(shape=(1,4))% D6 O0 t- J4 r" X
for j in range(4): ' ^/ E9 F3 s5 K8 I1 g$ O' ? x_abs=math.fabs(l_[0,j]) E5 H8 h. \1 y if x_abs <= 1:0 n+ Y/ \5 \% [
s[0,j] = 1-2* math.pow(x_abs, 2)+math.pow(x_abs, 3) - U' Z* K, `. w elif x_abs < 2 and x_abs > 1:' v' r8 y9 O% K& R# t8 x: [4 @, G
s[0,j] = 4-8*x_abs+5*math.pow(x_abs, 2) - math.pow(x_abs, 3) # x* ?" E0 Q2 v/ U# M return s8 G: n' ?1 P# a6 Y+ K2 E* t
0 b+ u+ F9 n2 W+ V( t7 t
7 r. i) u( s( A6 |. ?2 V: R/ |
A,C=S_x(l_x),S_x(l_y) 6 e& Q) z, `% n4 `- l |+ N" o7 `2 o( _
B=np.array([2 G2 \/ w9 L/ Z3 p' Y& z9 {( Z; Y
[9., 0., 7., 3.],4 x6 Q) c: U: z# `, I) @
[7., 0., 1., 8.],4 {2 o: z5 A7 d8 r5 y% r5 W9 p; r8 |
[1., 8., 1., 3.], 2 f: q4 g. O# e/ e% k/ r. Z) Y5 N [5., 5., 1., 1.]])% p' f2 _8 T0 j Q- G! d
b=np.matmul(np.matmul(A,B),np.transpose(C))( \2 s! p' D! l7 m3 z
print(b) 1 |+ \" I0 [) E) ~8 m. \% ]! Q1 |! a* B" x& y& {
2 , c# X6 b1 x8 a5 R8 D/ t3" X0 h; q7 @7 Q9 N; G/ @
45 N0 _# y. ]: C) s
5 6 @) y; \! e0 q% Z/ {& t6 ! V6 i4 g( s# b76 _' l- _' K1 _9 y$ P, W# {
8% h1 U$ Q) h' j& P9 X0 w' M
9$ o, ~" w( Q2 d6 I
10 ' x2 _6 _" v$ ?6 d$ B# B11 + s$ y0 }0 O3 _1 s3 m12 ' Y# L8 v. V8 }3 y# z* @/ p13 ( n4 G; Y, v# L+ s9 N1 e14 ! ]; M J5 W! R g5 e- o; i15 ( b7 i" G: D3 P' A! x168 N! P6 r6 P" V: ?
17 9 \% N. o" `# v0 d18 & W% `& G; [4 r( V7 }6 h1 P19 @1 i! F7 z/ \# o7 h208 X& G& ^ r' O/ M
21 B" F) U9 y) ?3 U" C: \22 - r# \; U3 S% F0 e" M23 2 @/ |8 w* N+ X2 f' v24 1 L* p, q* D- ]' G) F25 1 Y- `/ F1 X) e& m26 6 _0 f2 T9 M3 p" ~) k% q27 4 ?8 `- H" h. F5 E28 ( w2 ^7 T! ?8 s0 Q5 Q/ D: Y7 r29 7 |- ^7 V: S9 U" A8 G0 t$ u300 [) x' y/ y* c% i
318 R/ N' J f C1 a
320 s3 H) u* F7 g' v. |# L. @. O
334 t/ t2 F$ L, w8 M% s! Q
34 $ q: J2 h, R `: T) a35 ' t* f# n* T! G$ m( R$ ]36 ( B2 q* h/ d" d' D& W" X/ W37$ w* H0 Q6 Q) u. A% Y8 F
38( |1 L" }* S: L& j
39 ) |3 o, p; x8 E6 c2 t3 [40- l6 I1 _% g- Z8 ]& T: T
41 - ^8 d3 Q y& P/ c42 2 T5 b2 M! b/ ^43% y+ l! `) o& ~$ L2 L) J, q
44 2 ]$ f! I* j0 c# D$ j' ^45- e, F4 O. \& I2 r, a1 e
46" q) r, C# j5 M; Q7 H. y5 a' G, x
47 , M* m4 G0 a8 ?. r/ s: B9 e, C, |1 E48 ! z f2 L4 j: V } c6 `# T49+ W; {) b5 w8 D: f+ [
50 # N. n3 ^: ~% S \9 Z3 ]2 R51 2 j7 [ L; n5 _9 @: D9 s526 g+ _ D! h2 x& s
53 1 `, g; X6 A: h: u54 ; V: E% D% F5 N9 M2 F, O/ z55& E* g6 `+ F# g6 V) p! p, b7 F
3.代码实现 ) m! t( H+ o6 S! `7 c* Cimport torch# R) W- p4 | J: n
import torch.nn as nn0 W& f2 C( S4 t y+ H; `+ O5 r3 x
from torchvision import transforms 1 M' K' o( G6 i5 N/ V 6 ^2 `' q" r! K# e- U$ E $ }3 D/ ~+ d: a3 b& yimg=torch.randint(10,size=(1,4,4),dtype=torch.float32)2 Y9 X" |) e8 o4 l* q
print(img) 5 o1 U, z3 W$ I2 N2 nprint('---'*5)# m$ I) j) x. h! d! d
bicubic_interpolation=transforms.Resize(size=(8,8),( \" D* E; z; g
interpolation=transforms.InterpolationMode.BICUBIC)* D% I8 K& Z% f* K5 ]" G7 v
resize_img=bicubic_interpolation(img) c" w7 Y% b2 T( B2 h; u4 z/ U: v1 Tprint(resize_img) 3 Y( [/ `' a* ^1( |7 i4 {* |, `! E0 C7 |
2$ S. X* o. q3 J+ X& r) B! ]0 ]$ Y
3, ^8 l) u; E7 x0 I6 Y( q; h! |. X
4( r( {" A5 s) R2 |. i0 }1 o
58 A3 _* y# H( }! _
6 9 A$ o/ m9 R9 z* ]# n- W% m7 ' `' U$ D1 M# c4 S8 # a8 C/ D$ C7 u1 B+ G* I% n9 , g! E+ j: M9 |+ P4 b10 0 T( F7 R6 k, t7 r. |0 y5 V11 ( w3 w! N) ?' T0 z" e2 D125 K. Q% C) z+ S0 t& i" O
四、Pytorch实现 9 T% T( w# O# ~! f& V( O大家注意在Pytorch中不同插值方法是通过对transforms.Resize方法中的interpolation参数指定,上面这三种方法只需要依次采用下面三种模式即可:3 D! f7 V1 y- ~: `2 F; m" f
5 T& \: R) a2 j插值方法 指定方式/ S3 @# j6 V1 f( D% U1 T2 @
最近邻插值 transforms.InterpolationMode.NEAREST ! N D7 H( T- c& M- g双线性插值 transforms.InterpolationMode.BILINEAR ( }/ C( l( G$ [; G9 M, C+ s双三次插值 transforms.InterpolationMode.BICUBIC ; A& Z/ U, m* r# t' h5 e$ p这里我使用周杰伦的一张照片展示一下三种方法对应的插值结果:1 N1 t: g# \+ g) ~( R, D+ ?9 H6 b9 D
原图如下: $ ~! f" x6 E+ _. n$ @( A' C3 I9 Y ) ^3 M. g3 ?* T3 B7 @7 [1 {+ f2 G* y8 G0 i# g
import torch2 R; Q |3 V. J, g% [1 M( H) |4 J
from torchvision import transforms 7 ^9 c' r/ p' l1 D; Tfrom PIL import Image% a9 n8 t4 ?! C7 y* A
from torchvision.utils import save_image9 i1 M, [3 \1 B6 Z3 `9 R% v# X
% d4 ~+ J% C! {& ~# E0 A: Q
2 r5 d b8 B; O9 ?img=Image.open('./Jay.png',mode='r') ) ~; S* B9 `0 y! K# z& wimg_to_tensor=transforms.ToTensor()(img)3 Y7 ^+ j5 {0 j5 i1 b' [7 E
# print(img_to_tensor.shape) 2 E* v2 V: C/ E5 r5 C4 m' ? . Y, F) m( Q. v7 z* cnearest_neighbor_interpolation=transforms.Resize(size=(1024,1024), 4 b4 \0 x6 C, z; b interpolation=transforms.InterpolationMode.NEAREST)3 P9 z& `& B" o. c8 H
nearest_resize_img=nearest_neighbor_interpolation(img_to_tensor)& L6 j* Y* H6 I& \) q
# k' z& ~5 M' j0 u; o
bilinear_interpolation=transforms.Resize(size=(1024,10248),4 ]) C9 Q/ u! U: a
interpolation=transforms.InterpolationMode.BILINEAR)1 B/ M3 U7 D( G+ V: ^
bilinear_resize_img=bilinear_interpolation(img_to_tensor)/ R3 B# x$ i/ q, N, X
# , U# P' B9 R# `5 ]bicubic_interpolation=transforms.Resize(size=(1024,1024), & W3 `/ I( ~; o$ z5 ? interpolation=transforms.InterpolationMode.BICUBIC) l/ p; S' {: }* z) `* _6 U2 obicubic_resize_img=bicubic_interpolation(img_to_tensor) , y6 B- U: P" W5 @; [7 v8 A 6 Z8 d5 q# e/ B. V# g* v3 Jsave_image(nearest_resize_img,'./nearest.png') K/ L S% E# K4 ]4 z( Osave_image(bilinear_resize_img,'./bilinear.png') / t) z( J7 l7 j5 u5 ~save_image(bicubic_resize_img,'./bicubic.png'); p5 Q9 Y6 C: a0 B7 ?