augmentations.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. # YOLOv5 🚀 by Ultralytics, AGPL-3.0 license
  2. """
  3. Image augmentation functions
  4. """
  5. import math
  6. import random
  7. import cv2
  8. import numpy as np
  9. from ..augmentations import box_candidates
  10. from ..general import resample_segments, segment2box
  11. def mixup(im, labels, segments, im2, labels2, segments2):
  12. # Applies MixUp augmentation https://arxiv.org/pdf/1710.09412.pdf
  13. r = np.random.beta(32.0, 32.0) # mixup ratio, alpha=beta=32.0
  14. im = (im * r + im2 * (1 - r)).astype(np.uint8)
  15. labels = np.concatenate((labels, labels2), 0)
  16. segments = np.concatenate((segments, segments2), 0)
  17. return im, labels, segments
  18. def random_perspective(im,
  19. targets=(),
  20. segments=(),
  21. degrees=10,
  22. translate=.1,
  23. scale=.1,
  24. shear=10,
  25. perspective=0.0,
  26. border=(0, 0)):
  27. # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10))
  28. # targets = [cls, xyxy]
  29. height = im.shape[0] + border[0] * 2 # shape(h,w,c)
  30. width = im.shape[1] + border[1] * 2
  31. # Center
  32. C = np.eye(3)
  33. C[0, 2] = -im.shape[1] / 2 # x translation (pixels)
  34. C[1, 2] = -im.shape[0] / 2 # y translation (pixels)
  35. # Perspective
  36. P = np.eye(3)
  37. P[2, 0] = random.uniform(-perspective, perspective) # x perspective (about y)
  38. P[2, 1] = random.uniform(-perspective, perspective) # y perspective (about x)
  39. # Rotation and Scale
  40. R = np.eye(3)
  41. a = random.uniform(-degrees, degrees)
  42. # a += random.choice([-180, -90, 0, 90]) # add 90deg rotations to small rotations
  43. s = random.uniform(1 - scale, 1 + scale)
  44. # s = 2 ** random.uniform(-scale, scale)
  45. R[:2] = cv2.getRotationMatrix2D(angle=a, center=(0, 0), scale=s)
  46. # Shear
  47. S = np.eye(3)
  48. S[0, 1] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # x shear (deg)
  49. S[1, 0] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # y shear (deg)
  50. # Translation
  51. T = np.eye(3)
  52. T[0, 2] = (random.uniform(0.5 - translate, 0.5 + translate) * width) # x translation (pixels)
  53. T[1, 2] = (random.uniform(0.5 - translate, 0.5 + translate) * height) # y translation (pixels)
  54. # Combined rotation matrix
  55. M = T @ S @ R @ P @ C # order of operations (right to left) is IMPORTANT
  56. if (border[0] != 0) or (border[1] != 0) or (M != np.eye(3)).any(): # image changed
  57. if perspective:
  58. im = cv2.warpPerspective(im, M, dsize=(width, height), borderValue=(114, 114, 114))
  59. else: # affine
  60. im = cv2.warpAffine(im, M[:2], dsize=(width, height), borderValue=(114, 114, 114))
  61. # Visualize
  62. # import matplotlib.pyplot as plt
  63. # ax = plt.subplots(1, 2, figsize=(12, 6))[1].ravel()
  64. # ax[0].imshow(im[:, :, ::-1]) # base
  65. # ax[1].imshow(im2[:, :, ::-1]) # warped
  66. # Transform label coordinates
  67. n = len(targets)
  68. new_segments = []
  69. if n:
  70. new = np.zeros((n, 4))
  71. segments = resample_segments(segments) # upsample
  72. for i, segment in enumerate(segments):
  73. xy = np.ones((len(segment), 3))
  74. xy[:, :2] = segment
  75. xy = xy @ M.T # transform
  76. xy = (xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]) # perspective rescale or affine
  77. # clip
  78. new[i] = segment2box(xy, width, height)
  79. new_segments.append(xy)
  80. # filter candidates
  81. i = box_candidates(box1=targets[:, 1:5].T * s, box2=new.T, area_thr=0.01)
  82. targets = targets[i]
  83. targets[:, 1:5] = new[i]
  84. new_segments = np.array(new_segments)[i]
  85. return im, targets, new_segments