|
|
|
@ -485,9 +485,9 @@ class LoadImagesAndLabels(Dataset): # for training/testing
|
|
|
|
|
|
|
|
|
|
# MixUp https://arxiv.org/pdf/1710.09412.pdf
|
|
|
|
|
# if random.random() < 0.5:
|
|
|
|
|
# img2, labels2 = load_mosaic(self, random.randint(0, len(self.labels) - 1))
|
|
|
|
|
# img2, labels2 = load_mosaic(self, random.randint(0, len(self.labels) - 1))
|
|
|
|
|
# r = np.random.beta(0.3, 0.3) # mixup ratio, alpha=beta=0.3
|
|
|
|
|
# img = (img * r + img2 * (1 - r)).astype(np.uint8)
|
|
|
|
|
# img = (img * r + img2 * (1 - r)).astype(np.uint8)
|
|
|
|
|
# labels = np.concatenate((labels, labels2), 0)
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
@ -513,11 +513,11 @@ class LoadImagesAndLabels(Dataset): # for training/testing
|
|
|
|
|
if self.augment:
|
|
|
|
|
# Augment imagespace
|
|
|
|
|
if not self.mosaic:
|
|
|
|
|
img, labels = random_affine(img, labels,
|
|
|
|
|
degrees=hyp['degrees'],
|
|
|
|
|
translate=hyp['translate'],
|
|
|
|
|
scale=hyp['scale'],
|
|
|
|
|
shear=hyp['shear'])
|
|
|
|
|
img, labels = random_perspective(img, labels,
|
|
|
|
|
degrees=hyp['degrees'],
|
|
|
|
|
translate=hyp['translate'],
|
|
|
|
|
scale=hyp['scale'],
|
|
|
|
|
shear=hyp['shear'])
|
|
|
|
|
|
|
|
|
|
# Augment colorspace
|
|
|
|
|
augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v'])
|
|
|
|
@ -610,7 +610,7 @@ def load_mosaic(self, index):
|
|
|
|
|
|
|
|
|
|
labels4 = []
|
|
|
|
|
s = self.img_size
|
|
|
|
|
yc, xc = [int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border] # mosaic center x, y
|
|
|
|
|
yc, xc = s, s # mosaic center x, y
|
|
|
|
|
indices = [index] + [random.randint(0, len(self.labels) - 1) for _ in range(3)] # 3 additional image indices
|
|
|
|
|
for i, index in enumerate(indices):
|
|
|
|
|
# Load image
|
|
|
|
@ -656,12 +656,12 @@ def load_mosaic(self, index):
|
|
|
|
|
|
|
|
|
|
# Augment
|
|
|
|
|
# img4 = img4[s // 2: int(s * 1.5), s // 2:int(s * 1.5)] # center crop (WARNING, requires box pruning)
|
|
|
|
|
img4, labels4 = random_affine(img4, labels4,
|
|
|
|
|
degrees=self.hyp['degrees'],
|
|
|
|
|
translate=self.hyp['translate'],
|
|
|
|
|
scale=self.hyp['scale'],
|
|
|
|
|
shear=self.hyp['shear'],
|
|
|
|
|
border=self.mosaic_border) # border to remove
|
|
|
|
|
img4, labels4 = random_perspective(img4, labels4,
|
|
|
|
|
degrees=self.hyp['degrees'],
|
|
|
|
|
translate=self.hyp['translate'],
|
|
|
|
|
scale=self.hyp['scale'],
|
|
|
|
|
shear=self.hyp['shear'],
|
|
|
|
|
border=self.mosaic_border) # border to remove
|
|
|
|
|
|
|
|
|
|
return img4, labels4
|
|
|
|
|
|
|
|
|
@ -716,36 +716,54 @@ def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scale
|
|
|
|
|
return img, ratio, (dw, dh)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def random_affine(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, border=(0, 0)):
|
|
|
|
|
def random_perspective(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, perspective=0.0, border=(0, 0)):
|
|
|
|
|
# torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10))
|
|
|
|
|
# https://medium.com/uruvideo/dataset-augmentation-with-random-homographies-a8f4b44830d4
|
|
|
|
|
# targets = [cls, xyxy]
|
|
|
|
|
|
|
|
|
|
height = img.shape[0] + border[0] * 2 # shape(h,w,c)
|
|
|
|
|
width = img.shape[1] + border[1] * 2
|
|
|
|
|
|
|
|
|
|
# Center
|
|
|
|
|
C = np.eye(3)
|
|
|
|
|
C[0, 2] = -img.shape[1] / 2 # x translation (pixels)
|
|
|
|
|
C[1, 2] = -img.shape[0] / 2 # y translation (pixels)
|
|
|
|
|
|
|
|
|
|
# Perspective
|
|
|
|
|
P = np.eye(3)
|
|
|
|
|
P[2, 0] = random.uniform(-perspective, perspective) # x perspective (about y)
|
|
|
|
|
P[2, 1] = random.uniform(-perspective, perspective) # y perspective (about x)
|
|
|
|
|
|
|
|
|
|
# Rotation and Scale
|
|
|
|
|
R = np.eye(3)
|
|
|
|
|
a = random.uniform(-degrees, degrees)
|
|
|
|
|
# a += random.choice([-180, -90, 0, 90]) # add 90deg rotations to small rotations
|
|
|
|
|
s = random.uniform(1 - scale, 1 + scale)
|
|
|
|
|
# s = 2 ** random.uniform(-scale, scale)
|
|
|
|
|
R[:2] = cv2.getRotationMatrix2D(angle=a, center=(img.shape[1] / 2, img.shape[0] / 2), scale=s)
|
|
|
|
|
|
|
|
|
|
# Translation
|
|
|
|
|
T = np.eye(3)
|
|
|
|
|
T[0, 2] = random.uniform(-translate, translate) * img.shape[1] + border[1] # x translation (pixels)
|
|
|
|
|
T[1, 2] = random.uniform(-translate, translate) * img.shape[0] + border[0] # y translation (pixels)
|
|
|
|
|
R[:2] = cv2.getRotationMatrix2D(angle=a, center=(0, 0), scale=s)
|
|
|
|
|
|
|
|
|
|
# Shear
|
|
|
|
|
S = np.eye(3)
|
|
|
|
|
S[0, 1] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # x shear (deg)
|
|
|
|
|
S[1, 0] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # y shear (deg)
|
|
|
|
|
|
|
|
|
|
# Translation
|
|
|
|
|
T = np.eye(3)
|
|
|
|
|
T[0, 2] = random.uniform(0.5 - translate, 0.5 + translate) * width # x translation (pixels)
|
|
|
|
|
T[1, 2] = random.uniform(0.5 - translate, 0.5 + translate) * height # y translation (pixels)
|
|
|
|
|
|
|
|
|
|
# Combined rotation matrix
|
|
|
|
|
M = S @ T @ R # ORDER IS IMPORTANT HERE!!
|
|
|
|
|
M = T @ S @ R @ P @ C # order of operations (right to left) is IMPORTANT
|
|
|
|
|
if (border[0] != 0) or (border[1] != 0) or (M != np.eye(3)).any(): # image changed
|
|
|
|
|
img = cv2.warpAffine(img, M[:2], dsize=(width, height), flags=cv2.INTER_LINEAR, borderValue=(114, 114, 114))
|
|
|
|
|
if perspective:
|
|
|
|
|
img = cv2.warpPerspective(img, M, dsize=(width, height), borderValue=(114, 114, 114))
|
|
|
|
|
else: # affine
|
|
|
|
|
img = cv2.warpAffine(img, M[:2], dsize=(width, height), borderValue=(114, 114, 114))
|
|
|
|
|
|
|
|
|
|
# Visualize
|
|
|
|
|
# import matplotlib.pyplot as plt
|
|
|
|
|
# ax = plt.subplots(1, 2, figsize=(12, 6))[1].ravel()
|
|
|
|
|
# ax[0].imshow(img[:, :, ::-1]) # base
|
|
|
|
|
# ax[1].imshow(img2[:, :, ::-1]) # warped
|
|
|
|
|
|
|
|
|
|
# Transform label coordinates
|
|
|
|
|
n = len(targets)
|
|
|
|
@ -753,7 +771,11 @@ def random_affine(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10,
|
|
|
|
|
# warp points
|
|
|
|
|
xy = np.ones((n * 4, 3))
|
|
|
|
|
xy[:, :2] = targets[:, [1, 2, 3, 4, 1, 4, 3, 2]].reshape(n * 4, 2) # x1y1, x2y2, x1y2, x2y1
|
|
|
|
|
xy = (xy @ M.T)[:, :2].reshape(n, 8)
|
|
|
|
|
xy = xy @ M.T # transform
|
|
|
|
|
if perspective:
|
|
|
|
|
xy = (xy[:, :2] / xy[:, 2:3]).reshape(n, 8) # rescale
|
|
|
|
|
else: # affine
|
|
|
|
|
xy = xy[:, :2].reshape(n, 8)
|
|
|
|
|
|
|
|
|
|
# create new boxes
|
|
|
|
|
x = xy[:, [0, 2, 4, 6]]
|
|
|
|
|