精华内容
下载资源
问答
  • OCR -- 训练数据扩增的方法

    千次阅读 2018-10-27 22:41:50
    :param sigma3: 3 倍标准差, 99% 的数据落在 (mu-3*sigma, mu+3*sigma) :return: """ # 标准差 sigma = sigma3 / 3 dst = sigma * np.random.randn() + mu dst = np.clip(dst, 0 - sigma3, sigma3) return ...

    结交了一些大神级的人物, 每次交流都有很多收获,感谢一路相伴,感谢带我一起成长。

    (1)透视变换

    (2)gauss_blur

    (3)norm_blur

    (4)模糊图像,模拟小图片放大的效果

    (5)颜色翻转、滤波等等

    具体代码实现如下:

    (1)透视变换 (具体原理可查看:仿射变换,透视变换:二维坐标到二维坐标之间的线性变换,可用于landmark人脸矫正

    #!/usr/env/bin python3
    from functools import reduce
    import numpy as np
    import cv2
    import math
    import random
    
    
    # http://planning.cs.uiuc.edu/node102.html
    def get_rotate_matrix(x, y, z):
        """
        按照 zyx 的顺序旋转,输入角度单位为 degrees, 均为顺时针旋转
        :param x: X-axis
        :param y: Y-axis
        :param z: Z-axis
        :return:
        """
        x = math.radians(x)
        y = math.radians(y)
        z = math.radians(z)
    
        c, s = math.cos(y), math.sin(y)
        M_y = np.matrix([[c, 0., s, 0.],
                         [0., 1., 0., 0.],
                         [-s, 0., c, 0.],
                         [0., 0., 0., 1.]])
    
        c, s = math.cos(x), math.sin(x)
        M_x = np.matrix([[1., 0., 0., 0.],
                         [0., c, -s, 0.],
                         [0., s, c, 0.],
                         [0., 0., 0., 1.]])
    
        c, s = math.cos(z), math.sin(z)
        M_z = np.matrix([[c, -s, 0., 0.],
                         [s, c, 0., 0.],
                         [0., 0., 1., 0.],
                         [0., 0., 0., 1.]])
    
        return M_x * M_y * M_z
    
    
    def cliped_rand_norm(mu=0, sigma3=1):
        """
        :param mu: 均值
        :param sigma3: 3 倍标准差, 99% 的数据落在 (mu-3*sigma, mu+3*sigma)
        :return:
        """
        # 标准差
        sigma = sigma3 / 3
        dst = sigma * np.random.randn() + mu
        dst = np.clip(dst, 0 - sigma3, sigma3)
        return dst
    
    
    def warpPerspective(src, M33, sl, gpu):
        if gpu:
            from libs.gpu.GpuWrapper import cudaWarpPerspectiveWrapper
            dst = cudaWarpPerspectiveWrapper(src.astype(np.uint8), M33, (sl, sl), cv2.INTER_CUBIC)
        else:
            dst = cv2.warpPerspective(src, M33, (sl, sl), flags=cv2.INTER_CUBIC)
        return dst
    
    
    # https://stackoverflow.com/questions/17087446/how-to-calculate-perspective-transform-for-opencv-from-rotation-angles
    # https://nbviewer.jupyter.org/github/manisoftwartist/perspectiveproj/blob/master/perspective.ipynb
    # http://planning.cs.uiuc.edu/node102.html
    class PerspectiveTransform(object):
        def __init__(self, x, y, z, scale, fovy):
            self.x = x
            self.y = y
            self.z = z
            self.scale = scale
            self.fovy = fovy
    
        def transform_image(self, src, gpu=False):
            if len(src.shape) > 2:
                H, W, C = src.shape
            else:
                H, W = src.shape
    
            M33, sl, _, ptsOut = self.get_warp_matrix(W, H, self.x, self.y, self.z, self.scale, self.fovy)
            sl = int(sl)
    
            dst = warpPerspective(src, M33, sl, gpu)
    
            return dst, M33, ptsOut
    
        def transform_pnts(self, pnts, M33):
            """
            :param pnts: 2D pnts, left-top, right-top, right-bottom, left-bottom
            :param M33: output from transform_image()
            :return: 2D pnts apply perspective transform
            """
            pnts = np.asarray(pnts, dtype=np.float32)
            pnts = np.array([pnts])
            dst_pnts = cv2.perspectiveTransform(pnts, M33)[0]
    
            return dst_pnts
    
        def get_warped_pnts(self, ptsIn, ptsOut, W, H, sidelength):
            ptsIn2D = ptsIn[0, :]
            ptsOut2D = ptsOut[0, :]
            ptsOut2Dlist = []
            ptsIn2Dlist = []
    
            for i in range(0, 4):
                ptsOut2Dlist.append([ptsOut2D[i, 0], ptsOut2D[i, 1]])
                ptsIn2Dlist.append([ptsIn2D[i, 0], ptsIn2D[i, 1]])
    
            pin = np.array(ptsIn2Dlist) + [W / 2., H / 2.]
            pout = (np.array(ptsOut2Dlist) + [1., 1.]) * (0.5 * sidelength)
            pin = pin.astype(np.float32)
            pout = pout.astype(np.float32)
    
            return pin, pout
    
        def get_warp_matrix(self, W, H, x, y, z, scale, fV):
            fVhalf = np.deg2rad(fV / 2.)
            d = np.sqrt(W * W + H * H)
            sideLength = scale * d / np.cos(fVhalf)
            h = d / (2.0 * np.sin(fVhalf))
            n = h - (d / 2.0)
            f = h + (d / 2.0)
    
            # Translation along Z-axis by -h
            T = np.eye(4, 4)
            T[2, 3] = -h
    
            # Rotation matrices around x,y,z
            R = get_rotate_matrix(x, y, z)
    
            # Projection Matrix
            P = np.eye(4, 4)
            P[0, 0] = 1.0 / np.tan(fVhalf)
            P[1, 1] = P[0, 0]
            P[2, 2] = -(f + n) / (f - n)
            P[2, 3] = -(2.0 * f * n) / (f - n)
            P[3, 2] = -1.0
    
            # pythonic matrix multiplication
            M44 = reduce(lambda x, y: np.matmul(x, y), [P, T, R])
    
            # shape should be 1,4,3 for ptsIn and ptsOut since perspectiveTransform() expects data in this way.
            # In C++, this can be achieved by Mat ptsIn(1,4,CV_64FC3);
            ptsIn = np.array([[
                [-W / 2., H / 2., 0.],
                [W / 2., H / 2., 0.],
                [W / 2., -H / 2., 0.],
                [-W / 2., -H / 2., 0.]
            ]])
            ptsOut = cv2.perspectiveTransform(ptsIn, M44)
    
            ptsInPt2f, ptsOutPt2f = self.get_warped_pnts(ptsIn, ptsOut, W, H, sideLength)
    
            # check float32 otherwise OpenCV throws an error
            assert (ptsInPt2f.dtype == np.float32)
            assert (ptsOutPt2f.dtype == np.float32)
            M33 = cv2.getPerspectiveTransform(ptsInPt2f, ptsOutPt2f).astype(np.float32)
    
            return M33, sideLength, ptsInPt2f, ptsOutPt2f
    
    def apply_perspective_transform(img, text_box_pnts, max_x, max_y, max_z, gpu=False):
        """
        Apply perspective transform on image
        :param img: origin numpy image
        :param text_box_pnts: four corner points of text
        :param x: max rotate angle around X-axis
        :param y: max rotate angle around Y-axis
        :param z: max rotate angle around Z-axis
        :return:
            dst_img:
            dst_img_pnts: points of whole word image after apply perspective transform
            dst_text_pnts: points of text after apply perspective transform
        """
    
        x = math_utils.cliped_rand_norm(0, max_x)
        y = math_utils.cliped_rand_norm(0, max_y)
        z = math_utils.cliped_rand_norm(0, max_z)
    
        # print("x: %f, y: %f, z: %f" % (x, y, z))
    
        transformer = PerspectiveTransform(x, y, z, scale=1.0, fovy=50)
    
        dst_img, M33, dst_img_pnts = transformer.transform_image(img, gpu)
        dst_text_pnts = transformer.transform_pnts(text_box_pnts, M33)
    
        return dst_img, dst_img_pnts, dst_text_pnts

    (2)gauss_blur

    def apply_gauss_blur(img, ks=None):
        if ks is None:
            ks = [7, 9, 11, 13]
        ksize = random.choice(ks)
    
        sigmas = [0, 1, 2, 3, 4, 5, 6, 7]
        sigma = 0
        if ksize >= 3:
            sigma = random.choice(sigmas)
        img = cv2.GaussianBlur(img, (ksize, ksize), sigma)
        return img

    (3)norm_blur

    def apply_norm_blur(img, ks=None):
        # kernel == 1, the output image will be the same
        if ks is None:
            ks = [2, 3]
        kernel = random.choice(ks)
        img = cv2.blur(img, (kernel, kernel))
        return img

    (4)模糊图像,模拟小图片放大的效果

    def apply_prydown(img):
        """
        模糊图像,模拟小图片放大的效果
        """
        scale = random.uniform(1, self.cfg.prydown.max_scale)
        height = img.shape[0]
        width = img.shape[1]
    
        out = cv2.resize(img, (int(width / scale), int(height / scale)), interpolation=cv2.INTER_AREA)
        return cv2.resize(out, (width, height), interpolation=cv2.INTER_AREA)

    (5)颜色翻转、滤波等等

    def reverse_img(word_img):
        offset = np.random.randint(-10, 10)
        return 255 + offset - word_img
    
    
    def apply_emboss(word_img):
        emboss_kernal = np.array([
            [-2, -1, 0],
            [-1, 1, 1],
            [0, 1, 2]
        ])
        return cv2.filter2D(word_img, -1, emboss_kernal)
    
    def apply_sharp(word_img):
        sharp_kernel = np.array([
            [-1, -1, -1],
            [-1, 9, -1],
            [-1, -1, -1]
        ])
        return cv2.filter2D(word_img, -1, sharp_kernel)

     

     

     

     

     

     

    展开全文
  • 训练模型时,有时在数据量较少情况下,避免过拟合,通常会采取人为进行数据增强来达到扩充数据集的目的,下面就介绍一种使用Augmentor来扩充数据集的方法。 实现过程 step 1 将源数据放在E盘 step 2 运行脚本 ...

    文章目录

    前言

    在训练模型时,有时在数据量较少情况下,避免过拟合,通常会采取人为进行数据增强来达到扩充数据集的目的,下面就介绍一种使用Augmentor来扩充数据集的方法。

    实现过程

    • step 1 将源数据放在E盘
    • step 2 运行脚本
    • step 3 生成扩增后的数据

    程序实现过程如下:

    import numpy as np, Augmentor, cv2, sys
    import os
    import shutil
    def del_file(path):
        ls = os.listdir(path) 
        for i in ls:
            c_path = os.path.join(path, i)
            if os.path.isdir(c_path):
                del_file(c_path)
            else:
                os.remove(c_path)
    
    def Enhancement(filePath, rate):
        index = ngFilePath.rfind("\\")
        print(index)
        dataType = filePath.find("NG")
        dataType1 = filePath.find("OK")
    
        if(dataType > 0):
            enhancementDir = filePath[0:index] + "\\" + 'EnhanceImg' + '\\' + 'NG'
        if (dataType1 > 0):
            enhancementDir = filePath[0:index] + "\\" + 'EnhanceImg' + '\\' + 'OK'
    
        showDir = filePath[0:index] + "\\" + 'showImg'
        singleDir = filePath[0:index] + "\\" + 'sigleImg'
    
        isExist = os.path.exists(enhancementDir);
        if not isExist:
            os.makedirs(enhancementDir)
        else:
            del_file(enhancementDir)
        isExist = os.path.exists(showDir)
    
        if not isExist:
            os.makedirs(showDir)
        else:
            del_file(showDir)
    
        isExist = os.path.exists(singleDir)
        if not isExist:
            os.makedirs(singleDir)
        else:
            del_file(singleDir)
    
        sourceFiles = os.listdir(filePath)
        num = len(sourceFiles)
        sourceList = list(range(num))
        for i in sourceList:
            sourceFilesName = os.path.join(filePath,sourceFiles[i])
            src = cv2.imread(sourceFilesName, 0)
            shutil.copy2(sourceFilesName, singleDir)
            p = Augmentor.Pipeline(singleDir, showDir)
            p.random_brightness(probability= 0.7, min_factor = 0.5, max_factor= 1.2)
            # p.crop_centre(probability=0.5,160, 160)
            p.resize(probability=1, width=160, height=160)
            p.random_contrast(probability= 0.5, min_factor= 0.5, max_factor= 1.2)
            p.sample(rate)
            # shutil.copy2(sourceFilesName, enhancementDir)
            enhancedImg = os.listdir(showDir)
            enhanceImgList = list(range(len(enhancedImg)))
            sampleImgList =  []
            for j in enhanceImgList:
                fileName = enhancedImg[j]
                sampleImgList.append(fileName)
            numSampleImg = list(range(len(sampleImgList)))
            for k in numSampleImg:
                fileName = os.path.join(showDir, sampleImgList[k])
                shutil.copy2(fileName, enhancementDir)
    
            del_file(showDir)
    
    if __name__ == '__main__':
        ngFilePath = "E:\\IMG\\NG"
        okFilePath = "E:\\IMG\\OK"
        rate = 10
        Enhancement(okFilePath, rate)
    

    注:
    由于这里是做二分类,所以将数据分为OK和NG,这里OK文件夹里随便放了5张图片,然后对这5张图片进行数据增强。

    在这里插入图片描述
    运行脚本后,后自动生成三个文件夹,数据增强后的数据会自动保存在EnhanceImg文件夹下
    在这里插入图片描述在这里插入图片描述

    展开全文
  • Python中有很多库可以完成数据读取的操作,比较常见的有Pillow和OpenCV。 1.1 Pillow Pillow是Python图像处理函式库(PIL)的一个分支。Pillow提供了常见的图像读取和处理的操作,而且可以与ipython notebook无缝集成...

    1、图像读取

    Python中有很多库可以完成数据读取的操作,比较常见的有Pillow和OpenCV。
    1.1 Pillow
    Pillow是Python图像处理函式库(PIL)的一个分支。Pillow提供了常见的图像读取和处理的操作,而且可以与ipython notebook无缝集成,是应用比较广泛的库。
    在这里插入图片描述
    在这里插入图片描述
    注:
    Pillow的官方文档:https://pillow.readthedocs.io/en/stable/
    1.2 OpenCV
    OpenCV是一个跨平台的计算机视觉库,最早由Intel开源得来。OpenCV发展的非常早,拥有众多的计算机视觉、数字图像处理和机器视觉等功能。OpenCV在功能上比Pillow更加强大很多,学习成本也高很多。
    在这里插入图片描述
    OpenCV包含了众多的图像处理的功能。OpenCV还内置了很多的图像特征处理算法,如关键点检测、边缘检测和直线检测等。
    注:
    OpenCV官网:https://opencv.org/
    OpenCV Github:https://github.com/opencv/opencv
    OpenCV 扩展算法库:https://github.com/opencv/opencv_contrib

    2、数据扩增方法

    2.1 数据扩增介绍
    数据扩增可以增加训练集的样本,同时也可以有效缓解模型过拟合的情况,也可以给模型带来的更强的泛化能力。
    在这里插入图片描述
    数据扩增用处:
    在深度学习模型的训练过程中,数据扩增是必不可少的环节。现有深度学习的参数非常多,一般的模型可训练的参数量基本上都是万到百万级别,而训练集样本的数量很难有这么多。其次数据扩增可以扩展样本空间,假设现在的分类模型需要对汽车进行分类,左边的是汽车A,右边为汽车B。如果不使用任何数据扩增方法,深度学习模型会从汽车车头的角度来进行判别,而不是汽车具体的区别。
    在这里插入图片描述
    数据扩增方法:
    数据扩增方法有很多:从颜色空间、尺度空间到样本空间,同时根据不同任务数据扩增都有相应的区别。
    对于图像分类,数据扩增一般不会改变标签;对于物体检测,数据扩增会改变物体坐标位置;对于图像分割,数据扩增会改变像素标签。
    2.2 常见的数据扩增方法
    在常见的数据扩增方法中,一般会从图像颜色、尺寸、形态、空间和像素等角度进行变换。当然不同的数据扩增方法可以自由进行组合,得到更加丰富的数据扩增方法。
    以torchvision为例,常见的数据扩增方法包括:
    1、transforms.CenterCrop 对图片中心进行裁剪
    2、transforms.ColorJitter 对图像颜色的对比度、饱和度和零度进行变换
    3、transforms.FiveCrop 对图像四个角和中心进行裁剪得到五分图像
    4、transforms.Grayscale 对图像进行灰度变换
    5、transforms.Pad 使用固定值进行像素填充
    6、transforms.RandomAffine 随机仿射变换
    7、transforms.RandomCrop 随机区域裁剪
    8、transforms.RandomHorizontalFlip 随机水平翻转
    9、transforms.RandomRotation 随机旋转
    10、transforms.RandomVerticalFlip 随机垂直翻转
    在这里插入图片描述
    在本次赛题中,任务是需要对图像中的字符进行识别,因此对于字符图片并不能进行翻转操作。比如字符6经过水平翻转就变成了字符9,会改变字符原本的含义。
    2.3 常用的数据扩增库
    torchvision
    https://github.com/pytorch/vision
    pytorch官方提供的数据扩增库,提供了基本的数据数据扩增方法,可以无缝与torch进行集成;但数据扩增方法种类较少,且速度中等;

    imgaug
    https://github.com/aleju/imgaug
    imgaug是常用的第三方数据扩增库,提供了多样的数据扩增方法,且组合起来非常方便,速度较快;

    albumentations
    https://albumentations.readthedocs.io
    是常用的第三方数据扩增库,提供了多样的数据扩增方法,对图像分类、语义分割、物体检测和关键点检测都支持,速度较快。

    3、Pytorch读取数据

    在Pytorch中数据是通过Dataset进行封装,并通过DataLoder进行并行读取。所以我们只需要重载一下数据读取的逻辑就可以完成数据的读取。

    import os, sys, glob, shutil, json
    import cv2
    
    from PIL import Image
    import numpy as np
    
    import torch
    from torch.utils.data.dataset import Dataset
    import torchvision.transforms as transforms
    
    class SVHNDataset(Dataset):
        def __init__(self, img_path, img_label, transform=None):
            self.img_path = img_path
            self.img_label = img_label 
            if transform is not None:
                self.transform = transform
            else:
                self.transform = None
    
        def __getitem__(self, index):
            img = Image.open(self.img_path[index]).convert('RGB')
    
            if self.transform is not None:
                img = self.transform(img)
            
            # 原始SVHN中类别10为数字0
            lbl = np.array(self.img_label[index], dtype=np.int)
            lbl = list(lbl)  + (5 - len(lbl)) * [10]
            
            return img, torch.from_numpy(np.array(lbl[:5]))
    
        def __len__(self):
            return len(self.img_path)
    
    train_path = glob.glob('../input/train/*.png')
    train_path.sort()
    train_json = json.load(open('../input/train.json'))
    train_label = [train_json[x]['label'] for x in train_json]
    
    data = SVHNDataset(train_path, train_label,
              transforms.Compose([
                  # 缩放到固定尺寸
                  transforms.Resize((64, 128)),
    
                  # 随机颜色变换
                  transforms.ColorJitter(0.2, 0.2, 0.2),
    
                  # 加入随机旋转
                  transforms.RandomRotation(5),
    
                  # 将图片转换为pytorch 的tesntor
                  # transforms.ToTensor(),
    
                  # 对图像像素进行归一化
                  # transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])
                ]))
    

    上述代码可以将赛题的图像数据和对应标签进行读取,在读取过程中的进行数据扩增,效果如下:
    在这里插入图片描述
    接下来我们将在定义好的Dataset基础上构建DataLoder,Dataset:对数据集的封装,提供索引方式的对数据样本进行读取;
    DataLoder:对Dataset进行封装,提供批量读取的迭代读取。
    加入DataLoder后,数据读取代码改为如下:

    import os, sys, glob, shutil, json
    import cv2
    
    from PIL import Image
    import numpy as np
    
    import torch
    from torch.utils.data.dataset import Dataset
    import torchvision.transforms as transforms
    
    class SVHNDataset(Dataset):
        def __init__(self, img_path, img_label, transform=None):
            self.img_path = img_path
            self.img_label = img_label 
            if transform is not None:
                self.transform = transform
            else:
                self.transform = None
    
        def __getitem__(self, index):
            img = Image.open(self.img_path[index]).convert('RGB')
    
            if self.transform is not None:
                img = self.transform(img)
            
            # 原始SVHN中类别10为数字0
            lbl = np.array(self.img_label[index], dtype=np.int)
            lbl = list(lbl)  + (5 - len(lbl)) * [10]
            
            return img, torch.from_numpy(np.array(lbl[:5]))
    
        def __len__(self):
            return len(self.img_path)
    
    train_path = glob.glob('../input/train/*.png')
    train_path.sort()
    train_json = json.load(open('../input/train.json'))
    train_label = [train_json[x]['label'] for x in train_json]
    
    train_loader = torch.utils.data.DataLoader(
            SVHNDataset(train_path, train_label,
                       transforms.Compose([
                           transforms.Resize((64, 128)),
                           transforms.ColorJitter(0.3, 0.3, 0.2),
                           transforms.RandomRotation(5),
                           transforms.ToTensor(),
                           transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
                ])), 
        batch_size=10, # 每批样本个数
        shuffle=False, # 是否打乱顺序
        num_workers=10, # 读取的线程个数
    )
    
    for data in train_loader:
        break
    

    在加入DataLoder后,数据按照批次获取,每批次调用Dataset读取单个样本进行拼接。此时data的格式为:

    torch.Size([10, 3, 64, 128]), torch.Size([10, 6])
    

    前者为图像文件,为batchsize * chanel * height * width次序;后者为字符标签。

    4、总结

    此处进行了数据读取相关操作的总结,以及数据扩增方法和使用,并使用Pytorch框架对本次赛题的数据进行读取。

    展开全文
  • 深度学习中的图像数据扩增(Data Augmentations)方法总结:传统扩增方法及应用 1. 前言 这篇文章主要参考 A survey on Image Data Augmentation for Deep Learning, 结合 pytorch 和总结了常用的传统扩增方法及其...

    深度学习中的图像数据扩增(Data Augmentations)方法总结:常用传统扩增方法及应用

    1. 前言

    这篇文章主要参考 A survey on Image Data Augmentation for Deep Learning, 总结了常用的传统扩增方法及其应用时的注意事项。这里的传统方法指不包括基于深度学习(比如 GAN)等新的扩增方法。

    另外需要注意的是,虽然对于不同的任务,比如对于分类,检测任务,不同的任务在采用某一个具体的扩增方法的时候会有所不同,比如对于检测任务需要考虑对 bounding box 进行相应的操作,但是这里仅仅从扩增方法的角度来说是没有区别的。

    最后, 数据扩增的具体方法非常多,而且除了各个训练框架提供的方法之外还有很多第三方库,这里仅仅是整理了一些比较常见的扩增方法。更多的扩增方法可以参考第三方库 imgaug, albumentations 等。

    在这里插入图片描述

    2. 数据扩增

    数据扩增是对数据进行扩充的方法的总称。数据扩增可以增加训练集的样本,可以有效缓解模型过拟合的情况,也可以给模型带来的更强的泛化能力。怎么理解呢?

    数据扩增的目的就是使得训练数据尽可能的接近测试数据,从而提高预测精度。另外数据扩增可以迫使网络学习到更鲁棒性的特征,从而使模型拥有更强的泛化能力,比如对图像进行一定程度的遮挡。

    通常在进行数据扩增操作的时候应该保持图像原本的标签不变,比如对于猫狗分类任务,rotate 或者 flip ,一般对标签是没有影响的,但是对于手写数字识别,比如 9 和 6 就不适用了。当然如果能相应的修改标签,对于网络训练来说是有益的,但是这将又是一个麻烦的费时费力的过程。所以通常来说,数据扩增应该在不改变标签的前提下进行。

    3. 常用数据扩增方法

    3.1 基于几何变换的扩增方法

    基于几何变换的方法可以消除测试集和训练集的位置差异,尺度差异,视角差异等。

    3.1.1 Flipping

    水平翻转通常比竖直翻转更通用,但是对于字符识别任务,通常不适用。

    3.1.2 Cropping

    裁剪是一个比较常用,也是一个长点比较明显的数据增强的方式。

    3.1.3 Rotation

    旋转的角度关系到标签是否安全,比如对于 MNIST,1° 到 20° 或者 -1° 到 -20° 之间的轻微旋转是没有问题的,如果更大幅度的旋转可能会影响到标签。

    3.1.4 Translation

    平移(向左、向右、向上或向下移动)图像是一个非常有用的变换,可以避免数据中的位置偏差。例如,如果数据集中的所有图像都是居中的(这在人脸识别数据集中很常见),这就要求模型也要在完全居中的图像上进行测试。当原始图像被平移后造成的空白区域,可以用一个常数值填充,如 0 或 255 ,也可以用随机或高斯噪声填充。这种填充可以保留图像增强后的空间尺寸。

    3.1.5 Noise injection

    添加噪声一般可以应对噪声干扰,或者成像异常等特殊情况。

    增加高斯噪声是比较常用的操作,增加噪声可以帮助 CNNs 学习到更 robust feature。

    对于训练数据中存在的位置偏差,几何变换是非常好的解决方案。有许多潜在的偏差来源,可以将训练数据与测试数据的分布分开。如果存在位置偏差,例如在人脸识别数据集中,每个人脸都是完全居中的,几何变换是一个很好的解决方案。除了克服位置偏差的强大能力之外,几何变换也很有用,因为它们很容易实现。有很多成像处理库,可以让水平翻转和旋转等操作轻松上手。几何变换的一些缺点包括额外的内存、变换计算成本和额外的训练时间。一些几何变换,如平移或随机裁剪等几何变换必须手动观察,以确保它们没有改变图像的标签。最后,在所涉及的许多应用领域,如医学图像分析,训练数据与测试数据之间的偏差比位置偏差和平移偏差更复杂。因此,几何变换也不一定总是能带来明显的效果。

    3.2 颜色空间变换

    颜色空间变换一般可以消除光照、亮度及色彩差异。

    • 对过亮或过暗的图像进行快速处理的方法是在图像中进行循环,并将像素值减少或增加一个恒定值。
    • 另一种快速的色彩空间处理方法是拼接出单个RGB颜色矩阵。
    • 另一种变换包括将像素值限制在一定的最小值或最大值。数字图像中颜色的内在表现形式,使其可以用于许多增强策略。
    • 通道分离
    • 亮度
    • 对比度
    • 饱和度
    • 基于直方图
    • 灰度图
      转换为灰度图后,计算量减少,但是精度通常会有所降低,有人在 ImageNet 上对比 RGB 和 灰度图,发现灰度图的精度下降大约 3%。

    颜色空间变换也可以从图像编辑应用程序中得到。图像中每个RGB颜色通道中的像素值被聚合成一个颜色直方图。这个直方图可以被操纵,应用滤镜来改变图像的颜色空间特性。

    颜色空间变化可以帮助客服光照差异,但是如果任务对颜色的依赖性很强,比如要分辨油漆,水和血液,可能红色是一个非常重要的信息,如果进行不当的颜色空间变换,可能适得其反。

    3.3 Kernel filters

    • 模糊
    • 锐化
      直观地讲,为数据增强而对图像进行模糊化处理可能会导致测试过程中对运动模糊的抵抗力更强。此外,为数据增强而对图像进行锐化可能会导致对感兴趣对象的更多细节进行封装。另外由于 Kernel filters 的方式和 CNNs 类似,因此可以把该操作集成到 CNN 层。

    3.4 Mixing images

    在这里插入图片描述

    Mixing images 被证明对小的数据集作用更明显。

    • 两幅图每个像素取平均
    • 两幅图线性叠加
    • 从两幅或多幅图中裁剪一个局部,然后将这些拼接

    这种方法主要在目标检测中使用的比较多,效果比较好。

    3.5 Random erasing

    思想和 dropout 类似,不同的是 Random erasing 是在输入数据空间进行,而非是在网络结构中。这种方法也可以看着是在模拟遮挡的情况,以保证网络关注整个图像,而不是只关注其中的一个子集。

    通常 earsing 的区域直接填充随机值效果更好。使用的时候需要注意是否标签安全,可能需要人为的加入一些限制,以保证标签的正确性。

    4 总结

    • 数据扩增的方式很多,但是在实际项目中通常最直接的方法是收集更多的数据,从根本上解决问题,而数据扩增更多的是锦上添花。
    • 数据扩增并不是总能产生积极的作用,不当的数据扩增可能产生负面影响。而什么是适当的数据扩增,取决于具体的任务和数据集。
    • 数据扩增的总体原则是让训练集的分布靠近测试集。
    • crop 在多数情况下是非常有效的扩增方式。
    • 基于 GAN 的扩增方式往往需要大量的数据,可是扩增的原因就是数据太少。。。

    参考

    展开全文
  • 在Kaggle视觉竞赛中,数据扩增(Data Augmentation)是不可少的环节。数据扩增可以增加训练集的样本,同时也可以有效环节模型过拟合的情况,也可以给模型带来的更强的泛化能力...
  • ↑↑↑关注后"星标"Datawhale每日干货 &每月组队学习,不错过Datawhale干货作者:樊亮、黄星源、Datawhale优秀学习者本文对图像数据读...
  • 数据预处理--数据扩增

    千次阅读 2019-07-01 09:32:06
    原 数据预处理--数据扩增/Data Augmentation/图像增强 ...
  • 图2:传统数据扩增简介 本质上,数据扩增的效果来源于促进模型对于我们定义的这些变换的不变性。然而,从生物体的角度出发,视觉的不变性并不仅限于简单的几何变换,而是更多地体现在更为高级的语义层面。例如在图3...
  • 图像数据读取及数据扩增方法

    千次阅读 2020-05-25 19:30:00
    Datawhale干货作者:王程伟,Datawhale成员本文为干货知识+竞赛实践系列分享,旨在理论与实践结合,从学习到项目实践。(零基础入门系列:数据挖掘/cv/nlp/金融风控/...
  • 本章对语义分割任务中常见的数据扩增方法进行介绍,并使用OpenCV和albumentations两个库完成具体的数据扩增操作。 2 数据扩增方法 本章主要内容为数据扩增方法、OpenCV数据扩增、albumentations数据扩增和Pytorch...
  • 数据读取与数据扩增

    2020-05-23 22:48:48
    2 图像读取和处理2.1 学习Pillow2.1.1 类--图像2.2 OpenCV-python库3 数据扩增方法3.1 数据扩增介绍3.2 数据扩增方法3.3 常用的数据扩增函数3.3.1 以torchvision为例,常见的数据扩增方法包括:3.4 常用数据扩增库4 ...
  • 深度学习之数据扩增

    2020-05-23 18:45:26
    在深度学习中数据扩增非常重要,可以增加训练样本数量,同时可以在一定程度上缓解模型过拟合,提高模型的泛化能力,可以扩展样本空间。 二、常⻅的数据扩增⽅方法 常见的数据扩增方法主要是从图像颜色,尺寸,形态,...
  • 数据扩增python实现

    千次阅读 2019-04-09 10:28:13
    训练深度学习模型,当训练数据不够时,往往需要进行数据扩增,常见的数据扩增方法有: # 1 尺寸 # 2 旋转 # 3 镜像 # 4 平移 # 5 亮度不变 # 6 色度不变 # 7 对比度不变 # 8 锐度 from PIL import Image, ...
  • GAN实战(1)——Keras使用ACGAN实现数据扩增(含代码) 1、什么是ACGAN 2、数据集准备 3、ACGAN网络的结构详解 3.1 生成模型 3.2 判别模型 3.3 模型训练 5、主体代码 6、模型调用 7、总结 8、参考 1、什么是ACGAN ...
  • 自从BERT出现以来,越来越多的优秀的预训练模型如雨后春笋般层出不穷,这给我们处理NLP任务带来了极大的便利,身处这么一个时代,能随意使用这些预训练模型无疑是很舒适的一件事情,但是预训练模型的使用也有着不少...
  • 这里介绍其中一种带标签扩充数据集的方法。
  • 数据扩增一直是竞赛中非常重要的一环,在CVPR 2021论文中有不少的数据扩增方法,本文将对其中通用的论文进行介绍。
  • 计算机视觉入门CV之街道字符识别—02数据读取和数据扩增图像读取1.PIL库2.Opencv库数据扩增Pytorch实现 针对街道字符识别,利用Python和pytorch实现比赛中的数据读取和数据扩增。 图像读取 1.PIL库 from PIL import ...
  • 更准确的模型需要更多的数据,对于传统非神经网络机器学习方法,不同的特征需要有各自相符合的数据扩增方法。
  • 转载自:2021 AI技术盘点:预训练模型5大进展
  • Datawhale 零基础入门CV赛事-Task2 数据读取与数据扩增 文章目录1 数据读取与数据扩增2 常见的数据扩增方法2.1 读入并显示图片2.2 PyTorch数据增强(image transformations)2.2.1 Compose2.2.2 常见变化Resize标准...
  • 零基础入门语义分割-地表建筑物识别 Task2 数据扩增-学习笔记2 数据扩增方法2.1 学习目标2.2 常见的数据扩增方法2.3 OpenCV数据扩增2.4 albumentations数据扩增2.5 Pytorch数据读取2.6 本章小结2.7 课后作业 ...
  • 3.数据读取与数据扩增 主要内容为数据读取、数据扩增方法和Pytorch读取赛提数据。 3.1 图像读取 提供数据为图像数据,目的是识别图像中的字符,应先对需要完成对数据的读取操作,常见的有Pillow和OpenCV. 3.1.1 ...
  • 但是收集样本数据和标注往往是代价昂贵的,在有限的数据集上,通过数据增强技术可以增加训练的样本数量,获得一定程度上的性能提升。**数据增强(Data Augmentation)**是指在维持样本标签不变的条件下,根据先验知识...
  • 零基础入门CV赛事(二):数据读取与数据扩增 在上一章节,我们给大家讲解了赛题的内容和三种不同的解决方案。从本章开始我们将逐渐的学习使用【定长字符识别】思路来构建模型,逐步讲解赛题的解决方案和相应知识点...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,513
精华内容 1,405
关键字:

数据扩增训练模型