C++ OpenCV 색상 감지 개요
이 글에서는 C++와 OpenCV 라이브러리를 활용해 특정 색상을 실시간으로 감지하고, 감지된 색상을 기준으로 객체를 추적하는 방법을 단계별로 알아봅니다.
다만 색상 감지 및 색상 기반 추적 시스템의 성능은 환경에 크게 의존한다는 점을 유의해야 합니다. 방의 조명을 바꾸거나 배경색을 변경하면 감지 결과에 상당한 영향이 생길 수 있습니다.
HSV 색 공간을 사용하는 이유
일반적인 BGR 형식은 빛의 밝기 변화에 민감하지만, HSV(Hue·Saturation·Value) 색 공간은 색상(Hue) 성분을 독립적으로 다룰 수 있어 조명 변화에 비교적 강합니다. 그래서 색상 감지 작업에서는 영상을 먼저 HSV로 변환한 뒤 처리하는 것이 일반적입니다. OpenCV에서 Hue 값의 범위는 0~179, Saturation과 Value는 각각 0~255입니다.
전체 예제 코드
다음 프로그램은 웹캠 영상에서 원하는 색상을 트랙바로 조정하며 실시간으로 감지하는 방법을 보여줍니다.
#include<iostream>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
VideoCapture video_load(0);//기본 카메라(장치 번호 0)에서 영상 캡처//
namedWindow("Adjust");//트랙바와 영상을 표시할 윈도우 생성//
int Hue_Lower_Value = 0;//색조(Hue) 하한 초기값//
int Hue_Lower_Upper_Value = 22;//색조(Hue) 상한 초기값//
int Saturation_Lower_Value = 0;//채도(Saturation) 하한 초기값//
int Saturation_Upper_Value = 255;//채도(Saturation) 상한 초기값//
int Value_Lower = 0;//명도(Value) 하한 초기값//
int Value_Upper = 255;//명도(Value) 상한 초기값//
createTrackbar("Hue_Lower", "Adjust", &Hue_Lower_Value, 179);//하한 색조 트랙바//
createTrackbar("Hue_Upper", "Adjust", &Hue_Lower_Upper_Value, 179);//상한 색조 트랙바//
createTrackbar("Sat_Lower", "Adjust", &Saturation_Lower_Value, 255);//하한 채도 트랙바//
createTrackbar("Sat_Upper", "Adjust", &Saturation_Upper_Value, 255);//상한 채도 트랙바//
createTrackbar("Val_Lower", "Adjust", &Value_Lower, 255);//하한 명도 트랙바//
createTrackbar("Val_Upper", "Adjust", &Value_Upper, 255);//상한 명도 트랙바//
while (1) {
Mat actual_Image;//원본 이미지를 담을 행렬//
bool temp = video_load.read(actual_Image);//비디오 스트림에서 이미지를 행렬로 읽어옴//
Mat convert_to_HSV;//변환된 이미지를 저장할 행렬 선언//
cvtColor(actual_Image, convert_to_HSV, COLOR_BGR2HSV);//BGR 이미지를 HSV로 변환하여 저장//
Mat detection_screen;//객체가 감지될 화면용 행렬 선언//
inRange(convert_to_HSV,Scalar(Hue_Lower_Value,Saturation_Lower_Value, Value_Lower),Scalar(Hue_Lower_Upper_Value,Saturation_Upper_Value, Value_Upper), detection_screen);//트랙바에서 조정한 색상 범위 필터 적용//
erode(detection_screen, detection_screen, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))));//모폴로지 열기: 전경의 작은 객체 제거//
dilate(detection_screen, detection_screen, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))));//모폴로지 열기: 전경의 작은 노이즈 제거//
dilate(detection_screen, detection_screen, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))));//모폴로지 닫기: 전경의 작은 구멍 메우기//
erode(detection_screen, detection_screen, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))));//모폴로지 닫기: 전경의 작은 구멍 메우기//
imshow("Threesholded Image", detection_screen);//감지된 객체 표시//
imshow("Original", actual_Image);//원본 이미지 표시//
if (waitKey(30) == 27){ //ESC 키를 누르면 반복문 탈출//
break;
}
}
return 0;
}
코드 동작 원리 단계별 설명
1. 카메라 영상 입력 받기
VideoCapture video_load(0)는 장치 번호 0번, 즉 기본 카메라에서 영상 스트림을 가져옵니다. 외부 USB 카메라를 사용하려면 번호를 변경하면 됩니다.
2. BGR → HSV 색 공간 변환
cvtColor() 함수와 COLOR_BGR2HSV 옵션을 사용해 매 프레임을 HSV 형식으로 변환합니다. 이렇게 하면 색상(Hue)만으로 객체를 구분하기가 훨씬 쉬워집니다.
3. 트랙바로 색상 범위 지정하기
createTrackbar()로 생성한 6개의 슬라이더(Hue·Saturation·Value의 하한/상한)를 움직이면 해당 변수 값이 실시간으로 변경됩니다. 이를 통해 감지하고 싶은 색상의 범위를 손쉽게 조정할 수 있습니다.
4. inRange()로 이진 마스크 생성
inRange()는 지정한 HSV 범위 안에 들어오는 픽셀은 흰색(255), 범위를 벗어나는 픽셀은 검은색(0)으로 만드는 이진 마스크를 생성합니다. 결과적으로 원하는 색상 영역만 남게 됩니다.
5. 모폴로지 연산으로 노이즈 제거
침식(erode)과 팽창(dilate)을 조합한 모폴로지 열기 연산은 전경의 작은 잡음을 제거하고, 모폴로지 닫기 연산은 전경 내부의 작은 구멍을 메워 줍니다. 이 과정을 거치면 감지 결과가 훨씬 깔끔해집니다.
실행 결과
프로그램을 실행하면 'Original'(원본 영상)과 'Threesholded Image'(감지 결과) 두 개의 창이 나타납니다. 트랙바 값을 조정하면 감지되는 색상 범위가 즉시 반영됩니다.

프로그램을 종료하려면 키보드의 ESC 키(ASCII 코드 27)를 누르면 됩니다.
마무리 및 실전 팁
이 예제는 색상 감지의 기본 원리를 익히기에 가장 좋은 출발점입니다. 실제 프로젝트에서는 다음 사항을 함께 고려하면 더 안정적인 결과를 얻을 수 있습니다.
- 조명 환경이 바뀌면 트랙바 값을 다시 조정해야 합니다.
- 특정 색상의 대표적인 Hue 값(예: 빨강 약 0~10 및 170~179, 초록 약 40~80, 파랑 약 100~130)을 참고하면 초기 설정이 쉬워집니다.
- 노이즈가 심하면 커널 크기를 조정하거나 가우시안 블러(
GaussianBlur)를 추가로 적용해 보세요. - 감지된 마스크의 무게중심을 계산하면(
moments()활용) 색상 기반 객체 추적으로 확장할 수 있습니다.