首页 > 其他分享 >数据增强mosaic实现

数据增强mosaic实现

时间:2024-07-02 09:52:34浏览次数:17  
标签:增强 xc x1a self y1a x2a y2a 数据 mosaic

image

mosaic 是yolov4中提出的一个数据增强的方式,通过将4张图片拼接在一起送入训练,有效提升了模型的map。mosaic的优点包括如下:

  1. 增加数据多样性,随机选取四张图像进行组合,组合得到图像个数比原图个数要多。
  2. 增强模型鲁棒性,混合四张具有不同语义信息的图片,可以让模型检测超出常规语境的目标。
  3. 加强批归一化层(Batch Normalization)的效果。当模型设置 BN 操作后,训练时会尽可能增大批样本总量(BatchSize),因为 BN 原理为计算每一个特征层的均值和方差,如果批样本总量越大,那么 BN 计算的均值和方差就越接近于整个数据集的均值和方差,效果越好。
  4. Mosaic 数据增强算法有利于提升小目标检测性能。Mosaic 数据增强图像由四张原始图像拼接而成,这样每张图像会有更大概率包含小目标。
  5. 训练的难度增大,有助于模型性能的提

本篇分析mosaic的实现方式。

代码分析

    def load_mosaic(self, index):
        # YOLOv5 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic
        labels4, segments4 = [], []
        s = self.img_size
        yc, xc = (int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border)  # mosaic center x, y
        indices = [index] + random.choices(self.indices, k=3)  # 3 additional image indices
        random.shuffle(indices)
  
        for i, index in enumerate(indices):
            # Load image
            img, _, (h, w) = self.load_image(index)

            # place img in img4
            if i == 0:  # top left
                img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8)  # base image with 4 tiles
                x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc  # xmin, ymin, xmax, ymax (large image)
                x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h  # xmin, ymin, xmax, ymax (small image)
            elif i == 1:  # top right
                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:  # bottom left
                x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h)
                x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, w, min(y2a - y1a, h)
            elif i == 3:  # bottom right
                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)

            img4[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b]  # img4[ymin:ymax, xmin:xmax]
            padw = x1a - x1b
            padh = y1a - y1b

            # Labels
            labels, segments = self.labels[index].copy(), self.segments[index].copy()
            if labels.size:
                labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padw, padh)  # normalized xywh to pixel xyxy format
                segments = [xyn2xy(x, w, h, padw, padh) for x in segments]
            labels4.append(labels)
            segments4.extend(segments)

        # Concat/clip labels
        labels4 = np.concatenate(labels4, 0)
        for x in (labels4[:, 1:], *segments4):
            np.clip(x, 0, 2 * s, out=x)  # clip when using random_perspective()
        # img4, labels4 = replicate(img4, labels4)  # replicate

        # Augment
        img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp['copy_paste'])
        img4, labels4 = random_perspective(img4,
                                           labels4,
                                           segments4,
                                           degrees=self.hyp['degrees'],
                                           translate=self.hyp['translate'],
                                           scale=self.hyp['scale'],
                                           shear=self.hyp['shear'],
                                           perspective=self.hyp['perspective'],
                                           border=self.mosaic_border)  # border to remove

        return img4, labels4

马赛克之后的结果如下:

mosaic 的过程可以分为如下几步:

  1. 确定四张图片的中心点
  2. 计算上下左右四张图片的左上右下坐标点
  3. 图片上的标注框做相应的转换
  4. 裁剪标注框多余部分

确定四张图片的中心点

马赛克的第一步就是选择一个中心点,以中心点为基准放置4张图片。中心点选择不是随便的,需要一个范围能够马赛克之后的效果可控。

labels4, segments4 = [], []
s = self.img_size
yc, xc = (int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border)  # mosaic center x, y

其中 self.mosaic_border = [-img_size // 2, -img_size // 2],所以 self.mosaic_border = [320, 320]
s = 640,所以 random.uniform(320, 960) 就是用320到960之间选择四张图片的中心点。

计算四张图片的左上右下坐标点

确定了中心点之后就可以将四张图片分别放置在上左,上右,下左,下右四个位置上。

indices = [index] + random.choices(self.indices, k=3)  # 3 additional image indices
random.shuffle(indices)
for i, index in enumerate(indices):
    # Load image
    img, _, (h, w) = self.load_image(index)

    # place img in img4
    if i == 0:  # top left
        img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8)  # base image with 4 tiles
        x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc  # xmin, ymin, xmax, ymax (large image)
        x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h  # xmin, ymin, xmax, ymax (small image)
    elif i == 1:  # top right
        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:  # bottom left
        x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h)
        x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, w, min(y2a - y1a, h)
    elif i == 3:  # bottom right
        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)

    img4[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b]  # img4[ymin:ymax, xmin:xmax]

从剩余的图片中随机抽取三张,包括当前这一张一共四张,打乱顺序。遍历四张图片,分别处理。首先处理上左。

img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8)

首先建立一张空画布,长宽都是两张图片的长宽,1280 * 1280,空白画布如下:

然后画布中上左图片的位置。x1a, y1a是图片在画布中左上角的坐标,x2a, y2a是右下角的坐标。

 x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc  # xmin, ymin, xmax, ymax (large image)

x2a, y2a 可以想象就是中心点,也就是xc, yc。x1a 等于中心点横坐标减去图片宽,y1a等于中心点纵坐标减去图片高。可能会出现中心坐标比较靠左,图片超过画布的情况,x1a,y1a会变成一个负值,所以需要判断,当x1a,y1a变成一个负值时,要等于0。
可能存在的如下两种情况:

x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h

当出现第二种情况时,就需要先裁剪图片再填充到画布中,所以还需要计算出图片裁剪的坐标。
x1b,y1b是裁剪的左上角坐标, x2b, y2b是裁剪的右下角坐标。当然,如果图片没有超出画布,这两个值就刚好等于图片的全部大小。

img4[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b]

最后将图片裁剪之后的像素拷贝到画布中。
剩余三个照片也是同理粘贴。

图片上的标注框做相应的转换

将图片放置在画布上之后,标注框也要放置在画布上。由于图片放在画布上会让标注框产生偏移,所以需要将这些偏移量加到标注框上。

padw = x1a - x1b
padh = y1a - y1b

# Labels
labels, segments = self.labels[index].copy(), self.segments[index].copy()
if labels.size:
    labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padw, padh)  # normalized xywh to pixel xyxy format
    segments = [xyn2xy(x, w, h, padw, padh) for x in segments]
labels4.append(labels)
segments4.extend(segments)

假设画布中心点就是正方形中心,那么左上角的图片则刚贴合。标注框相当于图片的左上角而言,现在图片和画布上左完全重合,就不需要处理。但是通常画布的中心点不会那么正,相对于中心点有偏移。图片相对于画布的左上角也有偏移,那么标注框也得加上对应的偏移才能回到图片上的位置。
偏移量的计算如下:
padw = x1a - x1b
padh = y1a - y

在xywhn2xyxy中将xywh格式的标注框转换成xyxy格式,同时加上对应的偏移量。让标注框从以原图为坐标系变成以画布为坐标系。

def xywhn2xyxy(x, w=640, h=640, padw=0, padh=0):
    # Convert nx4 boxes from [x, y, w, h] normalized to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right
    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)
    y[:, 0] = w * (x[:, 0] - x[:, 2] / 2) + padw  # top left x
    y[:, 1] = h * (x[:, 1] - x[:, 3] / 2) + padh  # top left y
    y[:, 2] = w * (x[:, 0] + x[:, 2] / 2) + padw  # bottom right x
    y[:, 3] = h * (x[:, 1] + x[:, 3] / 2) + padh  # bottom right y
    return y

同理上右也是如此:

裁剪标注框多余部分

将标注框超出画布的部分裁剪掉,下图的蓝框所在区域。

# Concat/clip labels
labels4 = np.concatenate(labels4, 0)
for x in (labels4[:, 1:], *segments4):
    np.clip(x, 0, 2 * s, out=x)  # clip when using random_perspective()

np.clip 用于将数组中的元素限制在指定的范围内。如果元素的值低于给定的最小值,则会被设置为该最小值;如果元素的值高于给定的最大值,则会被设置为该最大值。

In [22]: arr = np.array([-1, 0.5, 1.5, 2, 3])
In [23]: arr
Out[23]: array([-1. ,  0.5,  1.5,  2. ,  3. ])

In [24]: np.clip(arr, 0, 2)
Out[24]: array([0. , 0.5, 1.5, 2. , 2. ])

使用np.clip函数将标签超出的部分都裁剪掉。

将标注框显示在图片中的效果如下。

标签:增强,xc,x1a,self,y1a,x2a,y2a,数据,mosaic
From: https://www.cnblogs.com/goldsunshine/p/18279312

相关文章

  • KES数据库实践指南:探索KES数据库的事务隔离级别
    引言前两篇文章我们详细讲解了如何安装KES金仓数据库,并提供了快速查询和搭建基于coze平台的智能体的解决方案。今天,我们的焦点将放在并发控制机制和事务隔离级别上。本文将通过一系列实验操作,深入探讨KES数据库中的并发控制机制和事务隔离级别。我们将通过实际操作演示,帮助读者......
  • 大型能源电力集团需要什么样的总部数据下发系统?
    能源电力集团的组织结构是一个复杂的系统,包括多个职能部门和子分公司。这些子分公司负责具体的电力生产、销售、运维等业务。这些部门和公司协同工作,确保电力生产的顺利进行,同时关注公司的长期发展、市场拓展、人力资源管理、财务管理和公司治理等方面。由于大型能源电力集团在......
  • R语言数据分析案例38-高等教育学生成绩分析(多元线性回归)
    一、研究背景学生成绩是衡量教育质量的重要指标,同时也是教育工作者进行教学反思和改进的重要依据。随着现代教育的不断发展,各类学科课程的设置日益多样化,学生的学习表现也呈现出复杂多样的特征。为了深入了解学生在各门课程中的表现,找出影响学生成绩的关键因素,有必要对学生成......
  • 达梦数据库迁移常见语法问题
    数据库迁移常见语法问题DM数据库常见语法差异一.Sql文语法1.杀进程语法select*fromv$lock;select*fromsysobjects;--(查询对象信息)select*fromv$sessions;--(查询会话信息)--上述3条语句组合一下就能查出哪张表上的某种锁是由哪个会话里的操作加上的--查哪张表上......
  • camunda数据库表结构详细说明
    本文基于Camunda7.19.0版本,介绍Camunda开源工作流引擎的数据库架构和ER模型,Camunda7.19.0共49张表,包括了BPMN流程引擎、DMN规则引擎、CMMN引擎、历史数据、用户身份等方面的表结构定义,以及表与表之间的关联关系。1、camunda数据库结构综述Camunda流程引擎的数据库架构由多个表组......
  • [AIGC] 常用的OLAP数据库:为数据分析提供强大的支持
    导语:在大数据时代,数据分析成为了企业决策的重要依据。为了高效地处理和分析海量的数据,OLAP数据库应运而生。本文将介绍几种常用的OLAP数据库,为数据分析提供强大的支持。一、SnowflakeSnowflake是一种云原生的OLAP数据库,以其强大的数据处理能力和灵活的架构而闻名。它具有......
  • 【分布式数据仓库Hive】Hive的安装配置及测试
    目录一、数据库MySQL安装1.检查操作系统是否有MySQL安装残留2.删除残留的MySQL安装(使用yum)3.安装MySQL依赖包、客户端和服务器4.MySQL登录账户root设置密码,密码值自定义,这里是‘abc1234’5.启动MySQL服务6.登录MySQL,进入数据库操作提示符7.授权Hive远程登录账户......
  • Python毕业设计-基于Python实现的深圳链家租房可视化系统源码+文档说明+条形图+数据库
    文章目录源码下载地址项目介绍项目功能界面预览项目备注源码下载地址源码下载地址点击这里下载代码项目介绍项目历经数据采集->数据展示->数据分析->数据预测lianjia_1:scrapy爬虫项目lianjia_show:flask对采集的数据进行展示链家房价预测:采集的数据进行分析......
  • 基于Python网络爬虫的二手房数据采集及可视化分析项目源码+使用教程+爬虫+报告PPT+详
    文章目录源码下载地址项目介绍项目功能界面预览项目备注源码下载地址源码下载地址点击这里下载代码项目介绍基于Python的南京二手房数据采集及可视化分析1内容简介首先通过爬虫采集链家网上所有南京二手房的房源数据,并对采集到的数据进行清洗;然后,对清洗后的数......
  • 金仓数据库
    文章目录开启列名大写开启列名大写在jdbc连接中指定的连接参数,开启列名大写jdbc:kingbase8://[ip]:[port]/[database]?initParams=enable_upper_colname=oninitParams参数说明:指定用来初始化数据库连接的session级参数,可指定多个,各个参数之间用分号进行分隔,如in......