Pytorch 图片数据增强

发布 : 2020-02-25 分类 : 深度学习 浏览 :

Pytorch 随机擦除和Möbius 变换变换

直接上代码

  • 使用时按需选择
1
2
3
4
5
6
7
8
9
10
11
12
import transforms

train_transforms = transforms.Compose([
transforms.RandomRotation(10),
transforms.RandomHorizontalFlip(),
# transforms.MobiusTransformations(),
# transforms.RandomResizedCrop(input_size),
transforms.Resize(input_size),
transforms.ToTensor(),
transforms.Normalize((.5, .5, .5), (.5, .5, .5))
# transforms.RandomErasing()
])
  • transforms.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
from __future__ import absolute_import

from torchvision.transforms import *

from PIL import Image
import random
import math
import numpy as np
import torch
import mobius_transformations as mt
import cv2

class RandomErasing(object):
'''
Class that performs Random Erasing in Random Erasing Data Augmentation by Zhong et al.
-------------------------------------------------------------------------------------
probability: The probability that the operation will be performed.
sl: min erasing area
sh: max erasing area
r1: min aspect ratio
mean: erasing value
-------------------------------------------------------------------------------------
'''

def __init__(self, probability=0.5, sl=0.02, sh=0.4, r1=0.3, mean=[0.4914, 0.4822, 0.4465]):
self.probability = probability
self.mean = mean
self.sl = sl
self.sh = sh
self.r1 = r1

def __call__(self, X):
if random.uniform(0, 1) > self.probability:
return X
for img in X:
for attempt in range(1):
area = img.size()[1] * img.size()[2]

target_area = random.uniform(self.sl, self.sh) * area
aspect_ratio = random.uniform(self.r1, 1 / self.r1)

h = int(round(math.sqrt(target_area * aspect_ratio)))
w = int(round(math.sqrt(target_area / aspect_ratio)))

if w < img.size()[2] and h < img.size()[1]:
x1 = random.randint(0, img.size()[1] - h)
y1 = random.randint(0, img.size()[2] - w)
if img.size()[0] == 3:
img[0, x1:x1 + h, y1:y1 + w] = self.mean[0]
img[1, x1:x1 + h, y1:y1 + w] = self.mean[1]
img[2, x1:x1 + h, y1:y1 + w] = self.mean[2]
else:
img[0, x1:x1 + h, y1:y1 + w] = self.mean[0]

return X


class MobiusTransformations(object):
def __init__(self):
self.FUNCLIST = [mt._clockwise_twist, mt._clockwise_half_twist, mt._spread, mt._spread_twist,
mt._counter_clockwise_twist,
mt._counter_clockwise_half_twist, mt._inverse, mt._inverse_spread]

def __call__(self, X):
source_image = np.asarray(X).astype(np.float64)
transformation_type = random.choice(self.FUNCLIST)
out_image = mt.apply_SL2C_elt_to_image(source_image, transformation_type)
np.clip(out_image, 0, 255, out_image)
out_image = Image.fromarray(out_image.astype('uint8'), "RGB")
return out_image
  • mobius_transformations.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import numpy as np
import math as m
from numpy import pi as PI
import cv2


### Apply tranformations
def get_abcd_from_3points(z1, z2, z3, w1, w2, w3):
a = np.linalg.det(np.array([[z1 * w1, w1, 1], [z2 * w2, w2, 1], [z3 * w3, w3, 1]]))
b = np.linalg.det(np.array([[z1 * w1, z1, w1], [z2 * w2, z2, w2], [z3 * w3, z3, w3]]))
c = np.linalg.det(np.array([[z1, w1, 1], [z2, w2, 1], [z3, w3, 1]]))
d = np.linalg.det(np.array([[z1 * w1, z1, 1], [z2 * w2, z2, 1], [z3 * w3, z3, 1]]))
return a, b, c, d


def _clockwise_twist(x, y):
z1, z2, z3 = complex(1, 0.5 * y), complex(0.5 * x, 0.8 * y), complex(0.6 * x, 0.5 * y)
w1 = complex(0.5 * x, y - 1)
w2 = complex(0.5 * x + 0.3 * m.sin(0.4 * PI) * y, 0.5 * y + 0.3 * m.cos(0.4 * PI) * y)
w3 = complex(0.5 * x + 0.1 * m.cos(0.1 * PI) * y, 0.5 * y - 0.1 * m.sin(0.1 * PI) * x)
return get_abcd_from_3points(z1, z2, z3, w1, w2, w3)


def _clockwise_half_twist(x, y):
z1, z2, z3 = complex(1, 0.5 * y), complex(0.5 * x, 0.8 * y), complex(0.6 * x, 0.5 * y)
w1 = complex(0.5 * x, y - 1)
w2 = complex(0.5 * x + 0.4 * y, 0.5 * y)
w3 = complex(0.5 * x, 0.5 * y - 0.1 * x)
return get_abcd_from_3points(z1, z2, z3, w1, w2, w3)


def _spread(x, y):
z1, z2, z3 = complex(0.3 * x, 0.5 * y), complex(0.5 * x, 0.7 * y), complex(0.7 * x, 0.5 * y)
w1, w2, w3 = complex(0.2 * x, 0.5 * y), complex(0.5 * x, 0.8 * y), complex(0.8 * x, 0.5 * y)
return get_abcd_from_3points(z1, z2, z3, w1, w2, w3)


def _spread_twist(x, y):
z1, z2, z3 = complex(0.3 * x, 0.3 * y), complex(0.6 * x, 0.8 * y), complex(0.7 * x, 0.3 * y)
w1, w2, w3 = complex(0.2 * x, 0.3 * y), complex(0.6 * x, 0.9 * y), complex(0.8 * x, 0.2 * y)
return get_abcd_from_3points(z1, z2, z3, w1, w2, w3)


def _counter_clockwise_twist(x, y):
z1, z2, z3 = complex(1, 0.5 * y), complex(0.5 * x, 0.8 * y), complex(0.6 * x, 0.5 * y)
w1 = complex(0.5 * x, y - 1)
w2 = complex(0.5 * x + 0.4 * y, 0.5 * y)
w3 = complex(0.5 * x, 0.5 * y - 0.1 * x)
return get_abcd_from_3points(z1, z2, z3, w1, w2, w3)


def _counter_clockwise_half_twist(x, y):
z1, z2, z3 = complex(1, 0.5 * y), complex(0.5 * x, 0.8 * y), complex(0.6 * x, 0.5 * y)
w1 = complex(0.5 * x, y - 1)
w2 = complex(0.5 * x + 0.3 * m.sin(0.4 * PI) * y, 0.5 * y + 0.3 * m.cos(0.4 * PI) * y)
w3 = complex(0.5 * x + 0.1 * m.cos(0.1 * PI) * x, 0.5 * y - 0.1 * m.sin(0.1 * PI) * x)
return get_abcd_from_3points(z1, z2, z3, w1, w2, w3)


def _inverse(x, y):
z1, z2, z3 = complex(0.3 * x, 0.5 * y), complex(0.5 * x, 0.9 * y), complex(x - 1, 0.5 * y)
w1, w2, w3 = complex(x - 1, 0.5 * y), complex(0.5 * x, 0.1 * y), complex(1, 0.5 * y)
return get_abcd_from_3points(z1, z2, z3, w1, w2, w3)


def _inverse_spread(x, y):
z1, z2, z3 = complex(0.1 * x, 0.5 * y), complex(0.5 * x, 0.8 * y), complex(0.9 * x, 0.5 * y)
w1, w2, w3 = complex(x - 1, 0.5 * y), complex(0.5 * x, 0.1 * y), complex(1, 0.5 * y)
return get_abcd_from_3points(z1, z2, z3, w1, w2, w3)


def get_in_location_for_out_location(pts_out, a, b, c, d):
# pts_out shape 2 x (num pixels)
A = np.array([[a.real], [a.imag]])
B = np.array([[b.real], [b.imag]])
C = np.array([[c.real, -c.imag], [c.imag, c.real]])
D = np.array([[d.real, -d.imag], [d.imag, d.real]])
pts_in = np.empty_like(pts_out)
W = pts_out # shape 2 x
DW = D @ W
CW = C @ W
B_DW = B - DW
CW_A = CW - A
CW_A_2 = (CW_A ** 2).sum(axis=0)
O1 = (B_DW * CW_A).sum(axis=0) / CW_A_2
B_DW_T = -1 * B_DW[0, :]
B_DW[0, :] = B_DW[1, :]
B_DW[1, :] = B_DW_T
O2 = (B_DW * CW_A).sum(axis=0) / CW_A_2
pts_in[0, :] = O1
pts_in[1, :] = O2
return pts_in


def get_out_location_for_in_location(pts_in, a, b, c, d):
# pts_in shape 2 x (num pixels)
A = np.array([[a.real, -a.imag], [a.imag, a.real]])
B = np.array([[b.real], [b.imag]])
C = np.array([[c.real, -c.imag], [c.imag, c.real]])
D = np.array([[d.real], [d.imag]])
pts_out = np.empty_like(pts_in)
Z = pts_in # shape 2 x
AZ = A @ Z
CZ = C @ Z
AZ_P_B = AZ + B
CZ_P_D = CZ + D
CZ_P_D_2 = (CZ_P_D ** 2).sum(axis=0)
O1 = (AZ_P_B * CZ_P_D).sum(axis=0) / CZ_P_D_2
AZ_P_B_T = -1 * AZ_P_B[0, :]
AZ_P_B[0, :] = AZ_P_B[1, :]
AZ_P_B[1, :] = AZ_P_B_T
O2 = (AZ_P_B * CZ_P_D).sum(axis=0) / CZ_P_D_2
pts_out[0, :] = O1
pts_out[1, :] = O2
return pts_out


# 双线性插值矩阵运算,减少计算量
def bilinear(pts_in, pts_out, s_im, o_min, o_max):
in_size = s_im.shape[:-1]
i_max = pts_in.max(axis=1)
i_min = pts_in.min(axis=1)
X, Y = (pts_in[0, :] - i_min[0]).reshape((pts_in.shape[1], 1)), (pts_in[1, :] - i_min[1]).reshape(
(pts_in.shape[1], 1))
p_h = max(2, -i_max[0] + i_min[0] + in_size[0])
p_w = max(2, -i_max[1] + i_min[1] + in_size[1])
p = max(p_h, p_w)
n_im = np.zeros((int(i_max[0] - i_min[0] + p), int(i_max[1] - i_min[1] + p), 3))
n_im[int(-i_min[0]):int(-i_min[0] + in_size[0]), int(-i_min[1]):int(-i_min[1] + in_size[1])] = s_im
t_left_X, t_left_Y = np.floor(X).astype(np.int16), np.floor(Y).astype(np.int16)
P1 = (t_left_X + 1 - X) * n_im[t_left_X, t_left_Y, :].reshape(pts_in.shape[1], 3) + (X - t_left_X) * n_im[
t_left_X + 1,
t_left_Y,
:].reshape(
pts_in.shape[1], 3)
P2 = (t_left_X + 1 - X) * n_im[t_left_X, t_left_Y + 1, :].reshape(pts_in.shape[1], 3) + (X - t_left_X) * n_im[
t_left_X + 1,
t_left_Y + 1,
:].reshape(
pts_in.shape[1], 3)
V = (t_left_Y + 1 - Y) * P1 + (Y - t_left_Y) * P2
o_im = V.reshape((o_max[0] - o_min[0], o_max[1] - o_min[1], 3))
return o_im


# Receives an np.matrix as the respresentation of the mobius transformation
def apply_SL2C_elt_to_image(src_image, transformation_type):
s_im = np.atleast_3d(src_image)
in_size = s_im.shape[:-1]
a, b, c, d = transformation_type(in_size[0], in_size[1])

pts_in = np.indices(in_size).reshape((2, -1)) # results in a 2 x (num pixels) array of indices
pts_out = get_out_location_for_in_location(pts_in, a, b, c, d)
o_max = pts_out.max(axis=1)
o_min = pts_out.min(axis=1)

pts_out = np.indices(((o_max - o_min)[0], (o_max - o_min)[1])).reshape(
(2, -1)) # results in a 2 x (num pixels) array of indices
pts_out = pts_out + np.array([[o_min[0]], [o_min[1]]])

pts_in = get_in_location_for_out_location(pts_out, a, b, c, d)

o_im = bilinear(pts_in, pts_out, s_im, o_min, o_max)
return o_im


def main():
FUNCLIST = [_clockwise_twist, _clockwise_half_twist, _spread, _spread_twist, _counter_clockwise_twist,
_counter_clockwise_half_twist, _inverse, _inverse_spread]
source_image = np.array(cv2.imread('20160222_081102_1281_361.jpg'), dtype=np.float32)
print(source_image.shape)
for ii, transformation_type in enumerate(FUNCLIST):
out_image = apply_SL2C_elt_to_image(source_image, transformation_type)
np.clip(out_image, 0, 255, out_image)
cv2.imwrite(str(ii) + '.png', out_image)


if __name__ == '__main__':
main()

参考

Mobius-transformations

本文作者 : HeoLis
原文链接 : https://ishero.net/Pytorch%20%E5%9B%BE%E7%89%87%E6%95%B0%E6%8D%AE%E5%A2%9E%E5%BC%BA.html
版权声明 : 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!

学习、记录、分享、获得

微信扫一扫, 向我投食

微信扫一扫, 向我投食