영상처리에서 RGB 색상모델을 이용하여 간단하게 색상을 검출하는 방법에 대해서 알아보겠다.


RGB 색상모델을 실제 영상처리에서 사용하는 일은 드물다 RGB 색상모델은 조명에 영향을 많이 받기 때문에 정확도가 많이 떨어진다. 그러나 간단하게 색을 인식하는 용도로 RGB 색상모델을 쓰기도 한다. 


영상처리의 기초로 간단하게 붉은색을 인식하는 예제를 알아보도록 하겠다.


소스를 먼저 보고 설명을 하도록 하겠다.


#include <opencv\highgui.h>

int main() {
	IplImage *frame;	// 원본영상
	IplImage *red;		// 색 검출 영상

	int width, height;	// 창의 넓이, 높이
	int i, j, index;
	unsigned char R, G, B;

	CvCapture* capture = cvCaptureFromCAM(0);
	frame = cvQueryFrame(capture);

	// frame 에서 width와 height 정보를 가져온다.
	width = frame->width;
	height = frame->height;
	
	cvNamedWindow("Original",0);
	cvNamedWindow("Red Tracking",0);
	cvResizeWindow("Original", width, height);
	cvResizeWindow("Red Tracking", width, height);

	// frame와 같은 크기를 갖는 3채널 영상 생성
	red = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3);

	while(capture) {
		frame = cvQueryFrame(capture);

		for(i = 0; i < (frame->height); i++) {
			for(j = 0; j < (frame->widthStep); j += (frame->nChannels)) {
				index = i * frame->widthStep + j;

				R = frame->imageData[index+2];	// R영역
				G = frame->imageData[index+1];	// G영역
				B = frame->imageData[index+0];	// B영역

				// 붉은색으로 예상되는 범위 설정
				if(R > 200 && G < 200 && B < 200) {
					// 흰색으로
					red->imageData[(i*frame->widthStep)+j + 0] = 255;	
					red->imageData[(i*frame->widthStep)+j + 1] = 255;
					red->imageData[(i*frame->widthStep)+j + 2] = 255;
				}
				else {
					// 검정색으로
					red->imageData[(i*frame->widthStep)+j + 0] = 0;
					red->imageData[(i*frame->widthStep)+j + 1] = 0;
					red->imageData[(i*frame->widthStep)+j + 2] = 0;
				}
			}
		}

		cvShowImage("Original",frame);
		cvShowImage("Red Tracking",red);

		if(cvWaitKey(33) >= 27)
			break;
	}
	cvReleaseCapture(&capture);
	cvReleaseImage(&red);
	cvDestroyWindow("Original");
	cvDestroyWindow("Red Tracking");

	return 0;
}

붉은색 영역은 본인이 임의로 설정하였다. 먼저 결과부터 확인해 보겠다.


실행결과 :


추출된 범위를 흰색으로(255) 나타내고 그 외의 범위는 검정색으로(0)으로 나타내었다.


이번 포스팅은 색상 검출에 대한 내용이므로 다른 코드에 대한 설명은 나중에 하도록 하겠다.


색상 범위


색상 검출한 결과를 나타내기 위해서 red라는 3채널의 IplImage 구조체를 선언하였다. 

카메라에서 프레임을 받아오는 동안 (while문 안에서) for 2개를 이용하여 전체영상의 각 ImageData에 접근하여서 R,G,B의 크기를 판단하였다. 

R,G,B 영역의 범위는 본인이 임의로 설정하였는데, 빨간색을 검출한다고 해서 꼭 R이 255의 값을 갖고 G와 B값은 0을 갖는것이 아니다. 컴퓨터로 작업을 한 영상이라면 R=255, G=0, B=0 의 값을 갖을수는 있지만 실제 영상에서 빨간색은 R,G,B 각각의 색상모델의 조합으로 나타내진다. 또한 그 값은 조명에 의해, 주변 환경에 의해 충분히 달라질 수 있다. 그렇기 때문에 색상검출을 위해서 실제로 사용할 경우 정확도가 크게 떨어지게 된다. 이러한 단점을 해결하기 위해 다양한 색상모델이 있고 대표적으로 YCbCr 모델을 많이 사용하고 있다. YCbCr에 대해서는 나중에 알아보도록 하겠다. 


RGB영역에서 색 검출을 굳이 하고싶다면 색 검출을 위한 범위는 직접 지정하길 바란다. 위의 코드의 범위는 본인마음대로 대충 때려넣은 범위이다.


widthStep


while문 안에서 2개의 for 루프를 이용하여 영상의 넓이(width)와 높이(height)만큼의 크기의 배열에 접근하고 있다. 이때 두번째 for 루프에는 width가 아닌 widthStep이 들어가 있다. 분명 넓이는 width인데 왜 widthStep을 쓸까?


컬러영상은 다음과 같이 B, G, R 순서의 세 영역으로 이루어져 있다.


하나의 컬러 영상은 B평면(B값만 존재), G평면(G값만 존재), R평면(R값만 존재)에 존재하는 각 값들의 합으로 이루어 진다. 3개의 평면이 하나로 겹쳐지면서 컬러 영상이 만들어 지는것이다. 우리는 각 영역의 색상값을 알아내기 위해 하나의 평면을 갖는 컬러 영상을 3개의 평면으로 나누어 볼 필요가 있다. 그렇기 때문에 width 대신 widthStep을 이용하는데 widthStep은 (영상의넓이) x (채널의 갯수) 의 값을 갖고있다. 여기서는 채널이 3채널이기 때문에(width x 3)의 값을 갖고 있는 것이다. 

한번 for루프에 들어갈 경우 [index+2], [index+1], [index+0] 으로 컬러영상에서 같은 위치에 있는 RGB평면을 동시에 체크하기 때문에 for루프에서 증가값은 3이 되어야 한다. 그렇기 때문에 j값은 nChannel 만큼 증가하게 된다. 


다시한번 말하지만 RGB색상모델은 실제 영상처리에서 사용하기에 좋은 색상모델은 아니다. 




제 머리속에 있는 내용을 정리해 보았습니다! 틀린내용이 있을수도 있고 저의 머리속에 있는 내용을 글로 옮겼기 때문에 이해가 안되는 분들도 계실꺼 같습니다. 댓글을 남겨주신다면 친절히 답변해 드리겠습니다.

+ Recent posts