|
import math |
|
import random |
|
|
|
import cv2 |
|
import numpy as np |
|
|
|
from ..augmentations import box_candidates |
|
from ..general import resample_segments, segment2box |
|
from ..metrics import bbox_ioa |
|
|
|
|
|
def mixup(im, labels, segments, seg_cls, semantic_masks, im2, labels2, segments2, seg_cls2, semantic_masks2): |
|
|
|
r = np.random.beta(32.0, 32.0) |
|
im = (im * r + im2 * (1 - r)).astype(np.uint8) |
|
labels = np.concatenate((labels, labels2), 0) |
|
segments = np.concatenate((segments, segments2), 0) |
|
seg_cls = np.concatenate((seg_cls, seg_cls2), 0) |
|
semantic_masks = np.concatenate((semantic_masks, semantic_masks2), 0) |
|
return im, labels, segments, seg_cls, semantic_masks |
|
|
|
|
|
def random_perspective(im, |
|
targets=(), |
|
segments=(), |
|
semantic_masks = (), |
|
degrees=10, |
|
translate=.1, |
|
scale=.1, |
|
shear=10, |
|
perspective=0.0, |
|
border=(0, 0)): |
|
|
|
|
|
|
|
height = im.shape[0] + border[0] * 2 |
|
width = im.shape[1] + border[1] * 2 |
|
|
|
|
|
C = np.eye(3) |
|
C[0, 2] = -im.shape[1] / 2 |
|
C[1, 2] = -im.shape[0] / 2 |
|
|
|
|
|
P = np.eye(3) |
|
P[2, 0] = random.uniform(-perspective, perspective) |
|
P[2, 1] = random.uniform(-perspective, perspective) |
|
|
|
|
|
R = np.eye(3) |
|
a = random.uniform(-degrees, degrees) |
|
|
|
s = random.uniform(1 - scale, 1 + scale) |
|
|
|
R[:2] = cv2.getRotationMatrix2D(angle=a, center=(0, 0), scale=s) |
|
|
|
|
|
S = np.eye(3) |
|
S[0, 1] = math.tan(random.uniform(-shear, shear) * math.pi / 180) |
|
S[1, 0] = math.tan(random.uniform(-shear, shear) * math.pi / 180) |
|
|
|
|
|
T = np.eye(3) |
|
T[0, 2] = (random.uniform(0.5 - translate, 0.5 + translate) * width) |
|
T[1, 2] = (random.uniform(0.5 - translate, 0.5 + translate) * height) |
|
|
|
|
|
M = T @ S @ R @ P @ C |
|
if (border[0] != 0) or (border[1] != 0) or (M != np.eye(3)).any(): |
|
if perspective: |
|
im = cv2.warpPerspective(im, M, dsize=(width, height), borderValue=(114, 114, 114)) |
|
else: |
|
im = cv2.warpAffine(im, M[:2], dsize=(width, height), borderValue=(114, 114, 114)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
n = len(targets) |
|
new_segments = [] |
|
new_semantic_masks = [] |
|
if n: |
|
new = np.zeros((n, 4)) |
|
segments = resample_segments(segments) |
|
for i, segment in enumerate(segments): |
|
xy = np.ones((len(segment), 3)) |
|
xy[:, :2] = segment |
|
xy = xy @ M.T |
|
xy = (xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]) |
|
|
|
|
|
new[i] = segment2box(xy, width, height) |
|
new_segments.append(xy) |
|
|
|
semantic_masks = resample_segments(semantic_masks) |
|
for i, semantic_mask in enumerate(semantic_masks): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
xy_s = np.ones((len(semantic_mask), 3)) |
|
xy_s[:, :2] = semantic_mask |
|
xy_s = xy_s @ M.T |
|
xy_s = (xy_s[:, :2] / xy_s[:, 2:3] if perspective else xy_s[:, :2]) |
|
|
|
new_semantic_masks.append(xy_s) |
|
|
|
|
|
i = box_candidates(box1=targets[:, 1:5].T * s, box2=new.T, area_thr=0.01) |
|
targets = targets[i] |
|
targets[:, 1:5] = new[i] |
|
new_segments = np.array(new_segments)[i] |
|
new_semantic_masks = np.array(new_semantic_masks) |
|
|
|
return im, targets, new_segments, new_semantic_masks |
|
|
|
|
|
def letterbox(im, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32): |
|
|
|
shape = im.shape[:2] |
|
if isinstance(new_shape, int): |
|
new_shape = (new_shape, new_shape) |
|
|
|
|
|
r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) |
|
if not scaleup: |
|
r = min(r, 1.0) |
|
|
|
|
|
ratio = r, r |
|
new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) |
|
dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] |
|
if auto: |
|
dw, dh = np.mod(dw, stride), np.mod(dh, stride) |
|
elif scaleFill: |
|
dw, dh = 0.0, 0.0 |
|
new_unpad = (new_shape[1], new_shape[0]) |
|
ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] |
|
|
|
dw /= 2 |
|
dh /= 2 |
|
|
|
if shape[::-1] != new_unpad: |
|
im = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR) |
|
top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) |
|
left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) |
|
im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) |
|
return im, ratio, (dw, dh) |
|
|
|
|
|
def copy_paste(im, labels, segments, seg_cls, semantic_masks, p=0.5): |
|
|
|
n = len(segments) |
|
if p and n: |
|
h, w, _ = im.shape |
|
im_new = np.zeros(im.shape, np.uint8) |
|
|
|
|
|
boxes = np.stack([w - labels[:, 3], labels[:, 2], w - labels[:, 1], labels[:, 4]], axis=-1) |
|
ioa = bbox_ioa(boxes, labels[:, 1:5]) |
|
indexes = np.nonzero((ioa < 0.30).all(1))[0] |
|
n = len(indexes) |
|
for j in random.sample(list(indexes), k=round(p * n)): |
|
l, box, s = labels[j], boxes[j], segments[j] |
|
labels = np.concatenate((labels, [[l[0], *box]]), 0) |
|
segments.append(np.concatenate((w - s[:, 0:1], s[:, 1:2]), 1)) |
|
seg_cls.append(l[0].astype(int)) |
|
semantic_masks.append(np.concatenate((w - s[:, 0:1], s[:, 1:2]), 1)) |
|
cv2.drawContours(im_new, [segments[j].astype(np.int32)], -1, (1, 1, 1), cv2.FILLED) |
|
|
|
result = cv2.flip(im, 1) |
|
i = cv2.flip(im_new, 1).astype(bool) |
|
im[i] = result[i] |
|
|
|
return im, labels, segments, seg_cls, semantic_masks |