首页 > 编程语言 >python实现Moaic数据增强

python实现Moaic数据增强

时间:2023-08-04 22:36:52浏览次数:43  
标签:Moaic 增强 python random xy im perspective np mosaic

数据增强 python实现Moaic数据增强 python实现Moaic数据增强

Moaic数据增强:对四张图片进行拼接,获得一张新的图片,同时获得这张图片对应的标签框。

主要原理:把4张图片,通过随机缩放、随机裁减、随机排布的方式进行拼接,再拼接到一张图上作为训练数据。yolov5之后加上了放射变换处理。

Mosaic有如下优点:
(1)丰富数据集,加强了小目标检测,加强了面对复杂环境的情况等等:随机使用4张图片,随机缩放,再随机分布进行拼接,丰富了检测数据集,随机缩放增加了很多小目标,让网络的鲁棒性更强;
(2) 减少对mini-batch的依赖,降低对GPU显存要求:直接计算4张图片的数据,使得Mini-batch大小并不需要很大就可以达到比较好的效果,四张图片拼接在一起变相提高了batch_size,在进行batch normalization(归一化)的时候也会计算四张图片。

import cv2
import torch
import random
import os.path
import numpy as np
import matplotlib.pyplot as plt
from camvid import get_bbox, draw_box

def load_mosaic(im_files, name_color_dict):
    im_size = 640
    s_mosaic = im_size * 2
    mosaic_border = [-im_size // 2, -im_size // 2]
    labels4, segments4, colors = [], [], []
    # mosaic center x, y
    y_c, x_c = (int(random.uniform(-x, s_mosaic + x)) for x in mosaic_border)
    
    img4 = np.full((s_mosaic, s_mosaic, 3), 114, dtype=np.uint8)
    seg4 = np.full((s_mosaic, s_mosaic), 0, dtype=np.uint8)
    
    for i, im_file in enumerate(im_files):
        # Load image
        img = cv2.imread(im_file)
        seg_file = im_file.replace('images', 'labels')
        name = os.path.basename(seg_file).split('.')[0]
        seg_file = os.path.join(os.path.dirname(seg_file), name + '_L.png')
        seg, boxes, color = get_bbox(seg_file, names, name_color_dict)
        colors += color
        h, w, _ = np.shape(img)
        
        # place img in img4
        if i == 0:  # top left
            x1a, y1a, x2a, y2a = max(x_c - w, 0), max(y_c - h, 0), x_c, y_c
            x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h 
        elif i == 1:  # top right
            x1a, y1a, x2a, y2a = x_c, max(y_c - h, 0), min(x_c + w, s_mosaic), y_c
            x1b, y1b, x2b, y2b = 0, h - (y2a - y1a), min(w, x2a - x1a), h
        elif i == 2:  # bottom left
            x1a, y1a, x2a, y2a = max(x_c - w, 0), y_c, x_c, min(s_mosaic, y_c + h)
            x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, w, min(y2a - y1a, h)
        elif i == 3:  # bottom right
            x1a, y1a, x2a, y2a = x_c, y_c, min(x_c + w, s_mosaic), min(s_mosaic, y_c + 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]
        
        # place seg in seg4
        seg4[y1a:y2a, x1a:x2a] = seg[y1b:y2b, x1b:x2b]
        
        # update bbox
        padw = x1a - x1b
        padh = y1a - y1b
        boxes = xywhn2xyxy(boxes, padw=padw, padh=padh)
        labels4.append(boxes)
    labels4 = np.concatenate(labels4, 0)
    for x in labels4[:, 1:]:
        np.clip(x, 0, s_mosaic, out=x)  # clip coord
    
    # draw result
    draw_box(seg4, labels4, colors)
    
    return img4, labels4,seg4

if __name__ == '__main__':
    names = ['Pedestrian', 'Car', 'Truck_Bus']
    
    im_files = ['camvid/images/0016E5_01440.png',
                'camvid/images/0016E5_06600.png',
                'camvid/images/0006R0_f00930.png',
                'camvid/images/0006R0_f03390.png']

    load_mosaic(im_files, name_color_dict)

一 确定拼接中心点

二 放置

三 贴图

四 计算小图到大图上时所产生的偏移,用来计算mosaic增强后的标签的位置

五 进行mosaic的时候将四张图片整合到一起之后shape为[2img_size,2img_size]

六 对mosaic整合的图片进行随机旋转、平移、缩放、裁剪

七 resize为输入大小img_size

def random_perspective(im,
                       targets=(),
                       segments=(),
                       degrees=10,
                       translate=.1,
                       scale=.1,
                       shear=10,
                       perspective=0.0,
                       border=(0, 0)):
    # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(0.1, 0.1), scale=(0.9, 1.1), shear=(-10, 10))
    # targets = [cls, xyxy]

    height = im.shape[0] + border[0] * 2  # shape(h,w,c)
    width = im.shape[1] + border[1] * 2

    # Center:平移改变旋转中心
    C = np.eye(3)
    C[0, 2] = -im.shape[1] / 2  # x translation (pixels)
    C[1, 2] = -im.shape[0] / 2  # y translation (pixels)

    # Perspective:透视变换
    P = np.eye(3)
    P[2, 0] = random.uniform(-perspective, perspective)  # x perspective (about y)
    P[2, 1] = random.uniform(-perspective, perspective)  # y perspective (about x)

    # Rotation and Scale,旋转和缩放
    R = np.eye(3)
    a = random.uniform(-degrees, degrees)
    # a += random.choice([-180, -90, 0, 90])  # add 90deg rotations to small rotations
    s = random.uniform(1 - scale, 1 + scale)
    # s = 2 ** random.uniform(-scale, scale)
    R[:2] = cv2.getRotationMatrix2D(angle=a, center=(0, 0), scale=s)

    # Shear:切变
    S = np.eye(3)
    S[0, 1] = math.tan(random.uniform(-shear, shear) * math.pi / 180)  # x shear (deg)
    S[1, 0] = math.tan(random.uniform(-shear, shear) * math.pi / 180)  # y shear (deg)

    # Translation:平移
    T = np.eye(3)
    T[0, 2] = random.uniform(0.5 - translate, 0.5 + translate) * width  # x translation (pixels)
    T[1, 2] = random.uniform(0.5 - translate, 0.5 + translate) * height  # y translation (pixels)

    # Combined rotation matrix
    M = T @ S @ R @ P @ C  # 合并所有变换矩阵,从右到左做一次执行,先改变旋转中心,再透视变换,旋转和缩放,切变,最后平移
    if (border[0] != 0) or (border[1] != 0) or (M != np.eye(3)).any():  # image changed
        if perspective:
            im = cv2.warpPerspective(im, M, dsize=(width, height), borderValue=(114, 114, 114))
        else:  # affine
            im = cv2.warpAffine(im, M[:2], dsize=(width, height), borderValue=(114, 114, 114))

    # Visualize
    # import matplotlib.pyplot as plt
    # ax = plt.subplots(1, 2, figsize=(12, 6))[1].ravel()
    # ax[0].imshow(im[:, :, ::-1])  # base
    # ax[1].imshow(im2[:, :, ::-1])  # warped

    # Transform label coordinates
    n = len(targets)
    if n:
        use_segments = any(x.any() for x in segments)
        new = np.zeros((n, 4))
        if use_segments:  # warp segments
            segments = resample_segments(segments)  # upsample
            for i, segment in enumerate(segments):
                xy = np.ones((len(segment), 3))
                xy[:, :2] = segment
                xy = xy @ M.T  # transform
                xy = xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]  # perspective rescale or affine

                # clip
                new[i] = segment2box(xy, width, height)

        else:  # warp boxes
            xy = np.ones((n * 4, 3))
            xy[:, :2] = targets[:, [1, 2, 3, 4, 1, 4, 3, 2]].reshape(n * 4, 2)  # x1y1, x2y2, x1y2, x2y1
            xy = xy @ M.T  # transform
            xy = (xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]).reshape(n, 8)  # perspective rescale or affine

            # create new boxes
            x = xy[:, [0, 2, 4, 6]]
            y = xy[:, [1, 3, 5, 7]]
            new = np.concatenate((x.min(1), y.min(1), x.max(1), y.max(1))).reshape(4, n).T

            # clip
            new[:, [0, 2]] = new[:, [0, 2]].clip(0, width)
            new[:, [1, 3]] = new[:, [1, 3]].clip(0, height)

        # filter candidates
        i = box_candidates(box1=targets[:, 1:5].T * s, box2=new.T, area_thr=0.01 if use_segments else 0.10)
        targets = targets[i]
        targets[:, 1:5] = new[i]

    return im, targets

补充:

在warpPerspective()函数中,最后面两个参数 boarderMode,boarderValue声明在转换后的图片背景颜色。

其中:

**borderMode:**说明背景外插模式,可以选择的模式包括:
cv2.BORDER_CONSTANT
cv2.BORDER_REPLICATE
boardValue: 外插背景颜色,可以使用三元组(R,G,B):0 ~ 255说明背景颜色。


标签:Moaic,增强,python,random,xy,im,perspective,np,mosaic
From: https://blog.51cto.com/u_15088375/6969206

相关文章

  • Python通过解析html来实现简历系统
    把以上三个文件放到personData目录下即可。Admin.pyw#coding:utf-8fromPyQt4.QtGuiimport*fromPyQt4.QtCoreimport*importos,sys,time,jsonimportlxml.htmlreload(sys)sys.setdefaultencoding("utf-8")classmat(QDialog):def__init__(self):s......
  • 猿创征文|Python学习工具千千万,我心中的TOP10
    前言:大家好,我是是Dream呀,在我们平时的开发和生活中,每天都在使用、寻找、贡献、创作各类开发者工具,包括开源服务、付费软件、API等。好的工具可以极大帮助我们提升效率,服务业务。作为一名资深的Python博主,很多人都会问我平时使用什么工具,亦或者说有什么比较好的推荐工具呢?实话实......
  • python fitz模块报错RuntimeError: Directory ‘static/’ does not exist 解决方案
    报错fitz模块报错RuntimeError:Directory‘static/’doesnotexist原因使用Python处理PDF文档时,需要使用fitz模块。由于Python3.8以上版本与fitz有兼容问题,会出现以下错误信息:RuntimeError:Directory‘static/’doesnotexist解决办法卸载fitz模块,安装pymupdf模块......
  • Python全局变量
    关于Python跨文件全局变量作用域的问题可以定义一个Global_var.py将所有的全局变量放进去,在其他模块导入;重点:在其他模块中使用importGlobal_var导入时,在函数内部使用Global_var.变量名即可直接修改全局变量,无需global修饰;但是使用fromGlobal_varimport*导入模块时必须要在......
  • CTFer成长记录——CTF之Web专题·攻防世界-Web_python_template_injection
    一、题目链接https://adworld.xctf.org.cn/challenges/list二、解法步骤  python的flask模板注入的题思路比较固定,Jinja2模板引擎中,{{}}是变量包裹标识符。{{}}并不仅仅可以传递变量,还可以执行一些简单的表达式。1.猜测是否存在注入:直接在url后面加上{{config}}2.获取基本......
  • python中的exec()、eval()以及complie()
    1.eval函数函数的作用:计算指定表达式的值。也就是说它要执行的python代码只能是单个表达式(注意eval不支持任何形式的赋值操作),而不能是复杂的代码逻辑。eval(source,globals=None,locals=None,/)参数说明:source:必选参数,可以是字符串,也可以是一个任意的code(代码)对象实......
  • python多进程编程常用到的方法
    python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU资源,在python中大部分情况需要使用多进程。python提供了非常好用的多进程包Multiprocessing,只需要定义一个函数,python会完成其它所有事情。借助这个包,可以轻松完成从单进程到并发执行的转换。multiprocessing支......
  • 【python_5】基础语法:数据类型以及数据类型转变!
    1.使用type()语句查看数据类型目前在入门阶段,我们主要接触如下三类数据类型:类型描述说明string字符串类型用引号引起来的数据都是字符串int整型(有符号)数字类型,存放整数如-1,10,0等float浮点型(有符号)数字类型,存放小数如-3.14,6.78等我们可以通过type()语句来得到数据的类型:type(被查......
  • 关于Python的学习记录(二十一_对象的序列化和反序列化)
    JSON概述在Python中,我们可以将程序中的数据以JSON格式进行保存。JSON是“JavaScriptObjectNotation”的缩写,它本来是JavaScript语言中创建对象的一种字面量语法,现在已经被广泛的应用于跨语言跨平台的数据交换。使用JSON的原因非常简单,因为它结构紧凑而且是纯文本,任何操......
  • Python数据的深浅拷贝
    一、怎么理解深浅拷贝二、本人之前的错误理解(写到最后我会进行提示,以防某些同学跟着我之前的思路走,导致理解混乱,怕自己理解混乱的同学可以不看这部分。) 一、深浅拷贝主要的区别是在于数据进行拷贝的时候,发生的变化浅拷贝:创建一个新对象,然后将原始对象中的元素复制到新对象中......