이미지 데이터 처리의 기본 - Pillow를 이용한 전처리

괴도소녀·2021년 7월 14일
1

데이터

목록 보기
12/14
post-thumbnail

이미지 데이터 처리의 전세계(?)에서 가장 널리 쓰이는 학습용 예제가 있다.
이름하여 CIFAR-100 예제이다.(발음이 정말 시파 같다!)

예제에서 사용할 데이터는 CIFAR-100 python version데이터이다.
여기선 train 데이터만 사용할 것이다.

import os
import pickle
from PIL import Image

dir_path = os.getcwd() + '/cifar-100-python'
train_file_path = os.path.join(dir_path, 'train')

with open(train_file_path, 'rb') as f:
    train = pickle.load(f, encoding='bytes')

print(type(train))
------------------------------------------------
<class 'dict'>

train 데이터 타입은 dictionary타입인걸 알 수 있다.
train 데이터의 데이터 타입을 알았으니, 이제 데이터를 살펴볼 차례다.

train.keys()
--------------------------------------------------------
dict_keys([b'filenames', b'batch_label', b'fine_labels', b'coarse_labels', b'data'])

key값으로는 filenames와 data등등이 있는 것을 알 수 있다.

type(train[b'filenames'])
--------------------------------------------------------
list

filename들의 데이터 타입은 list이다.
filename들 몇개를 살펴보자.

train[b'filenames'][0:5]
--------------------------------------------------------
[b'bos_taurus_s_000507.png',
 b'stegosaurus_s_000125.png',
 b'mcintosh_s_000643.png',
 b'altar_boy_s_001435.png',
 b'cichlid_s_000031.png']

참고로, 앞에 bbinary file이라는 뜻이다.

데이터의 shape을 알아보자

train[b'data'][0].shape
--------------------------------------------------------
(3072,)

3072이라는 숫자를 보니, RGB 3채널 X 1024(=32 * 32)Pixel 값인 것 같다.

3072라는 숫자를 생각해보면 RGB 순서가 맞지만, 그냥 모양만 맞추어 reshape하면 안되며, 1024를 32X32에 채우는 것을 3번 반복하는 방식의 reshape이어야 한다(32, 32, 3). 이런식으로 앞선 차원부터 데이터를 채우는 방식의 reshape를 위해 np.reshape에는 order라는 인자 값을 F로 주면 원하는 형태로 진행된다.

# order에 F값을 준다.
image_data = train[b'data'][0].reshape([32, 32, 3], order='F') 

# Pillow를 사용하여 Numpy 배열을 Image객체로 만든다.
image = Image.fromarray(image_data)    
image 

이미지를 자세히 살펴보면 X축과 Y축이 뒤집어져 나오고 있다. 그러므로, 축을 바꿔주는 작업이 필요하다. 이때 np.swapaxes(0, 1)를 사용하면 축이 바뀐다.

image_data = image_data.swapaxes(0, 1)
image = Image.fromarray(image_data)
image

CIFAR-100의 데이터셋 원본을 분석해서 이미지 파일을 시각화하는 것까지 진행하였다.
그러나 데이터 이미지 파일을 실제 파일처럼 만들고 싶어한다. 데이터셋에 파일명파일 데이터 배열이 순서를 따라 저장되어 있는 것을 확인하였으니, 차례대로 Numpy 배열로 읽어서 이를 이미지 파일로 저장해 주는 것은 여기서 배운 내용으로 충분히 구현할 수 있다.

여기서 추가로 tqdm이라는 패키지를 소개한다. 이 패키지를 사용하면 반복 작업의 진행상황을 시각화해서 체크할 수 있다.
tqdm github

이제 데이터 파일(train)을 가져와서 이미지 파일로 저장해주는 코드를 구현하자.

import os
import pickle
from PIL import Image
import numpy
from tqdm import tqdm

# 이미지들이 있는 디렉토리안에 train데이터를 경로를 가져온다.
dir_path = os.getcwd() + '/cifar-100-python'
train_file_path = os.path.join(dir_path, 'train')

images_dir_path = os.getcwd() + '/python_image_proc/cifar-images'
if not os.path.exists(images_dir_path): # 해당 경로에 디렉토리가 없으면
    os.mkdir(images_dir_path)  # 디렉토리 생성

# 32X32의 이미지 파일 50000개를 생성한다.
with open(train_file_path, 'rb') as f:
    train = pickle.load(f, encoding='bytes')
    for i in tqdm(range(len(train[b'filenames']))):
        filename = train[b'filenames'][i].decode()
        image_data = train[b'data'][i].reshape([32, 32, 3], order='F') 
        img = Image.fromarray(image_data.swapaxes(0, 1))
        img.save(os.path.join(images_dir_path, filename))


우와.... 작업 진행상황이 체크된다.....우와.....오.....오어어어어어


이미지 파일들은 정상적으로 만들어 졌다.


어라.... 49,999 items?.........1개 누가 훔쳐갔지...?

0개의 댓글