이미지 다루기

LEEEEE·2022년 1월 17일
0

이미지를 다루는 코드를 작성해보자.

예제로 사용가능한 이미지

CIFAR-100

디지털 이미지란?

디지털 이미지는 수많은 점으로 이뤄져 있다. 이런 점을 화소(pixel) 이라고 한다. 화소는 RGB(Red, Green, Blue) 세가지로 이뤄져 있다. 이는 인간의 시세포가 3가지로 이뤄져 있기 때문이다.

이미지는 각 픽셀 별 색상을 저장한다. 이를 래스터(raster) 또는 비트맵(bitmap) 이라고 부른다. 한 픽셀마다 8비트를 사용하여, 0~255 사이의 값으로 표시한다.

벡터(vector)방식의 이미지도 있는데 이는 이미지의 상대적인 점과 선의 위치를 방정식으로써 기록하여 계산하기 때문에 확대 및 축소에도 깨지지 않는다. 보통 일반 디지털 이미지는 비트맵 방식이고, 글꼴은 벡터 방식이다.

[출처 : https://en.wikipedia.org/wiki/Vector_graphics]

디지털 이미지를 표현하는 방식에는 RGB만 있는것이 아니다. 흑백 채널에 1/4 해상도를 가진 두개의 색상 채널을 붙이는 YUV 방식도 있고, 색감을 직관적으로 볼 때 사용하는 HSV(Hue 색상, Saturation 채도, Value 명도)도 있다. 이 외에 인쇄할 때는 RGB 삼색을 조합하여 사용하면 잉크 낭비가 심하기때문에 CMYK(Cyan, Magenta, Yellow, Black)를 사용한다. 이런 색 표현을 하는 것을 컬러 스페이스라고 하고, 각 색상 축을 채널이라고 한다.

이런 색상들을 전부 그대로 저장하기에는 용량 소모가 심하다. 그래서 이미지 형식을 사용하여 이미지를 압축한다. 대표적으로 사용되는 JPEG는 주변 화소들을 묶어서 비슷한 색상끼리 뭉뚱그리는 방식으로 압축한다. PNG의 경우 손실없이 이미지를 압축하며, 스크린샷 등에서 많이 사용한다.

이렇게 이미지 저장 시 압축률을 높이게 되면, 디지털 풍화라고 불리는 이미지 열화 현상이 생기게 된다.


Pillow

파이썬에는 PIL(Python Image Library) 이라는 라이브러리가 있었다. 2011년을 기점으로 개발이 중단되었다. 이후 Pillow라는 라이브러리가 PIL의 정신을 이어받아 지속적으로 개발되고 있다.

PIL을 이용해 이미지를 하나 만들어보자. 여기서 알아야 할 점은 이미지는 배열 형태의 데이터라는 것이다. 아래 코드는 256 × 256의 초록색 이미지를 만드는 코드이다.

data = np.zeros([256, 256, 3], dtype=np.uint8)
data[:, :] = [0, 255, 0]
image = Image.fromarray(data, 'RGB')
image
/--------------------------------------------/
# 출력

이미지 데이터타입이 왜 np.uint8일까?

앞서 배운것과 같이 디지털 이미지는 0~255 사이의 값을 가진다. 즉, 부호가 없는 u(unsigned)의 256개의 값을 가져야한다. 이는 2의 8승의 값이기 때문에 np.uint8를 사용하여 이미지를 만들게 된다.


OpenCV

OpenCV는 컴퓨터 비전용 라이브러리로 C++, Python, Java등 다양한 언어에서 사용가능하며, 오픈소스로 제공된다. 이번에는 특정 색을 갖고 있으면 추출하는 것을 해보자.

앞서 얘기한것과 같이 색 영역을 직관적으로 표현할때는 HSV를 이용하면 좋다. 즉, 원하는 색 영역을 추출하려면 RGB 이미지에서 HSV로 변환하여 진행하면 된다.

import cv2 as cv
import numpy as np
from  matplotlib import pyplot as plt
%matplotlib inline

img_path = './data/cv_practice.png'
img = cv.imread(img_path)

# HSV 변환
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)

# 파란색 영역 지정
lower_blue = np.array([100,100,100])
upper_blue = np.array([130,255,255])

# 파란색에 해당하는 임계값 추출
mask = cv.inRange(hsv, lower_blue, upper_blue)

# 비트와이즈 앤드 연산
res = cv.bitwise_and(img, img, mask=mask)

plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
plt.show()
plt.imshow(cv.cvtColor(mask, cv.COLOR_BGR2RGB))
plt.show()
plt.imshow(cv.cvtColor(res, cv.COLOR_BGR2RGB))
plt.show()
/---------------------------------------------/
# 출력



중요!

OpenCV에서는 RGB가 아닌 BGR 순서를 사용하기때문에 변환할 때 cv.cvtColor(img, cv.COLOR_BGR2HSV)와 같이 RGB2가 아닌 BGR2로 표시한다.


0개의 댓글