# 【语义分割】语义分割上采样方法汇总

3 篇文章 0 订阅
1 篇文章 0 订阅
20 篇文章 1 订阅

1、最近邻插值

2、双线性插值

3、其他插值方法

## 一、插值

### 1、最近邻插值

numpy实现及opencv对比：

import cv2
from math import floor
import numpy as np

def interpolate_nearest(image, size):
new_img = np.zeros(shape=size[::-1] + (image.shape[-1], )).astype('uint8')
scale_h = image.shape[0] / size[1]
scale_w = image.shape[1] / size[0]
for i in range(size[1]):
for j in range(size[0]):
new_img[i, j] = image[int(floor(i * scale_h)), int(floor(j * scale_w))]
return new_img

size = (256, 256)   # w, h
my_resized_image = interpolate_nearest(image, size)
cv_resized_image = cv2.resize(image, size, image, 0, 0, cv2.INTER_NEAREST)
assert np.allclose(my_resized_image, cv_resized_image), "Image not equal between your implemented and opencv."
cv2.imshow("opencv", cv_resized_image)
cv2.imshow('my_op', my_resized_image)
cv2.waitKey(0)

### 2、双线性插值

再纵向插值，根据上一步得到的R1和R2像素值，得到P的像素值：

numpy实现：

import cv2
from math import floor
import numpy as np

def interpolate_linear(image, size):
h, w = image.shape[0:2]
w_new, h_new = size
h_scale = h / h_new
w_scale = w / w_new

h_index = np.linspace(0, h_new - 1, h_new)
w_index = np.linspace(0, w_new - 1, w_new)
wv, hv = np.meshgrid(w_index, h_index)
hv = (hv + 0.5) * h_scale - 0.5
wv = (wv + 0.5) * w_scale - 0.5
# hv = hv * h_scale
# wv = wv * w_scale
hv[hv < 0] = 0
wv[wv < 0] = 0

h_down = hv.astype('int')
w_down = wv.astype('int')
h_up = h_down + 1
w_up = w_down + 1
h_up[h_up > (h - 1)] = h - 1
w_up[w_up > (w - 1)] = w - 1

pos_00 = image[h_down, w_down].astype('int')  # 左上
pos_01 = image[h_up, w_down].astype('int')  # 左下
pos_11 = image[h_up, w_up].astype('int')  # 右下
pos_10 = image[h_down, w_up].astype('int')  # 右上

m, n = np.modf(hv)[0], np.modf(wv)[0]
m = np.expand_dims(m, axis=-1)
n = np.expand_dims(n, axis=-1)
a = pos_10 - pos_00
b = pos_01 - pos_00
c = pos_11 + pos_00 - pos_10 - pos_01
image = np.round(a * n + b * m + c * n * m + pos_00).astype('uint8')
return image

size = (256, 256)   # w, h
my_resized_image = interpolate_linear(image, size)
cv_resized_image = cv2.resize(image, size, image, 0, 0, cv2.INTER_LINEAR)
print(np.mean(np.abs(my_resized_image.astype('int') - cv_resized_image.astype('int')))) # 线性插值四舍五入数值计算像素值可能差1
assert np.allclose(my_resized_image, cv_resized_image, atol=1), "Image not equal between your implemented and opencv."
cv2.imshow("opencv", cv_resized_image)
cv2.imshow('my_op', my_resized_image)
cv2.waitKey(0)

## 二、PixelShuffle

import torch
import numpy as np

def pixel_shuffle_np(x, up_factor):
n, c, h, w = x.shape
new_shape = (n, c // (up_factor * up_factor), up_factor, up_factor, h, w)
npresult = np.reshape(x, new_shape)
npresult = npresult.transpose(0, 1, 4, 2, 5, 3)
oshape = [n, c // (up_factor * up_factor), h * up_factor, w * up_factor]
npreslut = np.reshape(npresult, oshape)
return npreslut

np.random.seed(10001)
image = np.random.rand(2, 16, 224, 224)
scale = 4
np_image = pixel_shuffle_np(image, scale)
torch_pixel_shuffle = torch.nn.PixelShuffle(scale)
torch_image = torch_pixel_shuffle(torch.from_numpy(image))
assert np.allclose(np_image, torch_image.numpy()), "Implemented PixelShuffle is not the same with torch.nn.PixelShuffle."

## 三、反池化(unpool)

torch代码：

import torch
import numpy as np

inputs = np.array([1, 2, 6, 3, 3, 5, 2, 1, 1, 2, 2, 1, 7, 3, 4, 8], dtype='float').reshape([1, 1, 4, 4])
inputs = torch.from_numpy(inputs)
pool = torch.nn.MaxPool2d(2, stride=2, return_indices=True)
unpool = torch.nn.MaxUnpool2d(2, stride=2)
output, indices = pool(inputs)
output = unpool(output, indices)
print(output)

## 四、转置卷积（逆卷积）

上面的转置卷积使得2x2的输入特征图变为3x3的输出特征图，能不能让输出特征图变得更大呢？显然可以，见下图，引入了步长后（下图的步长可以理解为输出特征图上的步长），输入特征图为2x2，核为2x2，输出特征图为4x4。

import torch

x = torch.rand(1, 3, 50, 50)
transpose_conv = torch.nn.ConvTranspose2d(3, 3, kernel_size=3, stride=2, padding=2, output_padding=1)
y = transpose_conv(x)
print(x.shape, y.shape)
# 输出：
# torch.Size([1, 3, 50, 50]) torch.Size([1, 3, 98, 98])

## 五、附录

• 4
点赞
• 8
收藏
觉得还不错? 一键收藏
• 打赏
• 0
评论
11-28 994
02-05 1853
07-22 1777
03-23 2万+
04-24

### “相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

¥1 ¥2 ¥4 ¥6 ¥10 ¥20

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、付费专栏及课程。