OpenCV | Python | HSV 색공간에서 이미지의 특정색 추출하기

박나연·2020년 7월 16일
1

OpenCV

목록 보기
8/40
post-thumbnail
post-custom-banner

HSV 색공간이란

우선 색공간이란 색을 표현하는 방법을 3차원 좌표계로 표현한 것이다. 그 중 RGB 와 HSV 색공간이 존재한다.


먼저 RGB 는 빛의 삼원색인 빨강, 초록, 파랑을 이용하여 색을 표현하는 방식이다. 따라서 총 세 채널로 구성되어있으며, 각 채널은 0-255 의 범위를 가진다. 그리고 다양한 색이 3가지 좌표로 구성되어 표현되는 것이다.


다음으로 HSV 색공간은 색상, 명도, 채도를 기준으로 색을 구성하는 방식이다.
색상 : H ) 0 - 360 의 범위를 가지고, 가장 파장이 긴 빨간색을 0도로 지정한다.
채도 : S ) 0 - 100 의 범위를 가지고, 색상이 가장 진한 상태를 100으로 하며, 진함의 정도를 나타낸다.
명도 : V ) 0 - 100 의 범위를 가지고, 흰색, 빨간색을 100, 검은색이 0이며, 밝은 정도를 나타낸다.


OpenCV 에서의 HSV 색공간

OpenCV 에서 색을 추출할때, RGB 가 아닌, HSV 색공간을 주로 이용하는 이유는, RGB 는 색상을 표시할 때 세채널로 직관적인 색을 세부적으로 구현하는데 초점을 두는데 반해, HSV 는 실제 색상을 기준으로 한 상태에서 명도와 채도에 차이를 두며 비교하는 방식으로 나타낸다.


얘를 들어 야외의 차선의 색을 추출할때, 햇빛을 고려하여 색을 추출해내야한다면, 명도와 채도의 기준을 적절히 맞추어 가장 그 색상에 가까운 색을 모두 추출해 낼 수 있는 HSV 색공간이 적절할 것이다.


RGB -> HSV

import numpy as np
import cv2

color = [255, 0, 0] # 파란색
pixel = np.uint8([[color]]) # 한픽셀로 구성된 이미지로 변환

hsv = cv2.cvtColor(pixel, cv2.COLOR_BGR2HSV) 
# cvtColor 함수를 이용하여 hsv 색공간으로 변환

hsv = hsv[0][0] # 픽셀값을 가져옴

print("bgr: ", color)
print("hsv: ", hsv) # +_ 10

실행결과 다음과 같이 출력된다.

hsv = cv2.cvtColor(pixel, cv2.COLOR_BGR2HSV)

cvtColor 함수는 한 색상 공간에서 다른 색상 공간으로 이미지를 변환하는 기능을 가진다.

cvtColor 함수를 통해 RGB 이미지를 한픽셀로 구성된 이미지를 바꾼 값을 HSV 색공간으로 변환할 수 있다.

(uint8 은 0-255 범위를 의미하는 데이터 타입)


그 결과

https://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html

에 따라

H 의 값은 255의 절반 값인 120 (+- 10), 나머지는 255로 유지된다.


사용 코드 _ 특정 색 추출하기

import numpy as np
import cv2

img_color = cv2.imread('blue.jpg') # 이미지 파일을 컬러로 불러옴
height, width = img_color.shape[:2] # 이미지의 높이와 너비 불러옴, 가로 [0], 세로[1]

img_hsv = cv2.cvtColor(img_color, cv2.COLOR_BGR2HSV) # cvtColor 함수를 이용하여 hsv 색공간으로 변환

lower_blue = (120-10, 30, 30) # hsv 이미지에서 바이너리 이미지로 생성 , 적당한 값 30
upper_blue = (120+10, 255, 255)
img_mask = cv2.inRange(img_hsv, lower_blue, upper_blue) # 범위내의 픽셀들은 흰색, 나머지 검은색

img_result = cv2.bitwise_and(img_color, img_color, mask = img_mask) 
# 바이너리 이미지를 마스크로 사용하여 원본이미지에서 범위값에 해당하는 영상부분을 획득

cv2.imshow('img_color', img_color)
cv2.imshow('img_mask', img_mask)
cv2.imshow('img_color', img_result)

cv2.waitKey(0)
cv2.destroyAllWindows()

정리

height, width = img_color.shape[:2]

numpy 의 shape 함수는 행렬의 차원을 표현한 방식이다.
여기서는 이미지의 높이와 너비를 구하기 위해 이용되었으며, :2는 이미지의 인덱스 0과 1 을 의미한다. (문자열 인덱싱과 동일)
즉, 높이는 인덱스 0의 크기, 너비는 인덱스 1의 크기인 것이다.

lower_blue = (120-10, 30, 30)

추출하고자 하는 파란색의 최저값을 정하는 것이다. 명도와 채도는 적당한 값인 30으로 지정하여 너무 밝거나 옅은 색을 피하기 위함이다.

upper_blue = (120+10, 255, 255)

다음을 파란색의 최대 범위를 정하는 것이다.

img_mask = cv2.inRange(img_hsv, lower_blue, upper_blue)

2, 3번째 파라미터에 각각 이미지 픽셀값의 최저, 최대범위가 입력되고, 첫번째 파라미터로 입력된 것이 그 사이 범위에 포함하는 지를 살펴본다. 포함된다면 흰색, 나머지는 검은색으로 나타난다.

img_result = cv2.bitwise_and(img_color, img_color, mask = img_mask)

바이너리 이미지(img_mask)를 마스크로 사용하여 원본이미지(img_color)에서 범위값(AND연산)에 해당하는 부분을 획득한다.


결과


원본 이미지

바이너리 이미지

결과 이미지



참조 소스코드

profile
Data Science / Computer Vision
post-custom-banner

2개의 댓글

comment-user-thumbnail
2020년 8월 8일

포스팅 잘 보았습니다. 내용이랑 코드 주석 정리가 정말 잘 되어 있네요. 공부하는데 많은 도움이 됐습니다.
사소한 부분이긴 하지만 python 에서 opencv 는 기본적으로 color image 를 읽어들일 때 (RGB 순서가 아닌) BGR 순서로 읽는다는 얘기를 해놓으면 초보자 분들이 약간은 덜 헷갈려하지 않을까 생각합니다 :)
앞으로도 좋은 포스팅 부탁드립니다 :)

답글 달기
comment-user-thumbnail
2020년 10월 24일

한 이미지에서 파란색뿐만 아니라 빨간색도 검출하려면 어떻게 해야하나요?

답글 달기