Cutmix

def load_cutmix_image_and_boxes(self, index, imsize=1024):
"""
This implementation of cutmix author: https://www.kaggle.com/nvnnghia
Refactoring and adaptation: https://www.kaggle.com/shonenkov
"""
w, h = imsize, imsize
s = imsize // 2
xc, yc = [int(random.uniform(imsize * 0.25, imsize * 0.75)) for _ in range(2)]
indexes = [index] + [random.randint(0, self.image_ids.shape[0] - 1) for _ in range(3)]
result_image = np.full((imsize, imsize, 3), 1, dtype=np.float32)
result_boxes = []
for i, index in enumerate(indexes):
image, boxes = self.load_image_and_boxes(index)
if i == 0:
x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc
x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h
elif i == 1:
x1a, y1a, x2a, y2a = xc, max(yc - h, 0), min(xc + w, s * 2), yc
x1b, y1b, x2b, y2b = 0, h - (y2a - y1a), min(w, x2a - x1a), h
elif i == 2:
x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h)
x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, max(xc, w), min(y2a - y1a, h)
elif i == 3:
x1a, y1a, x2a, y2a = xc, yc, min(xc + w, s * 2), min(s * 2, yc + h)
x1b, y1b, x2b, y2b = 0, 0, min(w, x2a - x1a), min(y2a - y1a, h)
result_image[y1a:y2a, x1a:x2a] = image[y1b:y2b, x1b:x2b]
padw = x1a - x1b
padh = y1a - y1b
boxes[:, 0] += padw
boxes[:, 1] += padh
boxes[:, 2] += padw
boxes[:, 3] += padh
result_boxes.append(boxes)
result_boxes = np.concatenate(result_boxes, 0)
np.clip(result_boxes[:, 0:], 0, 2 * s, out=result_boxes[:, 0:])
result_boxes = result_boxes.astype(np.int32)
result_boxes = result_boxes[
np.where((result_boxes[:, 2] - result_boxes[:, 0]) * (result_boxes[:, 3] - result_boxes[:, 1]) > 0)]
return result_image, result_boxes
Mixup

def load_mixup_image_and_boxes(self, index):
image, boxes = self.load_image_and_boxes(index)
r_image, r_boxes = self.load_image_and_boxes(random.randint(0, self.image_ids.shape[0] - 1))
return (image+r_image)/2, np.vstack((boxes, r_boxes)).astype(np.int32)
随机旋转n*90°,n∈(0,1,2,3)

class RandomRotate90:
def __init__(self, prob=1.):
self.prob = prob
def __call__(self, img, bbox=None):
w, h = img.shape[:2]
bbox = (bbox[:, 0], bbox[:, 1], bbox[:, 2], bbox[:, 3])
if random.random() < self.prob:
factor = random.randint(0, 3)
img = np.rot90(img, factor)
if bbox is not None:
bbox = self.bbox_rot90(bbox, factor, w)
bbox = np.asarray(bbox).transpose((1, 0))
return img, bbox
def bbox_rot90(self, bbox, factor, shape):
"""Rotates a bounding box by 90 degrees CCW (see np.rot90)
Args:
bbox (tuple): A bounding box tuple (x_min, y_min, x_max, y_max).
factor (int): Number of CCW rotations. Must be in set {0, 1, 2, 3} See np.rot90.
rows (int): Image rows.
cols (int): Image cols.
Returns:
tuple: A bounding box tuple (x_min, y_min, x_max, y_max).
"""
if factor not in {0, 1, 2, 3}:
raise ValueError("Parameter n must be in set {0, 1, 2, 3}")
x_min, y_min, x_max, y_max = bbox[:4]
if factor == 1:
bbox = y_min, shape - x_max, y_max, shape - x_min
elif factor == 2:
bbox = shape - x_max, shape - y_max, shape - x_min, shape - y_min
elif factor == 3:
bbox = shape - y_max, x_min, shape - y_min, x_max
return bbox
随机水平或垂直旋转

class RandomFlip:
def __init__(self, prob=1):
self.prob = prob
def bbox_hflip(self, bbox, shape):
"""Flip a bounding box horizontally around the y-axis.
Args:
bbox (tuple): A bounding box `(x_min, y_min, x_max, y_max)`.
Returns:
tuple: A bounding box `(x_min, y_min, x_max, y_max)`.
"""
x_min, y_min, x_max, y_max = bbox
return shape - x_max, y_min, shape - x_min, y_max
def bbox_vflip(self, bbox, shape):
"""Flip a bounding box vertically around the x-axis.
Args:
bbox (tuple): A bounding box `(x_min, y_min, x_max, y_max)`.
Returns:
tuple: A bounding box `(x_min, y_min, x_max, y_max)`.
"""
x_min, y_min, x_max, y_max = bbox
return x_min, shape - y_max, x_max, shape - y_min
def __call__(self, img, bbox=None):
w, h = img.shape[:2]
bbox = (bbox[:, 0], bbox[:, 1], bbox[:, 2], bbox[:, 3])
if random.random() < self.prob:
d = random.randint(-1, 1)
img = cv2.flip(img, d)
if bbox is not None:
if d == 0:
bbox = self.bbox_vflip(bbox, w)
elif d == 1:
bbox = self.bbox_hflip(bbox, w)
elif d == -1:
bbox = self.bbox_hflip(bbox, w)
bbox = self.bbox_vflip(bbox, w)
else:
raise ValueError("Invalid d value {}. Valid values are -1, 0 and 1".format(d))
bbox = np.asarray(bbox).transpose((1, 0))
return img, bbox
随机擦除

class CoarseDropout:
"""
CoarseDropout of the rectangular regions in the image.
"""
def __init__(self, max_holes=30, max_height=8, max_width=8,
min_holes=5, min_height=4, min_width=4,
fill_value=0, p=1):
self.max_holes = max_holes
self.max_height = max_height
self.max_width = max_width
self.min_holes = min_holes if min_holes is not None else max_holes
self.min_height = min_height if min_height is not None else max_height
self.min_width = min_width if min_width is not None else max_width
self.fill_value = fill_value
self.prob = p
assert 0 < self.min_holes <= self.max_holes
assert 0 < self.min_height <= self.max_height
assert 0 < self.min_width <= self.max_width
def get_params_dependent_on_targets(self, img):
height, width = img.shape[:2]
holes = []
for n in range(random.randint(self.min_holes, self.max_holes + 1)):
hole_height = random.randint(self.min_height, self.max_height + 1)
hole_width = random.randint(self.min_width, self.max_width + 1)
y1 = random.randint(0, height - hole_height)
x1 = random.randint(0, width - hole_width)
y2 = y1 + hole_height
x2 = x1 + hole_width
holes.append((x1, y1, x2, y2))
return holes
def __call__(self, image, box=None):
if random.random() < self.prob:
holes = self.get_params_dependent_on_targets(image)
image = cutout(image, holes, self.fill_value)
return image, box