Pytorch圖像處理中數(shù)據(jù)擴(kuò)增方案

原文來源:https://github.com/datawhalechina/team-learning-cv/blob/master/AerialImageSegmentation/Task2%EF%BC%9A%E6%95%B0%E6%8D%AE%E6%89%A9%E5%A2%9E%E6%96%B9%E6%B3%95.md

零基礎(chǔ)入門語義分割-Task2 數(shù)據(jù)擴(kuò)增

本章對語義分割任務(wù)中常見的數(shù)據(jù)擴(kuò)增方法進(jìn)行介紹,并使用OpenCV和albumentations兩個(gè)庫完成具體的數(shù)據(jù)擴(kuò)增操作。

2 數(shù)據(jù)擴(kuò)增方法

本章主要內(nèi)容為數(shù)據(jù)擴(kuò)增方法、OpenCV數(shù)據(jù)擴(kuò)增、albumentations數(shù)據(jù)擴(kuò)增和Pytorch讀取賽題數(shù)據(jù)四個(gè)部分組成。

2.1 學(xué)習(xí)目標(biāo)

  • 理解基礎(chǔ)的數(shù)據(jù)擴(kuò)增方法
  • 學(xué)習(xí)OpenCV和albumentations完成數(shù)據(jù)擴(kuò)增
  • Pytorch完成賽題讀取

2.2 常見的數(shù)據(jù)擴(kuò)增方法

數(shù)據(jù)擴(kuò)增是一種有效的正則化方法,可以防止模型過擬合,在深度學(xué)習(xí)模型的訓(xùn)練過程中應(yīng)用廣泛。數(shù)據(jù)擴(kuò)增的目的是增加數(shù)據(jù)集中樣本的數(shù)據(jù)量,同時(shí)也可以有效增加樣本的語義空間。

需注意:

  1. 不同的數(shù)據(jù),擁有不同的數(shù)據(jù)擴(kuò)增方法;

  2. 數(shù)據(jù)擴(kuò)增方法需要考慮合理性,不要隨意使用;

  3. 數(shù)據(jù)擴(kuò)增方法需要與具體任何相結(jié)合,同時(shí)要考慮到標(biāo)簽的變化;

對于圖像分類,數(shù)據(jù)擴(kuò)增方法可以分為兩類:

  1. 標(biāo)簽不變的數(shù)據(jù)擴(kuò)增方法:數(shù)據(jù)變換之后圖像類別不變;
  2. 標(biāo)簽變化的數(shù)據(jù)擴(kuò)增方法:數(shù)據(jù)變換之后圖像類別變化;

而對于語義分割而言,常規(guī)的數(shù)據(jù)擴(kuò)增方法都會改變圖像的標(biāo)簽。如水平翻轉(zhuǎn)、垂直翻轉(zhuǎn)、旋轉(zhuǎn)90%、旋轉(zhuǎn)和隨機(jī)裁剪,這些常見的數(shù)據(jù)擴(kuò)增方法都會改變圖像的標(biāo)簽,即會導(dǎo)致地標(biāo)建筑物的像素發(fā)生改變。

2.3 OpenCV數(shù)據(jù)擴(kuò)增

OpenCV是計(jì)算機(jī)視覺必備的庫,可以很方便的完成數(shù)據(jù)讀取、圖像變化、邊緣檢測和模式識別等任務(wù)。為了加深各位對數(shù)據(jù)可做的影響,這里首先介紹OpenCV完成數(shù)據(jù)擴(kuò)增的操作。

# 首先讀取原始圖片
img = cv2.imread(train_mask['name'].iloc[0])
mask = rle_decode(train_mask['mask'].iloc[0])

plt.figure(figsize=(16, 8))
plt.subplot(1, 2, 1)
plt.imshow(img)

plt.subplot(1, 2, 2)
plt.imshow(mask)
# 垂直翻轉(zhuǎn)
plt.figure(figsize=(16, 8))
plt.subplot(1, 2, 1)
plt.imshow(cv2.flip(img, 0))

plt.subplot(1, 2, 2)
plt.imshow(cv2.flip(mask, 0))
# 水平翻轉(zhuǎn)
plt.figure(figsize=(16, 8))
plt.subplot(1, 2, 1)
plt.imshow(cv2.flip(img, 0))

plt.subplot(1, 2, 2)
plt.imshow(cv2.flip(mask, 0))
# 隨機(jī)裁剪
x, y = np.random.randint(0, 256), np.random.randint(0, 256)

plt.figure(figsize=(16, 8))
plt.subplot(1, 2, 1)
plt.imshow(img[x:x+256, y:y+256])

plt.subplot(1, 2, 2)
plt.imshow(mask[x:x+256, y:y+256])

2.4 albumentations數(shù)據(jù)擴(kuò)增

albumentations是基于OpenCV的快速訓(xùn)練數(shù)據(jù)增強(qiáng)庫,擁有非常簡單且強(qiáng)大的可以用于多種任務(wù)(分割、檢測)的接口,易于定制且添加其他框架非常方便。

albumentations也是計(jì)算機(jī)視覺數(shù)據(jù)競賽中最常用的庫:

與OpenCV相比albumentations具有以下優(yōu)點(diǎn):

  • albumentations支持的操作更多,使用更加方便;
  • albumentations可以與深度學(xué)習(xí)框架(Keras或Pytorch)配合使用;
  • albumentations支持各種任務(wù)(圖像分流)的數(shù)據(jù)擴(kuò)增操作

albumentations它可以對數(shù)據(jù)集進(jìn)行逐像素的轉(zhuǎn)換,如模糊、下采樣、高斯造點(diǎn)、高斯模糊、動態(tài)模糊、RGB轉(zhuǎn)換、隨機(jī)霧化等;也可以進(jìn)行空間轉(zhuǎn)換(同時(shí)也會對目標(biāo)進(jìn)行轉(zhuǎn)換),如裁剪、翻轉(zhuǎn)、隨機(jī)裁剪等。

import albumentations as A

# 水平翻轉(zhuǎn)
augments = A.HorizontalFlip(p=1)(image=img, mask=mask)
img_aug, mask_aug = augments['image'], augments['mask']

# 隨機(jī)裁剪
augments = A.RandomCrop(p=1, height=256, width=256)(image=img, mask=mask)
img_aug, mask_aug = augments['image'], augments['mask']

# 旋轉(zhuǎn)
augments = A.ShiftScaleRotate(p=1)(image=img, mask=mask)
img_aug, mask_aug = augments['image'], augments['mask']

albumentations還可以組合多個(gè)數(shù)據(jù)擴(kuò)增操作得到更加復(fù)雜的數(shù)據(jù)擴(kuò)增操作:

trfm = A.Compose([
    A.Resize(256, 256),
    A.HorizontalFlip(p=0.5),
    A.VerticalFlip(p=0.5),
    A.RandomRotate90(),
])

augments = trfm(image=img, mask=mask)
img_aug, mask_aug = augments['image'], augments['mask']
plt.figure(figsize=(16, 8))
plt.subplot(1, 2, 1)
plt.imshow(augments['image'])

plt.subplot(1, 2, 2)
plt.imshow(augments['mask'])aug

2.5 Pytorch數(shù)據(jù)讀取

由于本次賽題我們使用Pytorch框架講解具體的解決方案,接下來將是解決賽題的第一步使用Pytorch讀取賽題數(shù)據(jù)。在Pytorch中數(shù)據(jù)是通過Dataset進(jìn)行封裝,并通過DataLoder進(jìn)行并行讀取。所以我們只需要重載一下數(shù)據(jù)讀取的邏輯就可以完成數(shù)據(jù)的讀取。

  • Dataset:數(shù)據(jù)集,對數(shù)據(jù)進(jìn)行讀取并進(jìn)行數(shù)據(jù)擴(kuò)增;
  • DataLoder:數(shù)據(jù)讀取器,對Dataset進(jìn)行封裝并進(jìn)行批量讀??;

定義Dataset:

import torch.utils.data as D
class TianChiDataset(D.Dataset):
    def __init__(self, paths, rles, transform):
        self.paths = paths
        self.rles = rles
        self.transform = transform
        self.len = len(paths)

    def __getitem__(self, index):
        img = cv2.imread(self.paths[index])
        mask = rle_decode(self.rles[index])
        augments = self.transform(image=img, mask=mask)
        return self.as_tensor(augments['image']), augments['mask'][None]
   
    def __len__(self):
        return self.len

實(shí)例化Dataset:

trfm = A.Compose([
    A.Resize(IMAGE_SIZE, IMAGE_SIZE),
    A.HorizontalFlip(p=0.5),
    A.VerticalFlip(p=0.5),
    A.RandomRotate90(),
])

dataset = TianChiDataset(
    train_mask['name'].values,
    train_mask['mask'].fillna('').values,
    trfm
)

實(shí)例化DataLoder,批大小為10:

loader = D.DataLoader(
    dataset, batch_size=10, shuffle=True, num_workers=0)

2.6 其他數(shù)據(jù)擴(kuò)增方式

  1. 使用OpenCV完成圖像加噪數(shù)據(jù)擴(kuò)增
def gasuss_noise(image, path_out_gasuss, mean=0, var=0.001):
    '''
        添加高斯噪聲
        mean : 均值
        var : 方差
    '''
    image = np.array(image / 255, dtype=float)
    noise = np.random.normal(mean, var ** 0.5, image.shape)
    out = image + noise
    if out.min() < 0:
        low_clip = -1.
    else:
        low_clip = 0.
    out = np.clip(out, low_clip, 1.0)
    out = np.uint8(out * 255)
    cv.imwrite(path_out_gasuss, out)

  1. 使用OpenCV完成圖像旋轉(zhuǎn)數(shù)據(jù)擴(kuò)增;
def rotate(image, path_out_rotate):
    '''
        旋轉(zhuǎn)
    '''
    rows, cols = image.shape[:2]
    M = cv.getRotationMatrix2D((cols / 2, rows / 2), 10, 1)
    dst = cv.warpAffine(image, M, (cols, rows))
    cv.imwrite(path_out_rotate, dst)

  1. 使用albumentations其他的的操作完成擴(kuò)增操作

https://zhuanlan.zhihu.com/p/107399127

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容