1. Copy-Paste数据增强简介
(1)随机选择2张图片,并应用随机缩放抖动和随机水平翻转;
(2)从其中1张图片中随机选择1个物体子集,并将它们粘贴到另一张图片上;
(3)相应地调整GT:移除完全遮挡的对象,并更新部分遮挡目标对象的Mask和Box。
2. 代码及详解
Yolov8中的CopyPaste有所不同,在一个图像进行。求左右翻转后图像的目标与原图像目标 ioa(inter_area(交叉面积) / box2_area(翻转前真实框面积)) 的值,将 ioa 的值小于 0.3 的目标复制到原图上。
class CopyPaste:
def __init__(self, p=0.5) -> None:
self.p = p
def __call__(self, labels):
# 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
# 生成一个与原图一样全0的图像
im_new = np.zeros(im.shape, np.uint8)
# calculate ioa first then select indexes randomly
# 将原图进行深拷贝,然后将其真实框,分割点,关键点信息进行左右翻转
ins_flip = deepcopy(instances)
ins_flip.fliplr(w)
# 计算翻转后真实框与翻转前真实框的ioa = inter_area / box2_area(翻转前真实框面积)
ioa = bbox_ioa(ins_flip.bboxes, instances.bboxes) # intersection over area, (N, M)
# 如果翻转后的真实框与翻转前 全部的真实框 ioa<0.3 就保留
indexes = np.nonzero((ioa < 0.30).all(1))[0] # (N, )
# 保留下来翻转后真实框的个数
n = len(indexes)
# 随机选取保留下翻转后的真实框
for j in random.sample(list(indexes), k=round(self.p * n)):
# 将分类信息添加到原图分类信息中
cls = np.concatenate((cls, cls[[j]]), axis=0)
# 将其他信息(分割,关键点等)添加到原图其他信息中
instances = Instances.concatenate((instances, ins_flip[[j]]), axis=0)
# 将分割出来的图像放到生成的全0图象上
cv2.drawContours(im_new, instances.segments[[j]].astype(np.int32), -1, (1, 1, 1), cv2.FILLED)
# 将原图进行翻转
result = cv2.flip(im, 1) # augment segments (flip left-right)
# 将处理后的全0图象翻转
i = cv2.flip(im_new, 1).astype(bool)
# 将分割出来的图像放到原图上
im[i] = result[i] # cv2.imwrite('debug.jpg', im) # debug
labels["img"] = im
labels["cls"] = cls
labels["instances"] = instances
return labels