mat 객체를 생성할때 사용하는 imread()함수의 두번째 파라미터를 IMREAD_COLOR로 설정하면 영상을 3채널 컬러 영상 형식으로 불러온다.
일반적으로 컬러영상은 흔히 RGB라고 부르는 빨간색, 녹색, 파란색 색상 성분의 조합으로 픽셀 값을 표현한다. 그러나 openCV의 컬러 영상은 기본적으로 RGB가 아닌 BGR 색상순서로 픽셀 값을 표현한다.
각각 R,G,B의 색상 성분은 0부터 255사이의 값을 가질 수 있다. 색상 성분값이 0이면 해당 색상 성분이 전혀없는 상태, 255이면 해당 색상 성분이 가득 차있음을 의미한다. 각 색상 성분 값은 uchar 자료형을 사용하여 표현한다. 컬러영상에서 하나의 픽셀은 세개의 색상성분을 가지고 있으므로 컬러영상의 한픽셀을 정확하게 표현하려면 Vec3b 자료형을 이용한다.(크기가 3인 uchar자료형 배열을 멤버변수로 가지는 클래스)
컬러영상에서 픽셀 값을 참조할 때도 Mat::at()함수를 사용한다. 예를 들어 (0,0)위치의 픽셀 값을 참조하려면
Vec3b& pixel = img.at<Vec3b>(0,0)
다음과 같이 코드를 작성한다.
(0,0)좌표에서 BGR색상 정보를 가리키고, at함수가 픽셀 정보를 참조 형태로 변환하여 pixel 값을 변경하면 (0,0)좌표 픽셀 값도 같이 변경된다.
uchar b1 = pixel[0];
uchar g1 = pixel[1];
uchar r1 = pixel[2];
위 코드에서는 각각 pixel의 파란색 녹색 빨간색 성분 값이 저장된다.
Mat::ptr()함수를 이용하여 컬러 영상의 특정 행 시작 주소를 얻어 올때에도 Vec3b 자료형을 명시하여 사용한다. 예를 들어 img컬러영상에서 0번째 행 시작 픽셀 주소를 알고 싶다면 다음과 같이 코드를 작성한다.
Vec3b* ptr = img.ptr<Vec3c>(0)
포인터 변수 ptr에 특정 행 시작 주소를 받아온 후 해당행의 픽셀값을 ptr[0], ptr[1] ...과 같이 접근할 수 있다.
void color_inverse() {
Mat src = imread("butterfly.jpg", IMREAD_COLOR);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return;
}
Mat dst(src.rows, src.cols, src.type());
for (int j = 0; j < src.rows; j++) {
for (int i = 0; i < src.cols; i++) {
Vec3b& p1 = src.at<Vec3b>(j, i);
Vec3b& p2 = dst.at<Vec3b>(j, i);
p2[0] = 255 - p1[0];
p2[1] = 255 - p1[1];
p2[2] = 255 - p1[2];
}
}
imshow("src", src);
imshow("dst", dst);
waitKey();
destroyAllWindows();
}
빨간색, 녹색, 파란색 세가지 색 성분의 조합으로 색을 표현하는 방식을 RGB 색모델또는 RGB 색공간 표현이라고 한다. 컬러영상 처리에서는 보통 색상구분이 용이한 HSV, HSL 색공간을 사용하거나 또는 휘도 성분이 구분되어 있는 YCrCb, YUV 등 색공간을 사용하는 것이 유리하다.
OpenCV에서 영상의 색공간을 다른 색 공간으로 변환할 때에는 cvtColor()함수를 사용한다.
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn = 0);
src : 입력 영상
dst : 결과 영상
code : 색공간 변환 콛
dstCn : 결과 영상의 채널 수
BGR2GRAY 색공간변환 코드는 BGR컬러영상을 그레이스케일 영상으로 변환할때 사용한다. BGR 3채널 컬러영상을 그레이스케일 영상으로 변환할 때에는 다음 공식을 사용한다.
Y = 0.299R + 0.587G + 0.114B
R,G,B 는 각각 빨간색, 녹색, 파란색 성분의 값, Y는 해당 픽셀의 크레이스케일 성분 크기를 나타낸다.
GRAY2BGR 색공간 변환코드는 그레이스케일 영상을 BGR로 변환할 때 사용한다. 이때 각 성분값은
R = G = B = Y
다음과 같이 정해진다.
HSV색모델은 색상, 채도, 명도를 색으로 표현하는 방식이다.
HSV 색공간은 위와 같이 원뿔 모양으로 표현할 수 있다. 색상은 원뿔을 가로로 잘랐을때 나타나는 원형에서 각도로 정의된다. 0도이면 빨간색, 각도가 증가할수록 노란색, 녹색, 하늘색, 보라색을 거쳐 각도가 360도에 가까워지면 다시 빨간색으로 표현된다. 채도는 원뿔을 가로로 잘랐을때 나타나는 원모양의 중심에서 최소값을 갖고 원의 중심에서 방사형으로 멀어지는 방향으로 값이 증가한다. 명도는 원뿔 아래쪽 꼭지점에서 최솟값을 갖고 원뿔의 축을 따라 올라가면서 증가한다.
H는 0부터 179사이의 정수, S와 V는 0부터 255사이의 정수로 표현한다.
YCrCb 색공간에서 Y성분은 밝기 또는 휘도 정보를 나타내고, Cr과 Cb성분은 색상 또는 색차 정보를 나타낸다. RGB색상성분으로 부터 Y성분을 계싼하는 공식은 그레이스케일 계산공식과 완전히 같다. Cr과 Cb성분은 밝기에 대한 정보는 포함하지 않으며 오직 색상에 대한 정보만을 가지고 있다. 그러므로 YCrCb 색공간은 영상을 그레이스케일 정보와 색상정보로 분리하여 처리할 때 유용하다.
void color_grayscale() {
Mat src = imread("butterfly.jpg", IMREAD_COLOR);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return;
}
Mat dst;
cvtColor(src, dst, COLOR_BGR2GRAY);
imshow("src", src);
imshow("dst", dst);
waitKey();
destroyAllWindows();
}
컬러영상을 다루다 빨간색 성분만을 이용하거나 HSV색공간으로 변환 후 H성분만을 이용하는 경우가 종종 발생한다. 이러한 경우, 3채널 Mat 객체를 1채널 객체 세개로 분리해서 다루는 것이 효율적이다.
void split(const Mat& src, Mat* mvbegin);
void split(InputArray src, OutputArrayOfArrays mv);
src : 입력 다채널 행렬
mvbegin : 분리된 1채널 행렬을 저장할 Mat 배열 주소
mv : 분리된 1채널 행렬을 저장할 벡터
void merge(const Mat* mv, size_t count, OutputArray dst);
void merge(InputArrayOfArrays mv, OutputArray dst);
mv : 1채널 행렬을 저장하고 있는 배열 또는 벡터
count : Mat 행렬의 크기
dst : 출력 다채널 행렬
void color_split() {
Mat src = imread("candies.png", IMREAD_COLOR);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return;
}
vector<Mat> bgr_planes;
split(src, bgr_planes);
imshow("src", src);
imshow("B_plane", bgr_planes[0]);
imshow("G_plane", bgr_planes[1]);
imshow("R_plane", bgr_planes[2]);
waitKey();
destroyAllWindows();
}