YOLOV4用到的一些tricks以及代码实现(1)——CutMix and Mosaic data augmentation

YOLOV4用掉的一些tricks以及代码实现(1)——CutMix and Mosaic data augmentation

之前的几篇博客将YOLOV4整个流程都过了一边,其中把重心放在相关的语法中,从这篇博客开始,我将YOLOV4中提到的一些tricks逐一进行介绍并用代码实现。首先看下论文提到了哪些tricks:

Bag of Freebies(BoF)  指那些能够提高精度而不增加推断时间的技术。比如数据增广的方法图像几何变换、CutOut、grid mask等,网络正则化的方法DropOut、DropBlock等,类别不平衡的处理方法、难例挖掘方法、损失函数的设计等。

Bag  of Specials (BoS)是指那些增加稍许推断代价,但可以提高模型精度的方法,比如增大模型感受野的SPP、ASPP、RFB等,引入注意力机制Squeeze-and-Excitation (SE) 、Spatial Attention Module (SAM)等 ,特征集成方法SFAM , ASFF , BiFPN等,改进的激活函数Swish、Mish等,或者是后处理方法如soft NMS、DIoU NMS等。

本篇博客主要介绍:CutMix and Mosaic data augmentation

代码来源:https://github.com/jason9075/opencv-mosaic-data-aug

示例代码利用opencv展示Mosaic data augmentation算法

原理:


Yolov4的mosaic数据增强参考了CutMix数据增强方式,理论上具有一定的相似性!
CutMix数据增强方式利用两张图片进行拼接。

但是mosaic利用了四张图片这样在BN计算的时候一下子会计算四张图片的数据!
实现思路
1、每次读取四张图片。

2、分别对四张图片进行翻转、缩放、色域变化等,并且按照四个方向位置摆好。

3、进行图片的组合和框的组合。

 

通过查看实现思路,其实发现整体思路并不复杂,真正复杂的实在代码实现上,包括坐标转换,标签转换等。

本次示例中,利用opencv仅仅用于图像展示,算法原理与yoloV4中data augment 一模一样。

按照笔者一贯思路,逐一对代码进行分析后,解答上诉问题:

def get_dataset(anno_dir, img_dir):

首先通过dataset获取标签数据和图像数据。
 

for anno_file in glob.glob(os.path.join(anno_dir, '*.txt'))

遍历anno_dir中的数据,这其中牵扯到glob语法。glob模块是最简单的模块之一,内容非常少。用它可以查找符合特定规则的文件路径名。跟使用windows下的文件搜索差不多。查找文件只用到三个匹配符:””, “?”, “[]”。””匹配0个或多个字符;”?”匹配单个字符;”[]”匹配指定范围内的字符,如:[0-9]匹配数字。

在这里就是查找以“txt"结尾的文件,返回的是文件路径。

xmin = max(obj[1], 0) / img_width
ymin = max(obj[2], 0) / img_height
xmax = min(obj[3], img_width) / img_width
ymax = min(obj[4], img_height) / img_height

获取到标注信息的位置后进行归一化。

idxs = random.sample(range(len(annos)), 4)

random.sample()可以从指定的序列中,随机的截取指定长度的片断,不作原地修改。在这里用于随机选取图片。

def update_image_and_anno(all_img_list, all_annos, idxs, output_size, scale_range, filter_scale=0.)

该函数用于修改图像和标签,既实现mosaic数据增强。

scale_x = scale_range[0] + random.random() * (scale_range[1] - scale_range[0])
scale_y = scale_range[0] + random.random() * (scale_range[1] - scale_range[0])
divid_point_x = int(scale_x * output_size[1])
divid_point_y = int(scale_y * output_size[0])

利用random获取长和宽。注:生成的是0-1之间的浮点数。

for i, idx in enumerate(idxs)

根据之前产生的随机数获取数据,注:for遍历enumerate时,返回第一个值是index,第二个值是相对位置的数据。如:

date = [2,4,6,8,10]
for index, item in enumerate(date):
    print("index=%d ,item=%d" %(index,item))

for i in enumerate(date):
    print(i)

#结果:
index=0 ,item=2
index=1 ,item=4
index=2 ,item=6
index=3 ,item=8
index=4 ,item=10
(0, 2)
(1, 4)
(2, 6)
(3, 8)
(4, 10)

 

遍历随机选择出来的四张图后,更改图像尺寸:

        img = cv2.imread(path)
        if i == 0:  # top-left
            img = cv2.resize(img, (divid_point_x, divid_point_y))
            output_img[:divid_point_y, :divid_point_x, :] = img
            for bbox in img_annos:
                xmin = bbox[1] * scale_x
                ymin = bbox[2] * scale_y
                xmax = bbox[3] * scale_x
                ymax = bbox[4] * scale_y
                new_anno.append([bbox[0], xmin, ymin, xmax, ymax])

分别遍历四个角的图片并修改图像尺寸和标签,步骤如下:

1.根据随机生成的divid_point_x,divid_point_y,将图像随机resize后,放入左上角的位置。

2.根据scale_x,scale_y修改标签的缩放比,注意:一张图片可能有多个标签,故这里用了for bbox in img_annos。

3.选取另一个位置,重复上两步。

new_anno = [anno for anno in new_anno if filter_scale < (anno[3] - anno[1]) and filter_scale < (anno[4] - anno[2])]

通过filter_scale设定阈值,去除修改后标签尺寸过小的图片。

    for anno in new_annos:
        start_point = (int(anno[1] * OUTPUT_SIZE[1]), int(anno[2] * OUTPUT_SIZE[0]))
        end_point = (int(anno[3] * OUTPUT_SIZE[1]), int(anno[4] * OUTPUT_SIZE[0]))
        cv2.rectangle(new_image, start_point, end_point, (0, 255, 0), 1, cv2.LINE_AA)
    cv2.imwrite('img/output_box.jpg', new_image)

最后利用opencv将方框画出来。

 

Mosaic数据增强方法借用opencv实现并不复杂,唯一需要注意的就是random的用法和filter_scale设定进行筛选,没什么特语法难度。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值