본문 바로가기
Study

[Computer Vision] Augmentation과 Normalization이 진행된 이미지를 시각화

by Hwanin99 2024. 8. 29.

개발 환경: Colab


Drive Mount

from google.colab import drive
drive.mount('/content/drive')

 


Import Module

import torch
import torchvision
from torchvision import transforms # 이미지 데이터 augmentation
import os
import glob

Pytorch 데이터셋 클래스

1. 파이토치 데이터셋 클래스 만들기

  • 파이토치 데이터셋 클래스는 init, getitem,len 이렇게 특수 메소드 3개를 요구한다.
    • 항상 같은 포맷을 만드는 습관이 중요하다.
    • 따라서 root_path, mode(train/val/test), transform(전처리&Augmentation) 3개의 입력을 받아 data와 label을 출력하는 클래스를 만들도록 하자.
from torch.utils.data import Dataset, DataLoader
import cv2
import os

class Custom_dataset(Dataset):
  def __init__(self, root_path, mode, transforms):
    self.all_data = sorted( glob.glob( os.path.join(root_path, mode, '*', '*') ) ) # 전체 경로
    self.transforms = transforms

  def __getitem__(self, index):
    if torch.is_tensor(index): # 인덱스가 tensor형태일 수 있는 것을 방지
      index = index.tolist()

    data_path = self.all_data[index] # 인덱스가 부여된 데이터 1개
    image = cv2.imread(data_path)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # cv2 라이브러리의 BGR 형식을 RGB로 permute

    # transfrom 적용
    if self.transforms is not None:
      augmentation = self.transforms(image = image)
      image = augmentation['image']

    # 이미지의 이름을 이용하여, label 부여하기
    if 'dolphin' in data_path:
      label = 0
    elif 'shark' in data_path:
      label = 1
    else:
      label = 2

    return image, label

  def __len__(self):
    length = len(self.all_data)
    return length

2. 전처리와 Augmentation을 적용

  • Normalize
    • 픽셀 값에 대해 (X-mean)/std를 진행하며, 이때 통계값은 ImageNet 데이터셋의 RGB 통계값을 이용할 예정이다.
  • 텐서화
    • 파이토치는 tensor 자료형을 이용하므로 totensor를 해준다.
  • Augmentation
    • trainset에만 적용한다.
import albumentations as A
from albumentations.pytorch.transforms import ToTensorV2 # albumentations 텐서화 함수

train_transforms = A.Compose([
    A.Resize(224,224),
    A.Transpose(p=0.5),
    A.HorizontalFlip(p=0.5),
    A.VerticalFlip(p=0.5),
    A.ShiftScaleRotate(p=0.5),
    A.HueSaturationValue(hue_shift_limit=20, sat_shift_limit=20, val_shift_limit=20, p=0.5),
    A.RandomBrightnessContrast(brightness_limit=(-0.1,0.1), contrast_limit=(-0.1, 0.1), p=0.5),
    A.ChannelShuffle(),
    A.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225), max_pixel_value=255.0, always_apply=False, p=1.0), # 이미지넷 데이터셋 통계값으로 Normalize
    A.CoarseDropout(p=0.5),
    ToTensorV2()
])

test_transforms = A.Compose([
    A.Resize(224,224),
    A.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225), max_pixel_value=255.0, always_apply=False, p=1.0), # 텐서타입은 안해줌
    ToTensorV2() # Normalize를 먼저하고 tensor화를 진행해야한다.
])

### Pytorch 데이터 클래스 생성
train_class = Custom_dataset(root_path=root_path, mode='train', transforms=train_transforms)
valid_class = Custom_dataset(root_path=root_path, mode='valid', transforms=test_transforms)
test_class = Custom_dataset(root_path=root_path, mode='test', transforms=test_transforms)

### Pytorch BatchLoader 생성 (학습에 이용할 최종 dataloader)
from torch.utils.data import DataLoader as DataLoader

train_loader = DataLoader(train_class, batch_size=8, shuffle = True, num_workers=0)
valid_loader = DataLoader(valid_class, batch_size=8, shuffle = False, num_workers=0)
test_loader = DataLoader(test_class, batch_size=8, shuffle = False, num_workers=0)

응용

    • 원래 0~255 픽셀 값을 가진 돌고래 이미지는 Augmentation이 적용되어 (train_class[0][0]) 이미지가 변형되었다.
    • train_class[0][0] 데이터를 시각화할 수 있도록 시각화 라이브러리가 요구하는 numpy 타입의 올바른 이미지 데이터로 되돌리는 역함수를 만들어 시각화해보자.
train_class.all_data[0]  # train 전체에서 첫번째 이미지 경로
-----------------------
'/Your_path/train/dolphin/dolphin_000.jpg'
from PIL import Image as PILImage
PILImage.open(train_class.all_data[0])

원본 첫 번째 돌고래 이미지

train_class[0][0] # augmentation이 적용된 이미지(C,H,W)
-----------------
tensor([[[ 0.8104,  0.8104,  0.7077,  ..., -0.5767, -0.6965, -0.7993],
         [ 0.7077,  0.7077,  0.7762,  ..., -0.3027, -0.4568, -0.5424],
         [ 0.7419,  0.7419,  0.8104,  ..., -0.3541, -0.5082, -0.5938],
         ...,
         [-0.9192, -0.9363, -0.9705,  ..., -1.3815, -1.3644, -1.3644],
         [-0.9192, -0.9192, -0.9363,  ..., -1.3302, -1.3130, -1.2788],
         [-0.9020, -0.9020, -0.9363,  ..., -1.3302, -1.3130, -1.2788]],

        [[ 1.8333,  1.8333,  1.7633,  ...,  0.9755,  0.8704,  0.7479],
         [ 1.7458,  1.7633,  1.8333,  ...,  1.2731,  1.1331,  1.0105],
         [ 1.8158,  1.8333,  1.9209,  ...,  1.2556,  1.1331,  1.0105],
         ...,
         [ 1.0105,  1.0105,  0.9930,  ...,  0.8179,  0.8179,  0.8179],
         [ 0.9755,  0.9580,  0.9930,  ...,  0.8179,  0.8354,  0.8354],
         [ 0.9755,  0.9580,  0.9930,  ...,  0.8179,  0.8354,  0.8354]],

        [[ 2.4831,  2.4657,  2.3437,  ...,  2.0300,  1.8905,  1.7860],
         [ 2.4483,  2.4134,  2.4657,  ...,  2.3088,  2.1694,  2.0823],
         [ 2.5703,  2.5529,  2.5877,  ...,  2.3437,  2.1868,  2.0997],
         ...,
         [ 2.2043,  2.2217,  2.2391,  ...,  2.1694,  2.1868,  2.1868],
         [ 2.1694,  2.2043,  2.2217,  ...,  2.2043,  2.2217,  2.2217],
         [ 2.1694,  2.1868,  2.2217,  ...,  2.2043,  2.2217,  2.2217]]])

  • 시각화 라이브러리로는 matplot을 사용할 것이다.
    • format을 (c,h,w)에서 (h,w,c)로 바꿔준다.
    • tensort에서 array 형태로 바꿔준다.
image = train_class[0][0].permute(1, 2, 0).numpy()
image
--------------------------------------------------
array([[[-0.6280504 ,  2.3060224 ,  0.44392157],
        [-0.6622999 ,  2.3060224 ,  0.4264924 ],
        [-0.6622999 ,  2.3410363 ,  0.44392157],
        ...,
        [ 1.1186745 ,  2.4285712 ,  1.8556863 ],
        [ 1.1015497 ,  2.4285712 ,  1.8208278 ],
        [ 1.2042983 ,  2.4285712 ,  1.9602615 ]],
        
       [[-1.0561693 ,  2.3585434 ,  0.16505449],
        [-1.0561693 ,  2.3585434 ,  0.16505449],
        [-1.141793  ,  2.3235292 ,  0.09533771],
        ...,
        [-0.31980482,  2.2359943 ,  0.6705011 ],
        [-0.25130582,  2.2184873 ,  0.70535946],
        [-0.54242665,  1.9033612 ,  0.4090632 ]]], dtype=float32)

 

  • 위의 image를 unnormalize해준다.
    • normalize의 역순으로 계산하면 된다.
# unnormalize
mean=(0.485, 0.456, 0.406)
std=(0.229, 0.224, 0.225)

augmentation_img=(((image * std)+mean)*255).astype(int)
augmentation_img
-------------------------------------------------------
array([[[ 23, 148, 221],
        [ 29, 141, 220],
        [ 26, 141, 217],
        ...,
        [ 77, 156, 217],
        [ 91, 169, 232],
        [106, 183, 245]],

       [[ 29,  55,  74],
        [ 30,  57,  77],
        [ 31,  59,  80],
        ...,
        [119, 191, 233],
        [137, 207, 247],
        [143, 213, 253]]])

왼쪽은 normalize된 이미지, 오른쪽은 unnormalize된 이미지


역함수 로직

  • 1. (C,H,W) → (H,W,C)
  • 2. Tensor → Array
  • 3. Unnormalize
    • $  ((\text{Image} \times \text{std}) + \text{mean}) \times 255 $
  • 4. Float → Int
def converter(augmentationed_image):
  mean=(0.485, 0.456, 0.406)
  std=(0.229, 0.224, 0.225)

  ### 역함수 로직을 짜주세요. ###
  augmentationed_image = augmentationed_image.permute(1,2,0) # 채널축 정상적으로 맨뒤로 보내기
  augmentationed_image = augmentationed_image.numpy() # numpy 타입으로 변환
  augmentationed_image = (augmentationed_image * std) + mean # unnormalize
  converted_image = augmentationed_image * 255
  converted_image = converted_image.astype(int)

  return converted_image