将Albumentations用于语义分割任务

本文介绍了如何在语义分割任务中应用Albumentations,包括PadIfNeeded、CenterCrop、Crop等操作,以及非破坏性变换如HorizontalFlip、VerticalFlip和刚体变换如ElasticTransform、GridDistortion。展示了如何通过这些技巧增加数据多样性,提升模型泛化能力。
摘要由CSDN通过智能技术生成

将Albumentations用于语义分割任务

本文主要基于Using Albumentations for a semantic segmentation task的翻译修改,有少量修改,添加了一些个人理解批注。

Colab notebook示例
GitHub notebook示例

一些安装和数据获取的步骤,在此就不再赘述了。

import random

import cv2
import torch
from matplotlib import pyplot as plt

import albumentations as A

定义一个image和mask的可视化函数:

def visualize(image, mask, original_image=None, original_mask=None):
    fontsize = 18
    
    if original_image is None and original_mask is None:
        f, ax = plt.subplots(1, 2, figsize=(8, 8))

        ax[0].imshow(image)
        ax[1].imshow(mask)
    else:
        f, ax = plt.subplots(2, 2, figsize=(8, 8))

        ax[0, 0].imshow(original_image)
        ax[0, 0].set_title('Original image', fontsize=fontsize)
        
        ax[1, 0].imshow(original_mask)
        ax[1, 0].set_title('Original mask', fontsize=fontsize)
        
        ax[0, 1].imshow(image)
        ax[0, 1].set_title('Transformed image', fontsize=fontsize)
        
        ax[1, 1].imshow(mask)
        ax[1, 1].set_title('Transformed mask', fontsize=fontsize)
image = cv2.imread('data/1803151818-00000065.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) ### 
mask = cv2.imread('data/1803151818-00000065.png', cv2.IMREAD_GRAYSCALE) ### 
print(image.shape, mask.shape)
original_height, original_width = image.shape[:2]
(800, 600, 3) (800, 600)
visualize(image, mask) # 对原图像和mask的可视化

在这里插入图片描述

Padding

在 Unet 这样的网络架构中,输入图片的尺寸需要尺寸需要能被 2 N 2^N 2N 整除,其中 N N N 是池化层(maxpooling)的层数。在最简单的 Unet 结构中 N N N 的值为 5,那么我们就需要将输入的图片填充到能被 2 5 = 32 2^5=32 25=32 除尽的数字,这里取128。要进行此操作就需要用到 PadIfNeeded 类,这个方法在image和mask的四周填充,默认使用reflection padding.

关于仿射变换的理解可以看博主之前的文章 **图解pytorch padding方法 ReflectionPad2d**里面有一些图示可以帮助理解,这里就不再展开了,原理都一样。

# 本文使用的输入图片较大,
aug = A.PadIfNeeded(min_height=900, min_width=900, p=1)

augmented = aug(image=image, mask=mask)

image_padded = augmented['image']
mask_padded = augmented['mask']

print(image_padded.shape, mask_padded.shape)

visualize(image_padded, mask_padded, original_image=image, original_mask=mask)
(900, 900, 3) (900, 900)

在这里插入图片描述

CenterCrop and Crop

中心裁剪,裁剪。
这里用了crop来恢复之前的大小

aug = A.CenterCrop(p=1, height=original_height, width=original_width)

augmented = aug(image=image_padded, mask=mask_padded)

image_center_cropped = augmented['image']
mask_center_cropped = augmented['mask']

print(image_center_cropped.shape, mask_center_cropped.shape)

assert (image - image_center_cropped).sum() == 0
assert (mask - mask_center_cropped).sum() == 0

visualize(image_padded, mask_padded, original_image=image_center_cropped, original_mask=mask_center_cropped)
(800, 600, 3) (800, 600)

在这里插入图片描述

x_min = (900 - original_width) // 2
y_min = (900 - original_height) // 2

x_max = x_min + original_width
y_max = y_min + original_height

aug = A.Crop(x_min=x_min, x_max=x_max, y_min=y_min, y_max=y_max, p=1)

augmented = aug(image=image_padded, mask=mask_padded)

image_cropped = augmented['image']
mask_cropped = augmented['mask']

print(image_cropped.shape, mask_cropped.shape)

assert (image - image_cropped).sum() == 0
assert (mask - mask_cropped).sum() == 0

visualize(image_cropped, mask_cropped, original_image=image_padded, original_mask=mask_padded)
(800, 600, 3) (800, 600)

在这里插入图片描述

Non destructive transformations. Dehidral group D4

非破坏性转换
从上面的转换操作中可以看到操作破坏了图像的空间信息,对于想卫星、航空或者医学图片我们并不希望破坏它原有的空间结构,如以下的八种操作就不会破坏原有图片的空间结构。
image

通过 HorizontalFlip, VerticalFlip, Transpose, RandomRotate90 四种操作的组合就可以得到上面的八种操作。
主要是翻转,旋转之类的,在空间上转动,翻转,没有裁剪之类破坏图像内容的操作,所以叫做非破坏性转换。

# HorizontalFlip  水平翻转
aug = A.HorizontalFlip(p=1)

augmented = aug(image=image, mask=mask)

image_h_flipped = augmented['image']
mask_h_flipped = augmented['mask']

visualize(image_h_flipped, mask_h_flipped, original_image=image, original_mask=mask)

在这里插入图片描述

# VerticalFlip 垂直翻转
aug = A.VerticalFlip(p=1)

augmented = aug(image=image, mask=mask)

image_v_flipped = augmented['image']
mask_v_flipped = augmented['mask']

visualize(image_v_flipped, mask_v_flipped, original_image=image, original_mask=mask)

在这里插入图片描述

# RandomRotate90 (Randomly rotates by 0, 90, 180, 270 degrees) 随机旋转90
aug = A.RandomRotate90(p=1)

augmented = aug(image=image, mask=mask)

image_rot90 = augmented['image']
mask_rot90 = augmented['mask']

visualize(image_rot90, mask_rot90, original_image=image, original_mask=mask)

在这里插入图片描述

# Transpose (switch X and Y axis) 转置
aug = A.Transpose(p=1)

augmented = aug(image=image, mask=mask)

image_transposed = augmented['image']
mask_transposed = augmented['mask']

visualize(image_transposed, mask_transposed, original_image=image, original_mask=mask)

在这里插入图片描述

非刚体变换 Non-rigid transformations: ElasticTransform, GridDistortion, OpticalDistortion

在医学影像问题中非刚体装换可以帮助增强数据。albumentations 中主要提供了以下几种非刚体变换类: ElasticTransform, GridDistortion, OpticalDistortion.

例子里固定随机化种子是出于可视化的目的,固定随机种子数据增强可以生成相同的结果。在真是的计算机视觉pipeline中,在转换图像之前不应该固定随机种子,以防止pipeline总是输出相同的图片。数据增强的目的是为了每次使用不同的transformation

# 弹性装换
image41 = A.ElasticTransform(p=1, alpha=120, sigma=120 * 0.05, 
                          alpha_affine=120 * 0.03)(image=image, mask=mask)
image_elastic = image41['image']
mask_elastic = image41['mask']

# 网格畸变
image42 = A.GridDistortion(p=1, num_steps=10)(image=image, mask=mask)

image_grid = image42['image']
mask_grid = image42['mask']

# 光学畸变
image43 = A.OpticalDistortion(p=1, distort_limit=2, shift_limit=0.5)(image=image, mask=mask)

image_optical = image43['image']
mask_optical = image43['mask']

visualize(image_elastic, mask_elastic, original_image=image, original_mask=mask)
visualize(image_grid, mask_grid)
visualize(image_optical, mask_optical)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

多种变换组合

image5 = A.Compose([
   # 非刚体转换
    A.OneOf([A.RandomSizedCrop(min_max_height=(50, 101), 
                           height=original_height, width=original_width, p=0.5),
          A.PadIfNeeded(min_height=original_height, 
                      min_width=original_width, p=0.5)], p=1),
    # 非破坏性转换
    A.VerticalFlip(p=0.5),              
    A.RandomRotate90(p=0.5),
    # 非刚体转换
    A.OneOf([
        A.ElasticTransform(p=0.5, alpha=120, sigma=120 * 0.05, alpha_affine=120 * 0.03),
        A.GridDistortion(p=0.5),
        A.OpticalDistortion(p=1, distort_limit=2, shift_limit=0.5)                  
        ], p=0.8),
    # 非空间性转换
    A.CLAHE(p=0.8),
    A.RandomBrightnessContrast(p=0.8),    
    A.RandomGamma(p=0.8)])(image=image, mask=mask)

image_heavy = image5['image']
mask_heavy = image5['mask']

visualize(image_heavy, mask_heavy, original_image=image, original_mask=mask)

在这里插入图片描述

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值