3장. 디지털 영상과 색공간 변환
색으로 고르기
옷 가게에서 "빨간 옷만 골라 주세요"라고 하면 직원은 진열대를 훑으며 빨간 옷에만 표시를 합니다. 그다음 구멍 뚫린 가림판(스텐실)을 대고 페인트를 뿌리듯, 표시한 것만 남기고 나머지는 가립니다. OpenCV 에서는 cv2.inRange 가 표시를, 마스크가 가림판을 맡습니다.
그림의 네 걸음이 색으로 고르는 순서입니다. HSV 로 바꾸고, H·S·V 각각의 아래 값과 위 값을 정하고, inRange 로 마스크를 만들고, bitwise_and 로 마스크의 흰 칸만 남깁니다. 여기서 "빨간 옷"이라는 주문이 범위이고, 표시한 옷의 목록이 마스크이고, 스텐실을 대고 뿌리는 일이 bitwise_and 입니다.
범위 정하기
cv2.inRange(hsv, 아래 값, 위 값) 은 칸마다 H, S, V 세 숫자가 모두 아래 값 이상, 위 값 이하이면 255(흰색), 하나라도 벗어나면 0(검정)을 적습니다.
점선 네모가 이 장에서 과일을 고를 때 쓰는 H 범위입니다. 노랑, 초록, 보라는 한 구간이지만, 빨강은 H 띠의 양 끝에 하나씩 두 구간입니다. 그래서 빨강은 마스크를 둘 만들어 cv2.bitwise_or 로 합칩니다. OR 는 "둘 가운데 하나라도 흰색이면 흰색"이라는 뜻입니다.
| 과일 | H 범위 | S 범위 | V 범위 |
|---|---|---|---|
| 빨강(사과) | 0~10 과 170~179 | 100~255 | 80~255 |
| 노랑(바나나) | 20~35 | 100~255 | 100~255 |
| 초록(라임) | 40~85 | 80~255 | 60~255 |
| 보라(포도) | 125~160 | 60~255 | 50~255 |
이 범위는 이 장의 바구니 그림에서 과일 가운데의 HSV 값을 읽어 보고 정한 것입니다(실습 4). 다른 사진에서는 값을 다시 읽어 맞춰야 합니다.
마스크로 남기기
가운데 마스크의 흰 칸이 빨강으로 고른 칸입니다. 오른쪽은 cv2.bitwise_and(img, img, mask=mask) 로 흰 칸의 원래 색만 남기고 나머지를 검정으로 만든 그림입니다. 포도 아래쪽, 바구니 테두리와 맞닿은 곳에도 흰 점 몇 개가 보입니다. 보라와 갈색이 섞인 테두리 칸의 H 가 빨강 범위에 든 것입니다.
| 함수 | 원래 말 | 하는 일 |
|---|---|---|
cv2.inRange(hsv, lo, hi) | in range(범위 안에) | 범위 안이면 255, 밖이면 0 인 마스크 |
cv2.bitwise_or(m1, m2) | bitwise OR(또는) | 둘 중 하나라도 255 면 255 |
cv2.bitwise_and(img, img, mask=m) | bitwise AND(그리고) | 마스크가 255 인 칸만 원래 색, 나머지는 0 |
import cv2
import numpy as np
img = cv2.imread("fruit_basket.png")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 빨강은 H 의 양 끝 두 구간이다. 아래 값과 위 값은 [H, S, V] 순서의 배열로 준다
low_red = cv2.inRange(hsv, np.array([0, 100, 80]), np.array([10, 255, 255]))
high_red = cv2.inRange(hsv, np.array([170, 100, 80]), np.array([179, 255, 255]))
red = cv2.bitwise_or(low_red, high_red) # 두 마스크를 합친다
print(red.dtype, np.unique(red)) # 결과: uint8 [ 0 255] → 흑백 두 값뿐
only_red = cv2.bitwise_and(img, img, mask=red) # 흰 칸만 원래 색으로 남긴다
print(only_red.shape) # 결과: (240, 320, 3)