1. HSV
HSV 색 공간 또는 HSV 모델은 색을 표현하는 하나의 방법이자, 그 방법에 따라 색을 배치하는 방식이다. 색상(Hue), 채도(Saturation), 명도(Value)의 좌표를 써서 특정한 색을 지정한다. 비슷한 것으로 HSL(Lightness), HSI(Intensity) 등이 있다.
RGB가 색을 빨강, 초록, 파랑의 조합으로 표현한다면, HSV는 우리가 보는 그대로의 색을 Hue 채널로 나타낸다. 그리고 그 색의 진하고 연한 정도를 Saturation 채널로 표현하고, 밝기를 Value로 결정한다.
RGB 색 공간보다는 좀 더 우리들이 색을 판단하는 과정과 유사한 것이 HSV 색 공간이다. 예를 들어 노란색을 표현하고자 하면, RGB 색 공간은 빨강과 초록의 조합으로 노랑을 표현해야하기에 직관성이 떨어진다. 반면 HSV 색 공간은 색들의 조합이 아닌 그 색깔 자체를 알려주므로 직관성이 좋다.
만약 색깔을 통해 이미지에서 어떤 물체를 검출하고 싶다면, RGB 공간보다는 HSV 공간이 적합할 것이다.
다음 그림은 HVS 색 공간을 한 눈에 설명해준다. 원뿔 모양으로 HSV 공간을 표현했는데, 우선 색조는 원뿔의 밑면에 해당되고 360도 연속적으로 배치되어 있음을 볼 수 있다. 그리고 명도는 원뿔의 높이에 해당한다. 꼭지점으로 갈수록 어두워진다.
채도는 원뿔의 밑면의 중심에서 가까울수록 연해지고 멀어질수록 진해진다.
색상 : H ) 0 - 360 의 범위를 가지고, 가장 파장이 긴 빨간색을 0도로 지정한다.
채도 : S ) 0 - 100 의 범위를 가지고, 색상이 가장 진한 상태를 100으로 하며, 진함의 정도를 나타낸다.
명도 : V ) 0 - 100 의 범위를 가지고, 흰색, 빨간색을 100, 검은색이 0이며, 밝은 정도를 나타낸다.
RGB -> HSV
import numpy as np
import cv2
color = [255,0,0] # BGR 순서 ; 파란색
pixel = np.uint8([[color]]) # 한 픽셀로 구성된 이미지로 변환
# BGR -> HSV
hsv = cv2.cvtColor(pixel, cv2.COLOR_BGR2HSV)
print(hsv, 'shape:', hsv.shape )
# 픽셀값만 가져오기
hsv = hsv[0][0]
print("bgr: ", color)
print("hsv: ", hsv) # +_ 10
앞선 포스팅에서 RGB2HSV 를 종종 사용했었다.
위 코드를 실행해서 임의로 한 픽셀로 된 이미지를 만들어서 numpy array 를 살펴보자.
어떤 수식으로 변환할걸까? 공식문서에서 나온 공식을 참고 해보자.
H 는 0~360 , S 와 V 는 0~1 범위이다. 이는 맨 위에서 다룬 원뿔 모양으로 표현한 HSV 모델 구조를 생각해보면 이해가 될 것이다.
H는 절반값이고 나머지는 maximize 된 것으로 이해된다.
2. inRange(특정 색상 추출)
HSV 개념을 이해했다면 이를 활용하여 특정 생상을 추출해보겠습니다.
일반적으로 BGR 보다는 HSV 가 성능이 좋습니다.
결과
코드
# inRange
import numpy as np
import cv2
img_color = cv2.imread('color circle_w.jpg') # 이미지 파일을 컬러로 불러옴
print('shape: ', img_color.shape)
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_origin', img_color)
cv2.imshow('img_mask', img_mask)
cv2.imshow('img_color', img_result)
cv2.waitKey(0)
cv2.destroyAllWindows()
중간에 color 이미지의 shape 은 shape: (472, 600, 3) 인데요.
여기서 472 는 행(Y축), 600 은 열(X축) , 3 은 행과열이 만나는 지점의 값이 몇개의 원소로 이루어져 있는지를 나타냅니다. 위 값의 의미는 이미지 사이즈는 600 * 472 (가로 * 세로) (너비 * 높이) 로 보시면 됩니다.
472 = 가로 = 너비
600 = 세로 = 높이
입니다.
위 결과를 조금 확대해서 보여드리자면,
### 2번째 이미지 ###
다른 이미지도 적용해보겠습니다.
위와 같은 이미지에서 특정 색상을 추출해보겠습니다.
# inRange 함수를 이용해서 특정 색상 검출
import cv2
src = cv2.imread('inRange.jpg')
# size 축소
src = cv2.resize(src, (0, 0), fx=0.5, fy=0.5, interpolation=cv2.INTER_NEAREST)
src_hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV)
# 0 < B < 100 , 128 < G < 255 , 0 < R < 100
dst1 = cv2.inRange(src, (0, 128, 0), (100, 255, 100))
img_result = cv2.bitwise_and(src_hsv, src_hsv, mask = dst1)
dst2 = cv2.inRange(src_hsv, (50, 150, 0), (80, 255, 255))
img_result2 = cv2.bitwise_and(src_hsv, src_hsv, mask = dst2)
cv2.imshow('src', src)
cv2.moveWindow('src',400,100)
cv2.imshow('dst1', dst1)
cv2.moveWindow('dst1',400,450)
cv2.imshow('img_result', img_result)
cv2.moveWindow('img_result',800,450)
cv2.imshow('dst2', dst2)
cv2.moveWindow('dst2',400,800)
cv2.imshow('img_result2', img_result2)
cv2.moveWindow('img_result2',1100,450)
cv2.waitKey()
cv2.destroyAllWindows()
** 참고 **
ttps://ko.wikipedia.org/wiki/HSV_%EC%83%89_%EA%B3%B5%EA%B0%84
https://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html
https://opencv-python.readthedocs.io/en/latest/doc/01.imageStart/imageStart.html
'머신러닝,딥러닝 > opencv' 카테고리의 다른 글
opencv 입문하기 7-1편 histogram stretching, equalization (0) | 2020.08.08 |
---|---|
opencv 입문하기 6편 트랙바, 산술 연산 (0) | 2020.07.26 |
opencv 입문하기 5편 마우스 이벤트(2) (0) | 2020.07.26 |
opencv 입문하기 4편 키보드, 마우스 이벤트(1) (0) | 2020.07.25 |
opencv 입문하기 3편 영상생성,추출, 그리기 함수 (0) | 2020.07.21 |