|
|
import cv2
|
|
|
import matplotlib.pyplot as plt
|
|
|
import numpy as np
|
|
|
import torch
|
|
|
import torchvision.transforms as transforms
|
|
|
from PIL import Image
|
|
|
|
|
|
cnn_normalization_mean = [0.485, 0.456, 0.406]
|
|
|
cnn_normalization_std = [0.229, 0.224, 0.225]
|
|
|
tensor_normalizer = transforms.Normalize(mean=cnn_normalization_mean, std=cnn_normalization_std)
|
|
|
epsilon = 1e-5
|
|
|
|
|
|
|
|
|
def preprocess_image(image, target_width=None):
|
|
|
"""输入 PIL.Image 对象,输出标准化后的四维 tensor"""
|
|
|
if target_width:
|
|
|
t = transforms.Compose([
|
|
|
transforms.Resize(target_width),
|
|
|
transforms.CenterCrop(target_width),
|
|
|
transforms.ToTensor(),
|
|
|
tensor_normalizer,
|
|
|
])
|
|
|
else:
|
|
|
t = transforms.Compose([
|
|
|
transforms.ToTensor(),
|
|
|
tensor_normalizer,
|
|
|
])
|
|
|
return t(image).unsqueeze(0)
|
|
|
|
|
|
|
|
|
def image_to_tensor(image, target_width=None):
|
|
|
"""输入 OpenCV 图像,范围 0~255,BGR 顺序,输出标准化后的四维 tensor"""
|
|
|
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
|
|
image = Image.fromarray(image)
|
|
|
return preprocess_image(image, target_width)
|
|
|
|
|
|
|
|
|
def read_image(path, target_width=None):
|
|
|
"""输入图像路径,输出标准化后的四维 tensor"""
|
|
|
image = Image.open(path)
|
|
|
return preprocess_image(image, target_width)
|
|
|
|
|
|
|
|
|
def recover_image(tensor):
|
|
|
"""输入 GPU 上的四维 tensor,输出 0~255 范围的三维 numpy 矩阵,RGB 顺序"""
|
|
|
image = tensor.detach().cpu().numpy()
|
|
|
image = image * np.array(cnn_normalization_std).reshape((1, 3, 1, 1)) + \
|
|
|
np.array(cnn_normalization_mean).reshape((1, 3, 1, 1))
|
|
|
return (image.transpose(0, 2, 3, 1) * 255.).clip(0, 255).astype(np.uint8)[0]
|
|
|
|
|
|
|
|
|
def recover_tensor(tensor):
|
|
|
m = torch.tensor(cnn_normalization_mean).view(1, 3, 1, 1).to(tensor.device)
|
|
|
s = torch.tensor(cnn_normalization_std).view(1, 3, 1, 1).to(tensor.device)
|
|
|
tensor = tensor * s + m
|
|
|
return tensor.clamp(0, 1)
|
|
|
|
|
|
|
|
|
def imshow(tensor, title=None):
|
|
|
"""输入 GPU 上的四维 tensor,然后绘制该图像"""
|
|
|
image = recover_image(tensor)
|
|
|
print(image.shape)
|
|
|
plt.imshow(image)
|
|
|
if title is not None:
|
|
|
plt.title(title)
|
|
|
|
|
|
|
|
|
def mean_std(features):
|
|
|
"""输入 VGG16 计算的四个特征,输出每张特征图的均值和标准差,长度为1920"""
|
|
|
mean_std_features = []
|
|
|
for x in features:
|
|
|
x = x.view(*x.shape[:2], -1)
|
|
|
x = torch.cat([x.mean(-1), torch.sqrt(x.var(-1) + epsilon)], dim=-1)
|
|
|
n = x.shape[0]
|
|
|
x2 = x.view(n, 2, -1).transpose(2, 1).contiguous().view(n, -1) # 【mean, ..., std, ...] to [mean, std, ...]
|
|
|
mean_std_features.append(x2)
|
|
|
mean_std_features = torch.cat(mean_std_features, dim=-1)
|
|
|
return mean_std_features
|
|
|
|
|
|
|
|
|
class Smooth:
|
|
|
# 对输入的数据进行滑动平均
|
|
|
def __init__(self, windowsize=100):
|
|
|
self.window_size = windowsize
|
|
|
self.data = np.zeros((self.window_size, 1), dtype=np.float32)
|
|
|
self.index = 0
|
|
|
|
|
|
def __iadd__(self, x):
|
|
|
if self.index == 0:
|
|
|
self.data[:] = x
|
|
|
self.data[self.index % self.window_size] = x
|
|
|
self.index += 1
|
|
|
return self
|
|
|
|
|
|
def __float__(self):
|
|
|
return float(self.data.mean())
|
|
|
|
|
|
def __format__(self, f):
|
|
|
return self.__float__().__format__(f)
|