머신러닝을 위해 데이터를 모으는 과정은 매우 중요합니다.
데이터를 모으기도 귀찮고, 원하는 이미지 데이터를 직접 잘라내는 일도 만만치 않은 작업입니다.
다행히 우리는 DATA Augmentation이라는 데이터 뻥튀기하는 방법을 알고 있습니다.
[DATA Augmentation이란?]
한정된 데이터를 적절한 작업을 통해 늘릴 수 있습니다.
우선 다음 사진을 보겠습니다.
인간의 눈으로 보면 위 사진은 같은 고양이를 약간 돌리거나 좌우 반전한 모습에 지나지 않습니다.
하지만 컴퓨터의 눈으로 위 사진을 본다면, 살짝 돌리거나 좌우 반전한 같은 고양이의 사진은 완전히 새로운 데이터가 될 것입니다. 컴퓨터는 이미지를 볼 때 세 개의 채널(RGB)로 나누고, 각 픽셀의 RGB농도를 조절하여 합치는 방식으로 데이터를 표현하니까요. 혹은 의도적인 노이즈를 추가해도 될 것입니다. 우리가 알아볼 정도의 노이즈 추가면 괜찮을 것 같습니다.
직접 구현해보았습니다. 우선 코드부터 보고, 설명 및 실행 결과까지 확인해 보겠습니다.
[코드 보기]
import random
import numpy as np
import os
import cv2
import glob
from PIL import Image
import PIL.ImageOps
#다음 변수를 수정하여 새로 만들 이미지 갯수를 정합니다.
num_augmented_images = 50
file_path = 'custom_data\Wonbin_faces\\'
file_names = os.listdir(file_path)
total_origin_image_num = len(file_names)
augment_cnt = 1
for i in range(1, num_augmented_images):
change_picture_index = random.randrange(1, total_origin_image_num-1)
print(change_picture_index)
print(file_names[change_picture_index])
file_name = file_names[change_picture_index]
origin_image_path = 'custom_data\Wonbin_faces\\' + file_name
print(origin_image_path)
image = Image.open(origin_image_path)
random_augment = random.randrange(1,4)
if(random_augment == 1):
#이미지 좌우 반전
print("invert")
inverted_image = image.transpose(Image.FLIP_LEFT_RIGHT)
inverted_image.save(file_path + 'inverted_' + str(augment_cnt) + '.png')
elif(random_augment == 2):
#이미지 기울이기
print("rotate")
rotated_image = image.rotate(random.randrange(-20, 20))
rotated_image.save(file_path + 'rotated_' + str(augment_cnt) + '.png')
elif(random_augment == 3):
#노이즈 추가하기
img = cv2.imread(origin_image_path)
print("noise")
row,col,ch= img.shape
mean = 0
var = 0.1
sigma = var**0.5
gauss = np.random.normal(mean,sigma,(row,col,ch))
gauss = gauss.reshape(row,col,ch)
noisy_array = img + gauss
noisy_image = Image.fromarray(np.uint8(noisy_array)).convert('RGB')
noisy_image.save(file_path + 'noiseAdded_' + str(augment_cnt) + '.png')
augment_cnt += 1
주피터 노트북을 통해 작성하였습니다.
깃허브에서 코드를 확인하실 수 있습니다. 훨씬 더 나은 방향으로 업데이트될 수 있습니다 :)
github.com/BUZZINGPolarBear/Why_Am_I_ALONE/blob/master/Image_Augmentation.ipynb
[코드 설명 보기]
import random
import numpy as np
import os
import cv2
import glob
from PIL import Image
import PIL.ImageOps
#다음 변수를 수정하여 새로 만들 이미지 갯수를 정합니다.
num_augmented_images = 50
윗 문단은 단순 import해주시면 됩니다.
아래 문단의 num_augmented_images는 새로 만들 이미지 개수를 정합니다. 만약 50장의 원본 사진이 폴더에 있고 num_augmentd_images를 30장으로 설정한다면, 최종적으로 폴더에는 80장의 이미지가 저장됩니다.
변수 이름 참 못 짓네요... 죄송합니다...
file_path = 'custom_data\Wonbin_faces\\'
file_names = os.listdir(file_path)
total_origin_image_num = len(file_names)
augment_cnt = 1
file_path에 원본 사진이 있는 폴더를 정해줍니다.
file_names에는 위의 폴더 내부에 있는 이미지 이름의 배열이 저장됩니다.
total_origin_image_num에는 file_names의 길이를 저장합니다. 만약 50장의 원본 이미지가 있다면, 이 변수는 50이 될 것입니다.
augment_cnt는 몇번의 augmentation이 일어났는지를 확인하기 위해 선언해 주었습니다.
for i in range(1, num_augmented_images):
change_picture_index = random.randrange(1, total_origin_image_num-1)
print(change_picture_index)
print(file_names[change_picture_index])
file_name = file_names[change_picture_index]
origin_image_path = 'custom_data\Wonbin_faces\\' + file_name
print(origin_image_path)
image = Image.open(origin_image_path)
random_augment = random.randrange(1,4)
for문은 두 파트로 나누어 설명하겠습니다.
이 부분은 원본 이미지와 Augmetation 방식을 모두 랜덤으로 설정하는 부분입니다.
change_picture_index로 전체 이미지 개수 중 하나를 랜덤 하게 선택하여 file_name에 그 인덱스를 갖는 이미지 이름을 저장합니다.
이제 origin_image_path에는 file_name에 저장해놓은 이름 덕분에 원본 이미지의 경로가 저장되어 있습니다.
image변수에는 이미지가 탑재됩니다.
random_augment 변수에는 1~3의 무작위 수가 결정됩니다.
1이 선택되었다면 : 원본 이미지를 좌우반전하여 원 폴더에 저장합니다.
2가 선택되었다면 : 원본 이미지를 랜덤하게 -20 ~ 20도 회전하여 원 폴더에 저장합니다.
3이 선택되었다면 : 원본 이미지에 가우스 노이즈를 추가하여 원 폴더에 저장합니다.
if(random_augment == 1):
#이미지 좌우 반전
print("invert")
inverted_image = image.transpose(Image.FLIP_LEFT_RIGHT)
inverted_image.save(file_path + 'inverted_' + str(augment_cnt) + '.png')
elif(random_augment == 2):
#이미지 기울이기
print("rotate")
rotated_image = image.rotate(random.randrange(-20, 20))
rotated_image.save(file_path + 'rotated_' + str(augment_cnt) + '.png')
elif(random_augment == 3):
#노이즈 추가하기
img = cv2.imread(origin_image_path)
print("noise")
row,col,ch= img.shape
mean = 0
var = 0.1
sigma = var**0.5
gauss = np.random.normal(mean,sigma,(row,col,ch))
gauss = gauss.reshape(row,col,ch)
noisy_array = img + gauss
noisy_image = Image.fromarray(np.uint8(noisy_array)).convert('RGB')
noisy_image.save(file_path + 'noiseAdded_' + str(augment_cnt) + '.png')
augment_cnt += 1
이미지 반전, 기울이기 부분은 간단하여 설명이 없어도 될 것 같습니다.
다만 노이즈 추가 부분은 가우스 함수에 따른 노이즈 추가 방식을 사용했습니다.
이미지를 불러와 가우스 함수에 따른 노이즈를 추가하고 원 이미지와 합치는 방식입니다.
여기에서 고생을 좀 했었는데요, 이미지를 합치고 난 뒤의 형식은 numpy.array형식입니다. 따라서 바로 이미지로 저장이 되지 않았습니다.
위 코드에서 보실 수 있듯이
noisy_image = Image.fromarray(np.uint8(noisy_array)).convert('RGB')
이 코드를 통해 array를 이미지로 바꾸어 원 폴더에 저장할 수 있습니다.
augment_cnt는 한 바퀴 돌 때마다 +1씩 업데이트해줍니다.
[실제 작동 과정 확인하기]
위 코드에는 원빈님의 경로로 되어있지만,.. 사진 저작권에 위배될 수 있으므로 만만한 제 얼굴로 테스트 해보았습니다.
원본 폴더입니다.
num_augmentd_images를 50으로 설정하여 50장의 Augmentation된 사진을 얻어보겠습니다.
이젠 더 끔찍해졌습니다. 그럼 안녕~~
'머신러닝' 카테고리의 다른 글
[Pytorch] Siamese network를 이용하여 나의 외모를 점검해보자_2탄 (1) | 2021.02.27 |
---|---|
[Pytorch] Siamese network를 이용하여 나의 외모를 점검해보자_1탄 (1) | 2021.02.17 |
[입문] Pytorch 와 Linear Regression (0) | 2021.01.15 |