• 【记录】数据处理方法总结及实现


    【记录】数据处理方法总结及实现

    背景

    数据增强作为前处理的关键步骤,在整个计算机视觉中有着具足轻重的地位;

    数据增强往往是决定数据集质量的关键,主要用于数据增广,在基于深度学习的任务中,数据的多样性和数量往往能够决定模型的上限;

    本次记录主要是对数据增强中一些方法的源码实现;

    常用数据增强方法

    首先如果是使用Pytorch框架,其内部的torchvision已经包装好了数据增强的很多方法;

    from torchvision import transforms
    
    data_aug = transforms.Compose[
        transforms.Resize(size=240),
        transforms.RandomHorizontalFlip(0.5),
        transforms.ToTensor()
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    接下来自己实现一些主要的方法;

    常见的数据增强方法有:Compose、RandomHflip、RandomVflip、Reszie、RandomCrop、Normalize、Rotate、RandomRotate

    1、Compose

    作用:对多个方法的排序整合,并且依次调用;

    # 排序(compose)
    class Compose(object):
        def __init__(self, transforms):
            self.transforms = transforms
        def __call__(self, img):
            for t in self.transforms:
                img = t(img)	# 通过循环不断调用列表中的方法
            return img
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2、RandomHflip

    作用:随机水平翻转;

    # 随机水平翻转(random h flip)
    class RandomHflip(object):
        def __call__(self, image):
            if random.randint(2):
                return cv2.flip(image, 1)
            else:
                return image
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    通过随机数0或1,实现对图像可能反转或不翻转;

    3、RandomVflip

    作用:随机垂直翻转

    class RandomVflip(object):
        def __call__(self, image):
            if random.randint(2):
                return cv2.flip(image, 0)
            else:
                return image
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4、RandomCrop

    作用:随机裁剪;

    # 缩放(scale)
    def scale_down(src_size, size):
        w, h = size
        sw, sh = src_size
        if sh < h:
            w, h = float(w * sh) / h, sh
        if sw < w:
            w, h = sw, float(h * sw) / w
        return int(w), int(h)
        
    # 固定裁剪(fixed crop)
    def fixed_crop(src, x0, y0, w, h, size=None):
        out = src[y0:y0 + h, x0:x0 + w]
        if size is not None and (w, h) != size:
            out = cv2.resize(out, (size[0], size[1]), interpolation=cv2.INTER_CUBIC)
        return out
    
    # 随机裁剪(random crop)
    class RandomCrop(object):
        def __init__(self, size):
            self.size = size
        def __call__(self, image):
            h, w, _ = image.shape
            new_w, new_h = scale_down((w, h), self.size)
            if w == new_w:
                x0 = 0
            else:
                x0 = random.randint(0, w - new_w)
            if h == new_h:
                y0 = 0
            else:
                y0 = random.randint(0, h - new_h)
    
            out = fixed_crop(image, x0, y0, new_w, new_h, self.size)
            return out
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    5、Normalize

    作用:对图像数据进行正则化,也就是减均值除方差的作用;

    # 正则化(normalize)
    class Normalize(object):
        def __init__(self,mean, std):
            '''
            :param mean: RGB order
            :param std:  RGB order
            '''
            self.mean = np.array(mean).reshape(3,1,1)
            self.std = np.array(std).reshape(3,1,1)
        def __call__(self, image):
            '''
            :param image:  (H,W,3)  RGB
            :return:
            '''
            return (image.transpose((2, 0, 1)) / 255. - self.mean) / self.std
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    6、Rotate

    作用:对图像进行旋转;

    # 旋转(rotate)
    def rotate_nobound(image, angle, center=None, scale=1.):
        (h, w) = image.shape[:2]
        # if the center is None, initialize it as the center of the image
        if center is None:
            center = (w // 2, h // 2)    # perform the rotation
        M = cv2.getRotationMatrix2D(center, angle, scale)	# 这里是实现得到旋转矩阵
        rotated = cv2.warpAffine(image, M, (w, h))			# 通过矩阵进行仿射变换
        return rotated
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    7、RandomRotate

    作用:随机旋转,广泛适用于图像增强;

    # 随机旋转(random rotate)
    class FixRandomRotate(object):
    	# 这里的随机旋转是指在0、90、180、270四个角度下的
        def __init__(self, angles=[0,90,180,270], bound=False):
            self.angles = angles
            self.bound = bound
    
        def __call__(self,img):
            do_rotate = random.randint(0, 4)
            angle=self.angles[do_rotate]
            if self.bound:
                img = rotate_bound(img, angle)
            else:
                img = rotate_nobound(img, angle)
            return img
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    8、Resize

    作用:实现缩放;

    # 大小重置(resize)
    class Resize(object):
        def __init__(self, size, inter=cv2.INTER_CUBIC):
            self.size = size
            self.inter = inter
    
        def __call__(self, image):
            return cv2.resize(image, (self.size[0], self.size[0]), interpolation=self.inter)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    其他数据增强方法

    其他一些数据增强的方法大部分是特殊的裁剪;

    1、中心裁剪

    # 中心裁剪(center crop)
    def center_crop(src, size):
        h, w = src.shape[0:2]
        new_w, new_h = scale_down((w, h), size)
    
        x0 = int((w - new_w) / 2)
        y0 = int((h - new_h) / 2)
    
        out = fixed_crop(src, x0, y0, new_w, new_h, size)
        return out
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2、随机亮度增强

    # 随机亮度增强(random brightness)
    class RandomBrightness(object):
        def __init__(self, delta=10):
            assert delta >= 0
            assert delta <= 255
            self.delta = delta
    
        def __call__(self, image):
            if random.randint(2):
                delta = random.uniform(-self.delta, self.delta)
                image = (image + delta).clip(0.0, 255.0)
                # print('RandomBrightness,delta ',delta)
            return image
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3、随机对比度增强

    # 随机对比度增强(random contrast)
    class RandomContrast(object):
        def __init__(self, lower=0.9, upper=1.05):
            self.lower = lower
            self.upper = upper
            assert self.upper >= self.lower, "contrast upper must be >= lower."
            assert self.lower >= 0, "contrast lower must be non-negative."
    
        # expects float image
        def __call__(self, image):
            if random.randint(2):
                alpha = random.uniform(self.lower, self.upper)
                # print('contrast:', alpha)
                image = (image * alpha).clip(0.0,255.0)
            return image
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4、随机饱和度增强

    # 随机饱和度增强(random saturation)
    class RandomSaturation(object):
        def __init__(self, lower=0.8, upper=1.2):
            self.lower = lower
            self.upper = upper
            assert self.upper >= self.lower, "contrast upper must be >= lower."
            assert self.lower >= 0, "contrast lower must be non-negative."
    
        def __call__(self, image):
            if random.randint(2):
                alpha = random.uniform(self.lower, self.upper)
                image[:, :, 1] *= alpha
                # print('RandomSaturation,alpha',alpha)
            return image
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4、边界扩充

    # 边界扩充(expand border)
    class ExpandBorder(object):
        def __init__(self,  mode='constant', value=255, size=(336,336), resize=False):
            self.mode = mode
            self.value = value
            self.resize = resize
            self.size = size
    
        def __call__(self, image):
            h, w, _ = image.shape
            if h > w:
                pad1 = (h-w)//2
                pad2 = h - w - pad1
                if self.mode == 'constant':
                    image = np.pad(image, ((0, 0), (pad1, pad2), (0, 0)),
                                   self.mode, constant_values=self.value)
                else:
                    image = np.pad(image,((0,0), (pad1, pad2),(0,0)), self.mode)
            elif h < w:
                pad1 = (w-h)//2
                pad2 = w-h - pad1
                if self.mode == 'constant':
                    image = np.pad(image, ((pad1, pad2),(0, 0), (0, 0)),
                                   self.mode,constant_values=self.value)
                else:
                    image = np.pad(image, ((pad1, pad2), (0, 0), (0, 0)),self.mode)
            if self.resize:
                image = cv2.resize(image, (self.size[0], self.size[0]),interpolation=cv2.INTER_LINEAR)
            return image
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    当然还有很多其他数据增强的方式,在这里就不继续做说明了;

    拓展

    除了可以使用Pytorch中自带的数据增强包之外,也可以使用imgaug这个包(一个基于数据处理的包、包含大量的数据处理方法,并且代码完全开源)

    代码地址:https://github.com/aleju/imgaug

    说明文档:https://imgaug.readthedocs.io/en/latest/index.html

    强烈建议大家看看这个说明文档,其中的很多数据处理方法可以快速的应用到实际项目中,也可以加深对图像处理的理解;

  • 相关阅读:
    PM 的个人核心竞争力
    云计算的下一个飞跃:容器编排与Kubernetes最新趋势解析
    7/26 思维+dp+后缀数组的学习
    Shell编程——正则表达式
    【深入理解C++】可调用对象、std::function、std::bind()
    DSP28335学习记录(三)——ePWM
    灰狼算法Grey Wolf Optimizer跑23个经典测试函数|含源码
    知乎日报第四周总结
    B. Remove Prefix
    Postman使用总结
  • 原文地址:https://blog.csdn.net/weixin_40620310/article/details/126875826