• [딥러닝] 이미지 데이터 전처리

    2020. 11. 26.

    by. seo.0

    1. Data

    이전에 웹크롤링을 통해서 장롱 이미지 325장, 장롱이 아닌 이미지 325장의 데이터셋을 만들었다.

    ->train data(각 255장) : train_wardrobe, train_not_wardrobe

       test data(각 70장) : test_wardrobe, test_not_wardrobe

     

    kaggle이나 imagenet에서 장롱 이미지가 제공되지 않아 웹 크롤링을 통해서 이미지를 모았기 때문에 현재 데이터는 매우 부족하다. 그러나 신경망은 대량의 데이터가 공급될 때 성능이 훨씬 좋아지므로 현재 데이터셋을 증가시킬 필요가 있다.

     

    2. Data augmentation

    wardrobe, not_wardrobe에 각 20000장의 이미지를 얻으려 한다. 따라서 기존의 이미지들을 프로세싱해서 추가적인 데이터를 수집하려한다.

     

    우선 필요한 라이브러리들을 import하였다.

    import numpy as np
    import pandas as pd
    import os
    import tensorflow as tf
    rand_state=42
    tf.random.set_seed(rand_state)
    np.random.seed(rand_state)
    
    from skimage import exposure
    import cv2
    import glob
    import time
    import matplotlib.pyplot as plt
    from keras.utils.vis_utils import plot_model
    

     

    기존에 수집한 이미지 데이터를 불러오자.

    해당 이미지들은 구글 드라이브에 input 폴더에 저장하였으며, 구글 colob을 통해서 구글 드라이브를 마운트하여 실행하였다. 아래 코드를 통해 train data들을 장롱 이미지, 장롱이 아닌 이미지들을 나누어서 wardrobes, notWardrobes로 나누어 리스트를 만들었다.

    wardrobes = glob.glob('./drive/My Drive/input/train_wardrobe/*.jpg', recursive=True)
    notWardrobes = glob.glob('./drive/My Drive/input/train_not_wardrobe/*.jpg', recursive=True)

     

    이제 wardrobes, notWardrobes의 이미지들을 전처리하는 과정을 살펴보자.

     

    - Rotate image

    이미지를 평면상의 한 점을 중심으로 정해진 각도(angle)만큼 회전하는 변환이다.

    각도는 np.random.randint(0,360)을 통해서 랜덤으로 지정하였다.

    cv2.getRotationMatrix2D() 함수를 통해서 이미지의 중심 좌표를 (cols/2, rows/2)로 잡고 정해진 각도만큼 회전하는 변환행렬 M을 생성하고, 변환행렬 M을 cv2.warpAffine() 함수에 적용하여 이미지를 회전시킨다.

    (rows,cols,ch)=img.shape
    angle=np.random.randint(0,360)
    M=cv2.getRotationMatrix2D((cols/2, rows/2),angle,1)
    img=cv2.warpAffine(img,M,(cols,rows))

     

    - Blur image

    이미지를 블러처리하는 코드이다.

    cv2.blur() 함수에서 5*5의 필터 커널 사이즈를 지정해주고 블러처리를 하였다. 커널 사이즈가 클수록 이미지 전체가 블러처리가 많이 된다.

    img = cv2.blur(img,(5,5))

     

    - Resize image

    데이터의 이미지들이 제각기 다양한 크기를 가지는데 제대로된 모델 학습을 위해서는 모두 동일한 차원으로 만드는 과정이 필요하다.

    cv2.resize()를 이용해 imgSize로 이미지 크기를 재조정한다.

    이미지의 크기는 32*32로 표준화한다.

    size=32
    imgSize=(size, size)
    img = cv2.resize(img, imgSize)

     

    - Image class augmentation

    이미지들을 회전, 블러처리를 해서 x리스트에는 이미지를, y리스트에는 wardrobes에 대한 classLable '0'을 추가해주고, classSize만큼의 데이터가 모아질 때까지 이미지들을 회전, 블러처리하는 작업을 계속해서 데이터를 추가한다.

    notWardrobes 이미지에 대해서도 wardrobes와 마찬가지로 실행하여 20000개의 이미지를 만들고 classLable을 '1'로 설정해서 데이터를 만들어준다.

    classSize=20000
    x=[]
    y=[]
    
    for path in wardrobes:
      //img rotate, blur, resize
      x.append(img)
      y.append(0)
    
    while len(x) < classSize:
      //img=wardrobes[randIdx]
      //img rotate, blur, resize
      x.append(img)
      y.append(0)
            
    xWardrobe=x
    yWardrobe=y
    
    /*notWardrobes 도 마찬가지
    classLabe은 '1'
    
    */
    
    scaled_X=np.array(xWardrobe+xNotWardrobe)
    y=np.array(yWardrobe+yNotWardrobe)
    
    

     

     

    위와 같은 과정을 거쳐서 각 클래스에 대하여 20000장의 데이터를 얻었다.

     

    - Grayscale image

    현재 데이터 이미지는 컬러이미지로 구성되어 있다. 그러나 이미지 프로세싱에서 색상이 필요하지 않을 경우 노이즈라고 생각할 수 있으며, 엣지를 찾을 때 컬러 이미지를 그대로 사용할 경우 더 많은 일을 해야한다. 따라서 현재 컬러 이미지를 회색 이미지로 바꾸는 작업이 필요하다.

    아래의 공식은 RGB를 Grayscale로 변환할 때, opencv에서 제공하는 RGB에 각각 가중치를 둔 변환공식이다.

    images=0.2989*images[:,:,:,0] + 0.5870*images[:,:,:,1]+0.140*images[:,:,:,2]

     

    - Normalize image

    이미지의 히스토그램이 너무 특정영역에 집중되어 있으면 contrast가 낮아서 좋은 이미지라고 할 수 없다. 따라서 전체 영역으로 고르게 분포되어 있는 이미지가 필요한데 이러한 작업을 histogram equalization이라고 한다.

    총 40000만개의 이미지에 대해서 histogram equalization을 거쳐서 이미지를 반환해주는 작업을 거친다.

    images = (images / 255.).astype(np.float32)
    for i in range(images.shape[0]):
      images[i] = exposure.equalize_hist(images[i])
      images = images.reshape(images.shape + (1,)) 

     

    - Categorical

    classLable로 지정된 0과 1로 구성되어 있는 y 리스트를 카테고리화한다.

    from keras.utils.np_utils import to_categorical
    
    y=to_categorical(y)

     

    - Train/Validaton 분리

    모델에 train 데이터를 모두 학습시킨 후에 test 데이터에 모델을 적용했을 때 성능이 잘 안나오는 경우가 많다. 이러한 현상을 overfitting 되었다고 말하는데, 모델이 학습한 데이터에 너무 과적합되도록 학습을 해서 이에 조금이라도 벗어나면 예측율이 매우 떨어지는 현상을 말한다. 따라서 overfitting을 방지하는 것이 모델의 성능을 높이기 위한 매우 중요한 요소이다.

    따라서 train데이터와 test데이터로 구분되어 있는 데이터셋에서 train 데이터의 일부를 validation 데이터로 지정해주어 train 데이터로 모델을 학습하고 중간에 validation 데이터셋으로 학습한 모델을 평가해주는 과정을 추가하였다.

    모델이 과적합되었을 경우, validation 데이터셋으로 예측율이 떨어지는 것을 확인할 수 있다.

     

    train_test_split 함수를 통해 train/validation 셋으로 나눌 수 있다.

    이 함수에서 test_size는 테스트 셋 구성의 비율을 나타낸 것으로, test_size=0.2는 전체 데이터의 20%를 validation 셋으로 지정하겠다는 의미이다.

    또한 random_state는 데이터 분할 시에 셔플이 이루어지는데 이를 위한 시드값을 의미한다.

    이렇게 함수를 실행하면 X_train, X_test, y_train, y_test 이렇게 train과 validation 데이터셋이 분리가 된다.

    from sklearn.model_selection import train_test_split
    
    n_classes=2
    print("y shape", y.shape)
    X_train, X_test, y_train, y_test = train_test_split(scaled_X,y,test_size=0.2,random_state=rand_state)
    
    print("train shape X",X_train.shape)
    print("train shape y",y_train.shape)
    print("test shape X",X_test.shape)
    print("test shape y",y_test.shape)
    
    inputShape=(size,size,1)

    데이터의 train_test_split의 결과이다.

     

    이렇게 모델 학습을 위한 모든 이미지 데이터의 전처리 과정을 마쳤으며, 이제는 모델을 설계한 후 해당 데이터들을 이용하여 학습시킬 예정이다.

    댓글