-
Notifications
You must be signed in to change notification settings - Fork 40
/
Copy pathdeform_conv.py
99 lines (73 loc) · 3 KB
/
deform_conv.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
from __future__ import absolute_import, division
import torch
from torch.autograd import Variable
import numpy as np
from scipy.ndimage.interpolation import map_coordinates as sp_map_coordinates
def th_flatten(a):
"""Flatten tensor"""
return a.contiguous().view(a.nelement())
def th_repeat(a, repeats, axis=0):
"""Torch version of np.repeat for 1D"""
assert len(a.size()) == 1
return th_flatten(torch.transpose(a.repeat(repeats, 1), 0, 1))
def np_repeat_2d(a, repeats):
"""Tensorflow version of np.repeat for 2D"""
assert len(a.shape) == 2
a = np.expand_dims(a, 0)
a = np.tile(a, [repeats, 1, 1])
return a
def th_gather_2d(input, coords):
inds = coords[:, 0]*input.size(1) + coords[:, 1]
x = torch.index_select(th_flatten(input), 0, inds)
return x.view(coords.size(0))
def th_map_coordinates(input, coords, order=1):
"""Tensorflow verion of scipy.ndimage.map_coordinates
Note that coords is transposed and only 2D is supported
Parameters
----------
input : tf.Tensor. shape = (s, s)
coords : tf.Tensor. shape = (n_points, 2)
"""
assert order == 1
input_size = input.size(0)
coords = torch.clamp(coords, 0, input_size - 1)
coords_lt = coords.floor().long()
coords_rb = coords.ceil().long()
coords_lb = torch.stack([coords_lt[:, 0], coords_rb[:, 1]], 1)
coords_rt = torch.stack([coords_rb[:, 0], coords_lt[:, 1]], 1)
vals_lt = th_gather_2d(input, coords_lt.detach())
vals_rb = th_gather_2d(input, coords_rb.detach())
vals_lb = th_gather_2d(input, coords_lb.detach())
vals_rt = th_gather_2d(input, coords_rt.detach())
coords_offset_lt = coords - coords_lt.type(coords.data.type())
vals_t = vals_lt + (vals_rt - vals_lt) * coords_offset_lt[:, 0]
vals_b = vals_lb + (vals_rb - vals_lb) * coords_offset_lt[:, 0]
mapped_vals = vals_t + (vals_b - vals_t) * coords_offset_lt[:, 1]
return mapped_vals
def sp_batch_map_coordinates(inputs, coords):
"""Reference implementation for batch_map_coordinates"""
# coords = coords.clip(0, inputs.shape[1] - 1)
assert (coords.shape[2] == 2)
height = coords[:,:,0].clip(0, inputs.shape[1] - 1)
width = coords[:,:,1].clip(0, inputs.shape[2] - 1)
np.concatenate((np.expand_dims(height, axis=2), np.expand_dims(width, axis=2)), 2)
mapped_vals = np.array([
sp_map_coordinates(input, coord.T, mode='nearest', order=1)
for input, coord in zip(inputs, coords)
])
return mapped_vals
def th_batch_map_coordinates(input, coords, order=1):
"""Batch version of th_map_coordinates
Only supports 2D feature maps
Parameters
----------
input : tf.Tensor. shape = (b, s, s)
coords : tf.Tensor. shape = (b, n_points, 2)
Returns
-------
tf.Tensor. shape = (b, s, s)
"""
batch_size = input.size(0)
input_height = input.size(1)
input_width = input.size(2)
n_coords = coords.size(1)