Pytorch数据预处理——选择与自定义transforms(通过向图片上添加椒盐噪声、高斯噪声增来强数据的数据增强方法)

前言

这篇笔记是学习pytorch的数据预处理方式transforms,这篇笔记包括两个要点,第一是在已经选好transform方法transform1,transform2,transform3...,并且都设置好参数数的前提下,如何在每次迭代的时候选择不同组的transform方法或者使用不同的调用顺序,第二是如何自定义transform方法 ,虽然pytorch提供了很多transform方法,但有时可能也需要自己定义。本笔记提供了在图片上添加椒盐和高斯噪声 的数据增强方法。本笔记的知识框架主要来源于深度之眼,并依此作了内容的丰富拓展,拓展内容主要源自对torch文档的翻译理解,所用数据来源于网络。 

transform选择

  • transforms.RandomChoice()
torchvision.transforms.RandomChoice(transforms)

        transforms是一个由若干预处理方法组成的列表transforms=[transform1,transform2,transform3,.....],该方法就是随机从该列表中随机取一个方法来执行。 

   transforms.RandomChoice(
        [transforms.RandomGrayscale(1), transforms.ColorJitter(hue=0.5), transforms.RandomRotation(60, resample=2)]),
    transforms.ToTensor(),

在这里插入图片描述
图1.每次读入的图片都从灰度化、变色和旋转中随机选一种方法执行

  • transforms.RandomApply()
torchvision.transforms.RandomApply(transforms, p=0.5)

        依概率p执行transforms,并且执行时按照顺序执行其中每一个预处理方法。transforms是由若干预处理方法组成的list或者是tuple。 

   transforms.RandomApply([transforms.Pad(50, fill=(100, 130, 110)), transforms.RandomAffine(degrees=0, shear=40), transforms.RandomVerticalFlip(1)], 0.5),
   transforms.ToTensor(),

在这里插入图片描述
图2.每次读入的图片有0.5的概率按顺序执行拓展、仿射和翻转三个操作,有0.5的概率什么都不执行

  • transforms.RandomOrder()
torchvision.transforms.RandomOrder(transforms)

  按照随机的顺序执行transforms中每一个预处理方法,transforms是由若干预处理方法组成的list。 

  transforms.RandomOrder([transforms.Pad(100, fill=(100, 130, 110)), transforms.CenterCrop(200)]),
  transforms.ToTensor(),

在这里插入图片描述 

图2.每次读入的图片执行拓展和裁剪的先后顺序随机,顺序不同结果不同

transform方法自定义

 观察Pytorch提供的transform方法,我们会发现,每一个transform方法都有一个默认输入和一个默认输出,输入往往是PIL Image,输出往往也是PIL Image,当然有特例,比如随机擦除(输入是TenSor),ToTensor(输出是归一化张量)和Normalize(输入是张量)等。  

  以Resize为例,从以下源码中可以看出transform方法的基本代码结构。__init__ 中定义一些该类必要的其他参数,如概率p,标准差std,均值mean等。__call__() 中实现数据预处理方法,默认输入便是在这里使用的。大多数的transform方法的具体实现,都是直接调用的torchFunction里的函数,如这里的F.resize()。而在我们自定义预处理方法时,需要在这里自己写。

class Resize(object):

    def __init__(self, size, interpolation=Image.BILINEAR):
        assert isinstance(size, int) or (isinstance(size, Iterable) and len(size) == 2)
        self.size = size
        self.interpolation = interpolation

    def __call__(self, img):                # __call___,让类实例变成一个可以被调用的对象,像函数

        return F.resize(img, self.size, self.interpolation)

添加椒盐噪声
 

        椒盐噪声是脉冲噪声的特例,指灰度值很低或者灰度值很高的随机点噪声,在图像上就表现为很暗的点(椒)和很亮的点(盐)随机分布。用添加过椒盐噪声的数据集训练出来的模型,对被椒盐噪声污染的测试图像应该会更鲁棒。椒盐噪声的添加,根据想要的噪声密度density,在图像内随机的像素位置,对像素点赋值为0或255,彩色图赋(255,255,255)或者(0,0,0)。 

  噪声添加的基本实现,额外参数只有density,其需要在__init__定义,而__call__中则添加,向图片中随机撒椒盐的程序。

  撒椒、盐的密度(等于椒、盐出现的概率值)d = density/2.0
  信号密度(等于原图像像素出现的概率值)d = 1-density

  有了各种信号出现的概率,现在就需要根据概率值,随机的在图像上去选择点。用Numpy中的random.choice()函数产生掩膜mask来实现。

 random.choice()

numpy.random.choice(a, size=None, replace=True, p=None)

        a: 整型数值或者一维数组。为数字时,表示生成的mask中的值,是从np.arange(a)中根据概率p随机采样得到的。为一数组时,则表示生成的mask中的值,是随机选择数组中a中的一个值,选择概率由p中对应位置的概率值决定。
  size: 生成mask的大小或输出数组大小,为整型(一维)或者元组(多维)。
  replace: 为True时,输出数组中的元素可以重复,反之不可重复。
  pa中对应元素的概率,若没有给出,默认它们等概率。

import numpy as np
mask = np.random.choice(99, 100, replace=False)
print(mask)

        ValueError: Cannot take a larger sample than population when 'replace=False',replace=False时,a取值范围应该比size大。

  在添加椒盐噪声的应用中,共有三类点,只需要在mask中用三个值便可以区分,三个值的概率分别就是椒、盐和原像素出现的概率。类似如下代码:

mask = np.random.choice((0, 1, 2), size=(224, 224, 1), p=[0.1, 0.1, 0.8])

        my_transforms.py

import numpy as np
from PIL import Image


class AddSaltPepperNoise(object):

    def __init__(self, density=0):
        self.density = density

    def __call__(self, img):

        img = np.array(img)                                                             # 图片转numpy
        h, w, c = img.shape
        Nd = self.density
        Sd = 1 - Nd
        mask = np.random.choice((0, 1, 2), size=(h, w, 1), p=[Nd/2.0, Nd/2.0, Sd])      # 生成一个通道的mask
        mask = np.repeat(mask, c, axis=2)                                               # 在通道的维度复制,生成彩色的mask
        img[mask == 0] = 0                                                              # 椒
        img[mask == 1] = 255                                                            # 盐
        img= Image.fromarray(img.astype('uint8')).convert('RGB')                        # numpy转图片
        return img

        调用:

 my_transforms.AddSaltPepperNoise(0.2),
 transforms.ToTensor(),

        结果:

椒盐噪声

 图3.添加密度为0.2的椒盐噪声
  

添加高斯噪声
  

        高斯噪声,即分布服从正态分布的噪声,是一种非常常见的噪声,其叠加在图像的每一个点上。主要参数有方差、均值和幅值。用numpy.random.normal函数来产生服从高斯分布的噪声。 

在这里插入图片描述

  random.normal()

numpy.random.normal(loc=0.0, scale=1.0, size=None)  

       loc: 均值。浮点值或者数组
 scale:标准差。浮点值或者数组。
  size: 输出尺寸。整型值或者元组。

N = amplitude*numpy.random.normal(loc=mean, scale=variance, size=(224, 224, 1))  

在这里插入图片描述

图3.高斯噪声

 my_transforms.py 

class AddGaussianNoise(object):

    def __init__(self, mean=0.0, variance=1.0, amplitude=1.0):

        self.mean = mean
        self.variance = variance
        self.amplitude = amplitude

    def __call__(self, img):
        img = np.array(img)
        h, w, c = img.shape
        N = self.amplitude * np.random.normal(loc=self.mean, scale=self.variance, size=(h, w, 1))
        N = np.repeat(N, c, axis=2)
        img = N + img
        img[img > 255] = 255                       # 避免有值超过255而反转
        img = Image.fromarray(img.astype('uint8')).convert('RGB')
        return img

        主函数使用:

    my_transforms.AddGaussianNoise(mean=0, variance=1, amplitude=20),
    transforms.ToTensor(),

        结果:

高斯噪声

图3.添加幅值为20的标准高斯噪声
 

猜你喜欢

转载自blog.csdn.net/qq_45368632/article/details/124586826