美文网首页
Task2 数据读取与数据增广

Task2 数据读取与数据增广

作者: 蔓藤树下的甜蜜 | 来源:发表于2020-05-23 19:42 被阅读0次

    1、数据的读取

    1.1 对于图片的读取,一般计算机视觉领域常用的是opencv和pillow。

    对于pillow库我用的比较少,所以我这里就介绍一下opencv库。opencv是Intel开源的计算机视觉库,它是由一系列c函数和少量的c++类构成,实现了图像处理和计算机视觉方面的很多通用算法。opencv拥有包括300多个c函数的跨平台的中、高层API。它不依赖于其它的外部库-尽管可以使用某些外部库。最重要的是opencv对于商业和非商业都是free的。它同时支持linux,windows,android平台,提供有python,c,c++,java的接口函数。
    关于opencv的python接口函数的读取处理数据的简单用法,见下图:


    图片.png

    1.2 pytorch对于图片数据的读取操作代码示例:

    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])
            ]))
    

    2、数据的增广

    数据增广是深度学习中常用的技巧之一,主要用于增加训练集,让数据尽可能的多样化,使得训练的模型具有更强的泛化能力。现有的各大深度学习框架都已经自带了数据增广,它只是提供了接口函数。现在我们从:水平/垂直翻转,旋转,缩放,裁剪,剪切,平移,对比度,色彩抖动,噪声等几个方面讲解和实现数据增广。
    所有的数据增广在操作的时候默认是以图像中心点进行的。从数学角度来看,任何操作都可以分成以下几个步骤:1、首先将旋转点移动到原点处;2、执行如下图所描述的绕原点旋转;3、再将旋转点移回到原来的位置;为了更好的理解见下图:

    图片.png

    假设图像的原始坐标为(x1,y1),平移后的坐标为(x,y),则平移前和平移后的坐标关系为:
    \begin{matrix} \left[\begin{array}{rr} x \\ y \\ 1 \end{array}\right] & = H& \left[\begin{array}{rr} x1 \\ y1 \\ 1 \end{array}\right] \end{matrix}

    2.1、图像平移

    平移是指所有的像素在x和y方向各平移一定距离,平移变换对应的数学矩阵为:
    \begin{matrix} & H= & \left[\begin{array}{rr} 1&0&dx \\ 0&1&dy\\ 0&0&1 \end{array}\right] \end{matrix}
    如图平移的具体实例(这里平移采用的是到映射填充)

    图片.png

    2.2、图像翻转(图像镜像)

    图像翻转包括水平翻转和垂直翻转。水平翻转的变换矩阵为:
    \begin{matrix} & H= & \left[\begin{array}{rr} -1&0&0 \\ 0&1&0\\ 0&0&1 \end{array}\right] \end{matrix}
    垂直翻转的变换矩阵为:
    \begin{matrix} & H= & \left[\begin{array}{rr} 1&0&0 \\ 0&-1&0\\ 0&0&1 \end{array}\right] \end{matrix}
    翻转后的具体实例(这里是采用倒映射填充):

    图片.png

    2.3、图像旋转

    图像旋转是指以某个点(默认为图像中心点)为中心进行任意角度旋转,其变换矩阵为:
    \begin{matrix} & H= & \left[\begin{array}{rr} \cos\theta&-\sin\theta&0 \\ \sin\theta&\cos\theta&0\\ 0&0&1 \end{array}\right] \end{matrix}
    图像旋转图片(这里平移后采用的是到映射填充):

    图片.png

    2.4、图像缩放:

    图像缩放是指对当前图像进行任意尺度的缩放,其变换矩阵为:

    \begin{matrix} & H= & \left[\begin{array}{rr} Sx&0&0 \\ 0&Sy&0\\ 0&0&1 \end{array}\right] \end{matrix}
    缩放后的图片如下(这里平移后采用的是到映射填充):

    图片.png

    2.5、图像错切:

    其变换矩阵为:
    \begin{matrix} & H= & \left[\begin{array}{rr} 1&SHy&0 \\ SHx&1&0\\ 0&0&1 \end{array}\right] \end{matrix}
    错切的图像如下(这里平移后采用的到映射填充):

    图片.png

    2.6、图像裁剪:

    深度学习的图像裁剪的常用做法是将图片缩放到原图的1.1倍,然后在缩放后的图像上进行裁剪操作,具体的裁剪实例如下:


    图片.png

    2.7、组合变换:

    在深度学习中的数据增广一般会采用多种增广的方式的组合,根据其运算的规则,可以知道不同的组合顺序结果是不一样的。
    为了更好地解释,假设给定平移变换矩阵Hshift ,旋转矩阵Hrotate,缩放矩阵Hscale ,为了说明这里我给出两个不同的组合变换.对于组合变换一,其组合后的矩阵如下:M = Hshift x Hrotate x Hscale;对于组合变换二,其组合后的矩阵如下:M = Hscale x Hrotate x Hshift,对于两种不同的组合其结果如下:

    图片.png

    下边是数据增广的源码实现示例:

    import numpy as np
    import os
    import cv2
    import copy
    
    
    class DataAugment:
        def __init__(self,debug=False):
            self.debug=debug
            print("Data augment...")
    
        def basic_matrix(self,translation):
            """基础变换矩阵"""
            return np.array([[1,0,translation[0]],[0,1,translation[1]],[0,0,1]])
    
        def adjust_transform_for_image(self,img,trans_matrix):
            """根据图像调整当前变换矩阵"""
            transform_matrix=copy.deepcopy(trans_matrix)
            height, width, channels = img.shape
            transform_matrix[0:2, 2] *= [width, height]
            center = np.array((0.5 * width, 0.5 * height))
            transform_matrix = np.linalg.multi_dot([self.basic_matrix(center), transform_matrix, self.basic_matrix(-center)])
            return transform_matrix
    
        def apply_transform(self,img,transform):
            """仿射变换"""
            output = cv2.warpAffine(img, transform[:2, :], dsize=(img.shape[1], img.shape[0]),flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT, borderValue=0,)   #cv2.BORDER_REPLICATE,cv2.BORDER_TRANSPARENT
            return output
    
        def apply(self,img,trans_matrix):
            """应用变换"""
            tmp_matrix=self.adjust_transform_for_image(img, trans_matrix)
            out_img=self.apply_transform(img, tmp_matrix)
            if self.debug:
                self.show(out_img)
            return out_img
    
        def random_vector(self,min,max):
            """生成范围矩阵"""
            min=np.array(min)
            max=np.array(max)
            print(min.shape,max.shape)
            assert min.shape==max.shape
            assert len(min.shape) == 1
            return np.random.uniform(min, max)
    
        def show(self,img):
            """可视化"""
            cv2.imshow("outimg",img)
            cv2.waitKey()
    
        def random_transform(self,img,min_translation,max_translation):
            """平移变换"""
            factor=self.random_vector(min_translation,max_translation)
            trans_matrix=np.array([[1, 0, factor[0]],[0, 1, factor[1]],[0, 0, 1]])
            out_img=self.apply(img,trans_matrix)
            return trans_matrix, out_img
    
        def random_flip(self,img,factor):
            """水平或垂直翻转"""
            flip_matrix = np.array([[factor[0], 0, 0],[0, factor[1], 0],[0, 0, 1]])
            out_img=self.apply(img,flip_matrix)
            return flip_matrix, out_img
    
        def random_rotate(self,img,factor):
            """随机旋转"""
            angle=np.random.uniform(factor[0],factor[1])
            print("angle:{}".format(angle))
            rotate_matrix=np.array([[np.cos(angle), -np.sin(angle), 0],[np.sin(angle),np.cos(angle), 0],[0, 0, 1]])
            out_img=self.apply(img,rotate_matrix)
            return rotate_matrix, out_img
    
        def random_scale(self,img,min_translation,max_translation):
            """随机缩放"""
            factor=self.random_vector(min_translation, max_translation)
            scale_matrix = np.array([[factor[0], 0, 0],[0, factor[1], 0],[0, 0, 1]])
            out_img=self.apply(img,scale_matrix)
            return scale_matrix, out_img
    
        def random_shear(self,img,factor):
            """随机剪切,包括横向和众向剪切"""
            angle = np.random.uniform(factor[0], factor[1])
            print("fc:{}".format(angle))
            crop_matrix = np.array([[1, factor[0], 0], [factor[1], 1, 0], [0, 0, 1]])
            out_img=self.apply(img,crop_matrix)
            return crop_matrix, out_img
    
    
    if __name__=="__main__":
        demo=DataAugment(debug=True)
        img=cv2.imread("/pathto/dataArgu/wr.jpg")
    
        # 平移测试
        _,outimg=demo.random_transform(img,(0.1,0.1),(0.2,0.2))  #(-0.3,-0.3),(0.3,0.3)
    
    
       # 垂直变换测试
       _, outimg =demo.random_flip(img,(1.0,-1.0))
    
      # 水平变换测试
      _, outimg =demo.random_flip(img, (-1.0, 1.0))
    
    
       # 旋转变换测试
        _, outimg =demo.random_rotate(img,(0.5,0.8))
    
        # # 缩放变换测试
        _, outimg =demo.random_scale(img,(1.2, 1.2),(1.3,1.3))
    
        # 随机裁剪测试
        _, outimg =demo.random_shear(img,(0.2,0.3))
    
        # 组合变换
        t1,_=demo.random_transform(img,(-0.3,-0.3),(0.3,0.3))
        t2,_=demo.random_rotate(img,(0.5,0.8))
        t3,_=demo.random_scale(img,(1.5,1.5),(1.7,1.7))
        tmp=np.linalg.multi_dot([t1,t2,t3])
        print("tmp:{}".format(tmp))
        out=demo.apply(img,tmp)
    

    3、总结

    图片数据读取和数据增广是计算机视觉,特别是搞深度学习的最最基础的部分了,可能对于没有cv基础的同学理解起来会有点困难。

    参考链接:
    https://zhuanlan.zhihu.com/p/43665254

    相关文章

      网友评论

          本文标题:Task2 数据读取与数据增广

          本文链接:https://www.haomeiwen.com/subject/pyelahtx.html