튜토리얼에도 고난과 역경이 있다.

[fd_16] 파이썬으로 이미지 다루기 본문

나의 공부/인공지능

[fd_16] 파이썬으로 이미지 다루기

내가 Nega 2022. 1. 20. 00:27
728x90

오늘은 파이썬에서 이미지 파일 다루는 법에 대하여 공부해 보았습니다. AIFFEL의 FUNDMANTAL 16번 노드의 학습노트입니다.

디지털 이미지란?

컴퓨터에서 이미지 데이터를 방식에는 대표적으로 두가지가 있습니다.

  • 래스터 Raster 방식 / 비트맵 Bitmap 방식
  • 벡터 Vector 방식

래스터 Raster 방식 / 비트맵 Bitmap 방식

사람의 시세포는 대부분 3가지 색상에 반응합니다. 많이 들어본 RGB값으로 Red, Green, Blue 색상입니다. 이와 같은 방식으로 픽셀 하나당의 RGB값을 저장하는 방식이 래스터 혹은 비트맵 방식입니다.

한 픽셀당 0-255값을 가지며 0은 검정, 255는 흰색입니다.

픽셀당 값이 정해져있기 때문에, 확대와 축소시 해당 픽셀값을 넓히거나 축소시켜 모자이크된 것 처럼 깨지는 특징이 있습니다.

벡터 Vector 방식

상대적인 점과 선의 위치를 방정식에 기록해두었다가, 확대 및 축소에 따라 해당 픽셀값을 계산해내는 방식입니다. 그렇기 때문에 확대와 축소에 자유로운 특징이 있습니다.

그 밖의 방식들

  • YUV 방식
  • 예전에 흑백 TV에서 컬러 TV로 이용되던 방법으로 흑백 이미지에다가 1/4 해상도를 가진 두 색상채널을 덧붙여서 송출하는 방식입니다.
  • HSV 방식
  • Hue 색상 Saturation 채도 Value 명도
  • CMYK
  • 인쇄매체에서 자주 사용되는 이미지의 색상 표현방법이며, Cyan, Magenta, Yellow, Black 네가지 색상을 이용합니다.

컬러 스페이스 Color space : 색을 표현하는 다양한 방식

채널 Channel : 각 컬러 스페이스를 구성하는 단일 축

Pillow 사용법

파이썬의 이미지 라이브러리는 PIL이라는 라이브러리가 유명했으나 현재는 개발이 진행되고 있지 않습니다. 대신 Pillow라는 라이브러리가 대신 개발이 되고 있으며, 요즘 이미지처리에는 OpenCV를 많이 사용합니다.

1. PIL을 이용해 간단한 이미지 생성하기

이미지는 배열 형태의 데이터로 이루어져 있습니다. 그렇기 때문에, 배열형태로 데이터를 선언하기만 하면 이미지를 생성할수있습니다.

import numpy as np
from PIL import Image

data = np.zeros([32, 32, 3], dtype=np.uint8)
# np.zeros : 생성되는 행렬 값을 전부 0으로 채운다.
image = Image.fromarray(data, 'RGB')
#fromarray : np 배열을 이미지 객체로 변환해주는 코드
image

cf. 흰색 : data = np.zeros([32, 32, 3], dtype=np.uint8) +255

cf. 파란색 : data[:, :] = [0, 0, 255]

2. 이미지 저장하기

레퍼런스 보는 것은 항상 어려운것 같습니다.

봐도봐도 모르겠고, 어떻게 써야할지는 모르겠으나,, 일단 레퍼런스에서 저장하는 메소드를 찾아서 코드를 작성해보았습니다.

img.save("test.jpg")

위코드는 안되며, 다음 오류를 내뱉습니다.

뭔가 RGBA를 RGB로 바꾸어 줘야 하나 봅니다.

어디선가 줏어들은 지식으로 JPG는 RGB값저장하는 형태라고 했던듯

img = img.convert('RGB')
img.save("test.jpg")

위와 같이 수정했더니 오류는 안나지만, jpg파일이 저장되진 않았습니다.

이 파이썬 파일이 존재하는 상대경로에 생길줄알았는데ㅠㅠ

해결된 코드는 다음과 같습니다.

new_image_path = os.getenv('HOME')+'/aiffel/python_image_proc/data/jpg_pillow_practice.jpg'
img = img.convert('RGB')
img.save(new_image_path)

저장될 경로를 선언해주는 것이 중요합니다.

3. cifar-100 데이터 전처리

cifar-100 데이터 셋은 100003072의 numpy array of uint8s 로 이루어져 있습니다. 각 행은 32\32 컬러이미지를 저장하고 있고, 첫번째 1024 픽셀은 Red, Green, Blue 데이터를 저장하고 있습니다.

다음 코드는 cifar 데이터 중 train 데이터를 가저오는 코드입니다.

import os
import pickle
from PIL import Image

dir_path = os.getenv('HOME')+'/aiffel/python_image_proc/data/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))

해당 행을 이미지로 변환하려면, reshape를 해주면 되지만, 1024를 각각 32*32에 채워주고 이를 3번 반복해야합니다.

그러기 위에서는 reshape에 order옵션을 사용하면 됩니다. 앞선 차원부터 데이터를 채우는 방식입니다. 코드는 아래와 같습니다.

image_data = train[b'data'][0].reshape([32, 32, 3], order='F')   
image = Image.fromarray(image_data)    
# fromarray : 배열을 이미지 객체로 변환

아무 처리를 하지 않은 상태로 위의 image를 출력하면 사진이 누워있는 형태로, X축과 Y축이 바뀌어있습니다. 그렇기 때문에 축을 바꿔주는 과정이 필요합니다.

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

OpenCV

openCV는 오픈소스로 제공되는 컴퓨터 비전용 라이브러리입니다.

보통 이미지는 RGB 순서를 사용하지만 openCV는 BGR순서를 사용합니다.

이미지는 [너비, 높이, 채널]의 형태를 가집니다.

openCV를 이용해서, 사진에서 파란색 부분만을 추출하는 토이 프로젝트를 작성했었고, 해당 코드 중 기억해야할 메서드를 정리해보았습니다.

hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV) : BGR인 이미지를 HSV이미지로 변경하는 코드

mask = cv.inRange(hsv, lower_blue, upper_blue)

res = cv.bitwise_and(img, img, mask=mask)

  • img에서 mask값이 0인 부분은 색상을 날려버리고, 1인 부분은 기존 이미지의 색상값으로 연산하는 메소드

출처
반응형