컬러 영상과 색공간
컬러 영상(Color Image)
- 인간이 보는 세상은 빛의 파장에 따라 다양한 색을 띄우며, 디지털 영상에서 색(Color)를 표현하기 위해서 채널과 픽셀값을 통해 색을 나타낼 수 있다.
- 인간의 눈은 세 가지 원추세포(빨강, 초록, 파랑) 에 민감 → 이 원리를 모방한 것이 RGB 컬러 모델. (빛의 3원색)
- 디지털 영상에서 흑백 영상(Grayscale Image)은 단일 채널에서 밝기(Intensity)만 표현하지만, 컬러 영상은 주로 3가지 채널(Red, Green, Blue) 의 각 0~255 사이의 정수 값 (UINT8) 으로 다양한 색을 표현한다.
Color Image | Grayscale Image |
---|
 |  |
RGB 컬러 모델
- 빛의 3원색 - 빨강(Red), 초록(Green), 파랑(Blue)을 조합해 모든 색을 표현. (가산혼합)
- RGB (255, 255, 255) = White
- RGB (0, 0, 0) = Black
- OpenCV 에서는 RGB 순서가 아니라 BGR 순서를 기본으로 사용.

Blue Plane | Green Plane | Red Plane | Color (B+G+R) |
---|
 |  |  |  |
RGB to Gray
- 인간의 시각은 녹색(G)에 가장 민감하며, 빨강(R), 파랑(B) 순서로 민감하다.
- RGB 영상을 Grayscale로 변환할 때, ITU-R BT.601 표준에 따라 민감도를 반영한 가중합을 사용한다.
Gray=0.299⋅R+0.587⋅G+0.114⋅B
색공간(Color Space)
- 같은 색을 표현하는 또 다른 좌표계.
- RGB는 화면 출력에는 적합하지만, 사람의 인지나 영상처리 목적에 따라 다른 표현법이 필요함.
- 대표적인 색공간:
- RGB: 디스플레이용 (화면 표현에 적합)
- HSV: 사람이 직관적으로 색을 이해하기 쉽도록 변환한 공간
- 특정 색 범위를 마스크 처리 → 객체 추적 (예: 축구공, 차량 번호판 색)
- YCbCr: 밝기(Y)와 색차(Cb, Cr)를 분리 → 영상 압축(JPEG, MPEG)에 사용
- 영상 압축, 스킨 컬러 검출 (피부 색상은 Cr, Cb 범위로 잘 구분됨)
- Lab: 인간 시각과 유사하게 밝기와 색을 분리
HSV 색공간
- Hue (색상), Saturation (채도), Value (명도) 로 색을 표현함.
- Hue : 0° ~ 360° (OpenCV 에서는 0~180 사이로 정규화)
- Saturation : 0% ~ 100% (OpenCV 에서는 0~255)
- Value : 0% ~ 100% (OpenCV 에서는 0~255)

RGB to HSV
- OpenCV에서
cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
를 통해 변환 가능.
1. 정규화 및 최대, 최소 찾기
R,G,B∈[0,1]Cmax=max(R,G,B), Cmin=min(R,G,B)Δ=Cmax−Cmin
2. Hue 계산
H=⎩⎨⎧060×(ΔG−Bmod6)60×(ΔB−R+2)60×(ΔR−G+4)Δ=0Cmax=RCmax=GCmax=B
3. Saturation 계산
S={0CmaxΔCmax=0Cmax=0
4. Value 계산
V=Cmax
YCbCr 색공간
- Y(밝기), Cr(빨강 성분과의 차), Cb(파랑 성분과의 차) 로 색을 표현함.
- mpeg에서 사용되는 색상모델로서 인간의 눈이 밝기차에는 민감하지만 색차에는 상대적으로 둔감하다는 점을 이용해서 Y에는 많은 비트수(해상도)를 할당하고 Cb, Cr에는 낮은 비트수를 할당하는 방식으로 비디오를 압축함.
- OpenCV에서는 아래와 같이 입력 범위에 따라 출력 범위가 달라짐.
- RGB (0–255) 입력 → Y, Cb, Cr 모두 0–255
- RGB (0–1, float32/float64) 입력 → Y, Cb, Cr 모두 0–1
YCbCr 색공간의 시각화 | Y′=0.5에서 CbCr 평면 |
---|
 |  |
RGB to YCbCr
- OpenCV에서
cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
를 통해 변환 가능.
- 이론적으로는
Cb = (B - Y)
, Cr = (R - Y)
성분이므로 범위가 음수~양수가 되어야 하지만, OpenCV는 Offset(128 또는 0.5) 를 추가하여 양수 범위 안에 들어오도록 조정한다.
- BT.601 표준에 따라 R,G,B∈[0,255] 일 때, YCbCr 변환 식은 아래와 같다.
YCbCr=0.299R+0.587G+0.114B=−0.168736R−0.331264G+0.5B+128=0.5R−0.418688G−0.081312B+128
Lab 색공간
- 국제 조명 위원회(CIE)가 1931년에 정의한 CIE XYZ를 바탕으로 1976년 발표한 색 공간이며 CIE L*a*b*로도 표기한다.
- Lab 색공간은 RGB나 CMYK와 달리 장치에 독립적(Device-independent)이며, 디스플레이 장비나 인쇄 매체에 따라 색이 달라지는 색 공간과 달리 L*a*b* 색 공간은 인간의 시각에 대한 연구를 바탕으로 정의되었다.
- L* : Lightness (명도) → 0(검정) ~ 100(흰색)
- 사람이 느끼는 밝기, 로그적(비선형) 반응 반영
- a* : Green–Red 축 (음수 → 초록, 양수 → 빨강)
- b* : Blue–Yellow 축 (음수 → 파랑, 양수 → 노랑)
- OpenCV에서는 모두 0~255 범위.

RGB to Lab
- OpenCV에서
cv2.cvtColor(img_bgr, cv2.COLOR_BGR2Lab)
를 통해 변환 가능.
- 색의 선형 조합(혼색)은 물리적(선형) 광량 값에서만 성립 → 따라서 먼저 감마를 제거(선형화)해야 함.
- Lab은 사람 눈의 지각적 특성(지각적 균일성)을 반영하기 위해 XYZ를 비선형 변환한 것.
1. 정규화 및 감마 해제
- 감마 보정이 된 픽셀값(RGB) 을 다시 선형 광량 값으로 되돌리는 과정
- 인간 눈의 감각 특성을 고려해 비선형으로 저장된 RGB (JPEG, PNG 등) → 실제 광량(linear) 값
- 0~1 범위로 정규화
R,G,B∈[0,1]
C={R,G,B}Clinear={12.92C(1.055C+0.055)2.4C≤0.04045otherwise
2. XYZ 변환
- CIE 1931 XYZ는인간의 색 일치 실험을 근거로 만든 선형 3자극값(tristimulus) 공간, 장치 독립적 색공간.
- sRGB 프라이머리(원색)와 D65 백색점에 의해 유도된 변환. (어떤 RGB 프로파일을 가정하느냐가 중요)
XYZ=0.41245640.21267290.01933390.35757610.71515220.11919200.18043750.07217500.9503041RlinearGlinearBlinear
3. Lab 변환
- 참조 백색(Reference White)으로 XYZ 정규화
- sRGB+D65 표준에서는 Xn=95.047, Yn=100.000, Zn=108.883
x=XnX, y=YnY, z=ZnZ
- 비선형 함수 f(x) 정의 (사람 시각의 비선형 응답을 근사)
f(t)=⎩⎨⎧t1/3,3δ2t+294,t>δ3otherwise,δ=296
L∗a∗b∗=116f(x)−16=500(f(x)−f(y))=200(f(y)−f(z))
- L∗ 는 약 0~100 범위를 가짐.
- a∗,b∗는 약 -128~127 범위를 가짐.
예시
- 입력 RGB=(255, 0, 0) 인 순수 빨강을 위 방식으로 Lab로 변환하면 아래와 같다.
L∗≈53.2408, a∗≈80.0925, b∗≈67.2032
- L∗(53.2) 밝기는 중간 정도.
- a∗(80.0) 매우 큰 양수, 녹색-적색 축에서 강하게 적색 쪽.
- b∗(67.2) 노랑 쪽도 기여도가 있음. 즉, 순수 빨강도 실제로는 노란기가 섞여 있다는 의미.
OpenCV에서 컬러 영상 다루기
1. HSV 변환을 통한 색상 영역 추출
- RGB 색공간은 같은 색상이라도 밝기가 달라지면 RGB 값이 크게 변하므로 특정 색상을 추출하기 위해 HSV 색공간으로 변환 후 H 채널을 통해 조명변화에 강인한 색상 추출을 할 수 있다.
OpenCV
cv2.inRange()
사용하여 이미지의 특정 색상 영역만 추출.
import cv2
import numpy as np
# 이미지 읽기
img = cv2.imread("example.jpg")
# BGR -> HSV 변환
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 빨강색 범위 지정 (OpenCV HSV는 H:0~179, S:0~255, V:0~255)
# 빨강은 0도 근처이므로 두 개의 구간으로 나눠야 함
lower_red1 = np.array([0, 100, 100])
upper_red1 = np.array([10, 255, 255])
lower_red2 = np.array([170, 100, 100])
upper_red2 = np.array([180, 255, 255])
# 마스크 생성
mask1 = cv2.inRange(hsv, lower_red1, upper_red1)
mask2 = cv2.inRange(hsv, lower_red2, upper_red2)
mask = cv2.bitwise_or(mask1, mask2)
# 원본 이미지에서 빨강색 부분만 추출
result = cv2.bitwise_and(img, img, mask=mask)
# 결과 출력
cv2.imshow("Red Color Extraction", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
2. 히스토그램 역투영
개요
- 히스토그램 역투영(Histogram Backprojection)은 ROI(관심영역)의 색상 분포를 확률밀도(또는 빈도)로 추정한 뒤, 영상의 각 픽셀이 그 분포에 얼마나 일치하는지를 매핑하여 확률 맵(또는 유사도 맵) 을 만드는 방법.

원본 링크
참고