|
|
|
@ -44,20 +44,8 @@ class Compose: |
|
|
|
|
self.transforms = transforms |
|
|
|
|
|
|
|
|
|
def __call__(self, data): |
|
|
|
|
mosaic_p = None |
|
|
|
|
mosaic_imgsz = None |
|
|
|
|
|
|
|
|
|
for t in self.transforms: |
|
|
|
|
if isinstance(t, Mosaic): |
|
|
|
|
temp = t(data) |
|
|
|
|
mosaic_p = False if temp == data else True |
|
|
|
|
mosaic_imgsz = t.imgsz |
|
|
|
|
data = temp |
|
|
|
|
else: |
|
|
|
|
if isinstance(t, RandomPerspective): |
|
|
|
|
t.border = [-mosaic_imgsz // 2, -mosaic_imgsz // 2] if mosaic_p else [0, 0] |
|
|
|
|
data = t(data) |
|
|
|
|
|
|
|
|
|
data = t(data) |
|
|
|
|
return data |
|
|
|
|
|
|
|
|
|
def append(self, transform): |
|
|
|
@ -140,7 +128,7 @@ class Mosaic(BaseMixTransform): |
|
|
|
|
labels_patch = (labels if i == 0 else labels["mix_labels"][i - 1]).copy() |
|
|
|
|
# Load image |
|
|
|
|
img = labels_patch["img"] |
|
|
|
|
h, w = labels_patch["resized_shape"] |
|
|
|
|
h, w = labels_patch.pop("resized_shape") |
|
|
|
|
|
|
|
|
|
# place img in img4 |
|
|
|
|
if i == 0: # top left |
|
|
|
@ -184,11 +172,12 @@ class Mosaic(BaseMixTransform): |
|
|
|
|
cls.append(labels["cls"]) |
|
|
|
|
instances.append(labels["instances"]) |
|
|
|
|
final_labels = { |
|
|
|
|
"im_file": mosaic_labels[0]["im_file"], |
|
|
|
|
"ori_shape": mosaic_labels[0]["ori_shape"], |
|
|
|
|
"resized_shape": (self.imgsz * 2, self.imgsz * 2), |
|
|
|
|
"im_file": mosaic_labels[0]["im_file"], |
|
|
|
|
"cls": np.concatenate(cls, 0), |
|
|
|
|
"instances": Instances.concatenate(instances, axis=0)} |
|
|
|
|
"instances": Instances.concatenate(instances, axis=0), |
|
|
|
|
"mosaic_border": self.border} |
|
|
|
|
final_labels["instances"].clip(self.imgsz * 2, self.imgsz * 2) |
|
|
|
|
return final_labels |
|
|
|
|
|
|
|
|
@ -213,7 +202,14 @@ class MixUp(BaseMixTransform): |
|
|
|
|
|
|
|
|
|
class RandomPerspective: |
|
|
|
|
|
|
|
|
|
def __init__(self, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, border=(0, 0)): |
|
|
|
|
def __init__(self, |
|
|
|
|
degrees=0.0, |
|
|
|
|
translate=0.1, |
|
|
|
|
scale=0.5, |
|
|
|
|
shear=0.0, |
|
|
|
|
perspective=0.0, |
|
|
|
|
border=(0, 0), |
|
|
|
|
pre_transform=None): |
|
|
|
|
self.degrees = degrees |
|
|
|
|
self.translate = translate |
|
|
|
|
self.scale = scale |
|
|
|
@ -221,8 +217,9 @@ class RandomPerspective: |
|
|
|
|
self.perspective = perspective |
|
|
|
|
# mosaic border |
|
|
|
|
self.border = border |
|
|
|
|
self.pre_transform = pre_transform |
|
|
|
|
|
|
|
|
|
def affine_transform(self, img): |
|
|
|
|
def affine_transform(self, img, border): |
|
|
|
|
# Center |
|
|
|
|
C = np.eye(3) |
|
|
|
|
|
|
|
|
@ -255,7 +252,7 @@ class RandomPerspective: |
|
|
|
|
# Combined rotation matrix |
|
|
|
|
M = T @ S @ R @ P @ C # order of operations (right to left) is IMPORTANT |
|
|
|
|
# affine image |
|
|
|
|
if (self.border[0] != 0) or (self.border[1] != 0) or (M != np.eye(3)).any(): # image changed |
|
|
|
|
if (border[0] != 0) or (border[1] != 0) or (M != np.eye(3)).any(): # image changed |
|
|
|
|
if self.perspective: |
|
|
|
|
img = cv2.warpPerspective(img, M, dsize=self.size, borderValue=(114, 114, 114)) |
|
|
|
|
else: # affine |
|
|
|
@ -341,6 +338,10 @@ class RandomPerspective: |
|
|
|
|
Args: |
|
|
|
|
labels(Dict): a dict of `bboxes`, `segments`, `keypoints`. |
|
|
|
|
""" |
|
|
|
|
if self.pre_transform and "mosaic_border" not in labels: |
|
|
|
|
labels = self.pre_transform(labels) |
|
|
|
|
labels.pop("ratio_pad") # do not need ratio pad |
|
|
|
|
|
|
|
|
|
img = labels["img"] |
|
|
|
|
cls = labels["cls"] |
|
|
|
|
instances = labels.pop("instances") |
|
|
|
@ -348,10 +349,11 @@ class RandomPerspective: |
|
|
|
|
instances.convert_bbox(format="xyxy") |
|
|
|
|
instances.denormalize(*img.shape[:2][::-1]) |
|
|
|
|
|
|
|
|
|
self.size = img.shape[1] + self.border[1] * 2, img.shape[0] + self.border[0] * 2 # w, h |
|
|
|
|
border = labels.pop("mosaic_border", self.border) |
|
|
|
|
self.size = img.shape[1] + border[1] * 2, img.shape[0] + border[0] * 2 # w, h |
|
|
|
|
# M is affine matrix |
|
|
|
|
# scale for func:`box_candidates` |
|
|
|
|
img, M, scale = self.affine_transform(img) |
|
|
|
|
img, M, scale = self.affine_transform(img, border) |
|
|
|
|
|
|
|
|
|
bboxes = self.apply_bboxes(instances.bboxes, M) |
|
|
|
|
|
|
|
|
@ -513,8 +515,10 @@ class CopyPaste: |
|
|
|
|
# Implement Copy-Paste augmentation https://arxiv.org/abs/2012.07177, labels as nx5 np.array(cls, xyxy) |
|
|
|
|
im = labels["img"] |
|
|
|
|
cls = labels["cls"] |
|
|
|
|
h, w = im.shape[:2] |
|
|
|
|
instances = labels.pop("instances") |
|
|
|
|
instances.convert_bbox(format="xyxy") |
|
|
|
|
instances.denormalize(w, h) |
|
|
|
|
if self.p and len(instances.segments): |
|
|
|
|
n = len(instances) |
|
|
|
|
_, w, _ = im.shape # height, width, channels |
|
|
|
@ -605,7 +609,7 @@ class Format: |
|
|
|
|
self.batch_idx = batch_idx # keep the batch indexes |
|
|
|
|
|
|
|
|
|
def __call__(self, labels): |
|
|
|
|
img = labels["img"] |
|
|
|
|
img = labels.pop("img") |
|
|
|
|
h, w = img.shape[:2] |
|
|
|
|
cls = labels.pop("cls") |
|
|
|
|
instances = labels.pop("instances") |
|
|
|
@ -654,7 +658,7 @@ class Format: |
|
|
|
|
return masks, instances, cls |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def mosaic_transforms(dataset, imgsz, hyp): |
|
|
|
|
def v8_transforms(dataset, imgsz, hyp): |
|
|
|
|
pre_transform = Compose([ |
|
|
|
|
Mosaic(dataset, imgsz=imgsz, p=hyp.mosaic, border=[-imgsz // 2, -imgsz // 2]), |
|
|
|
|
CopyPaste(p=hyp.copy_paste), |
|
|
|
@ -664,7 +668,7 @@ def mosaic_transforms(dataset, imgsz, hyp): |
|
|
|
|
scale=hyp.scale, |
|
|
|
|
shear=hyp.shear, |
|
|
|
|
perspective=hyp.perspective, |
|
|
|
|
border=[-imgsz // 2, -imgsz // 2], |
|
|
|
|
pre_transform=LetterBox(new_shape=(imgsz, imgsz)), |
|
|
|
|
),]) |
|
|
|
|
return Compose([ |
|
|
|
|
pre_transform, |
|
|
|
@ -675,23 +679,6 @@ def mosaic_transforms(dataset, imgsz, hyp): |
|
|
|
|
RandomFlip(direction="horizontal", p=hyp.fliplr),]) # transforms |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def affine_transforms(imgsz, hyp): |
|
|
|
|
return Compose([ |
|
|
|
|
LetterBox(new_shape=(imgsz, imgsz)), |
|
|
|
|
RandomPerspective( |
|
|
|
|
degrees=hyp.degrees, |
|
|
|
|
translate=hyp.translate, |
|
|
|
|
scale=hyp.scale, |
|
|
|
|
shear=hyp.shear, |
|
|
|
|
perspective=hyp.perspective, |
|
|
|
|
border=[0, 0], |
|
|
|
|
), |
|
|
|
|
Albumentations(p=1.0), |
|
|
|
|
RandomHSV(hgain=hyp.hsv_h, sgain=hyp.hsv_s, vgain=hyp.hsv_v), |
|
|
|
|
RandomFlip(direction="vertical", p=hyp.flipud), |
|
|
|
|
RandomFlip(direction="horizontal", p=hyp.fliplr),]) # transforms |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Classification augmentations ----------------------------------------------------------------------------------------- |
|
|
|
|
def classify_transforms(size=224): |
|
|
|
|
# Transforms to apply if albumentations not installed |
|
|
|
|