| |
|
|
| from __future__ import absolute_import, division, print_function |
|
|
| import torch |
| import torch.nn.functional as tf |
| from torch import nn |
|
|
|
|
| def _bchw2bhwc(tensor): |
| return tensor.transpose(1, 2).transpose(2, 3) |
|
|
|
|
| def _bhwc2bchw(tensor): |
| return tensor.transpose(2, 3).transpose(1, 2) |
|
|
|
|
| class Meshgrid(nn.Module): |
| def __init__(self): |
| super(Meshgrid, self).__init__() |
| self.width = 0 |
| self.height = 0 |
| self.register_buffer("xx", torch.zeros(1, 1)) |
| self.register_buffer("yy", torch.zeros(1, 1)) |
| self.register_buffer("rangex", torch.zeros(1, 1)) |
| self.register_buffer("rangey", torch.zeros(1, 1)) |
|
|
| def _compute_meshgrid(self, width, height): |
| torch.arange(0, width, out=self.rangex) |
| torch.arange(0, height, out=self.rangey) |
| self.xx = self.rangex.repeat(height, 1).contiguous() |
| self.yy = self.rangey.repeat(width, 1).t().contiguous() |
|
|
| def forward(self, width, height): |
| if self.width != width or self.height != height: |
| self._compute_meshgrid(width=width, height=height) |
| self.width = width |
| self.height = height |
| return self.xx, self.yy |
|
|
|
|
| class BatchSub2Ind(nn.Module): |
| def __init__(self): |
| super(BatchSub2Ind, self).__init__() |
| self.register_buffer("_offsets", torch.LongTensor()) |
|
|
| def forward(self, shape, row_sub, col_sub, out=None): |
| batch_size = row_sub.size(0) |
| height, width = shape |
| ind = row_sub * width + col_sub |
| torch.arange(batch_size, out=self._offsets) |
| self._offsets *= height * width |
|
|
| if out is None: |
| return torch.add(ind, self._offsets.view(-1, 1, 1)) |
| else: |
| torch.add(ind, self._offsets.view(-1, 1, 1), out=out) |
|
|
|
|
| class Interp2(nn.Module): |
| def __init__(self, clamp=False): |
| super(Interp2, self).__init__() |
| self._clamp = clamp |
| self._batch_sub2ind = BatchSub2Ind() |
| self.register_buffer("_x0", torch.LongTensor()) |
| self.register_buffer("_x1", torch.LongTensor()) |
| self.register_buffer("_y0", torch.LongTensor()) |
| self.register_buffer("_y1", torch.LongTensor()) |
| self.register_buffer("_i00", torch.LongTensor()) |
| self.register_buffer("_i01", torch.LongTensor()) |
| self.register_buffer("_i10", torch.LongTensor()) |
| self.register_buffer("_i11", torch.LongTensor()) |
| self.register_buffer("_v00", torch.FloatTensor()) |
| self.register_buffer("_v01", torch.FloatTensor()) |
| self.register_buffer("_v10", torch.FloatTensor()) |
| self.register_buffer("_v11", torch.FloatTensor()) |
| self.register_buffer("_x", torch.FloatTensor()) |
| self.register_buffer("_y", torch.FloatTensor()) |
|
|
| def forward(self, v, xq, yq): |
| batch_size, channels, height, width = v.size() |
|
|
| |
| if self._clamp: |
| xq.clamp_(0, width - 1) |
| yq.clamp_(0, height - 1) |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| self._x0 = torch.floor(xq).long().clamp(0, width - 1) |
| self._y0 = torch.floor(yq).long().clamp(0, height - 1) |
|
|
| self._x1 = torch.add(self._x0, 1).clamp(0, width - 1) |
| self._y1 = torch.add(self._y0, 1).clamp(0, height - 1) |
|
|
| |
| self._batch_sub2ind([height, width], self._y0, self._x0, out=self._i00) |
| self._batch_sub2ind([height, width], self._y0, self._x1, out=self._i01) |
| self._batch_sub2ind([height, width], self._y1, self._x0, out=self._i10) |
| self._batch_sub2ind([height, width], self._y1, self._x1, out=self._i11) |
|
|
| |
| v_flat = _bchw2bhwc(v).contiguous().view(-1, channels) |
| torch.index_select(v_flat, dim=0, index=self._i00.view(-1), out=self._v00) |
| torch.index_select(v_flat, dim=0, index=self._i01.view(-1), out=self._v01) |
| torch.index_select(v_flat, dim=0, index=self._i10.view(-1), out=self._v10) |
| torch.index_select(v_flat, dim=0, index=self._i11.view(-1), out=self._v11) |
|
|
| |
| torch.add(xq, -self._x0.float(), out=self._x) |
| torch.add(yq, -self._y0.float(), out=self._y) |
|
|
| |
| w00 = torch.unsqueeze((1.0 - self._y) * (1.0 - self._x), dim=1) |
| w01 = torch.unsqueeze((1.0 - self._y) * self._x, dim=1) |
| w10 = torch.unsqueeze(self._y * (1.0 - self._x), dim=1) |
| w11 = torch.unsqueeze(self._y * self._x, dim=1) |
|
|
| def _reshape(u): |
| return _bhwc2bchw(u.view(batch_size, height, width, channels)) |
|
|
| |
| values = ( |
| _reshape(self._v00) * w00 |
| + _reshape(self._v01) * w01 |
| + _reshape(self._v10) * w10 |
| + _reshape(self._v11) * w11 |
| ) |
|
|
| if self._clamp: |
| return values |
| else: |
| |
| invalid = ( |
| ((xq < 0) | (xq >= width) | (yq < 0) | (yq >= height)) |
| .unsqueeze(dim=1) |
| .float() |
| ) |
| |
| transformed = invalid * torch.zeros_like(values) + (1.0 - invalid) * values |
|
|
| return transformed |
|
|
|
|
| def resize2D(inputs, size_targets, mode="bilinear"): |
| size_inputs = [inputs.size(2), inputs.size(3)] |
|
|
| if all([size_inputs == size_targets]): |
| return inputs |
| elif any([size_targets < size_inputs]): |
| resized = tf.adaptive_avg_pool2d(inputs, size_targets) |
| else: |
| resized = tf.upsample(inputs, size=size_targets, mode=mode) |
|
|
| |
| return resized |
|
|
|
|
| def resize2D_as(inputs, output_as, mode="bilinear"): |
| size_targets = [output_as.size(2), output_as.size(3)] |
| return resize2D(inputs, size_targets, mode=mode) |
|
|