[컴퓨터비전 STUDY / KOCW 한동대학교 황성수 교수님 강의 Review]
Color Processing을 하기 위해 RGB 영상을 HSI나 YCbCr 색 공간으로 변화시킨다.
HSI와 YCbCr로부터 Intensity 값을 얻을 수 있다.
HSI
HSI는 Hue(색조), Saturation(순도), Intensity(세기)로 이루어져 있다.
HSI는 HSV로도 불린다.
Hue (색조) : 순수한 색깔을 나타내며, 붉은 색으로부터 얼마나 떨어져 있는지를 의미하기도 한다.
Saturation (순도) : 색상의 순도를 나타내며, 흰색이 섞인 정도를 의미한다.
Intensity (세기) : 밝기를 의미하며, 값이 높을수록 밝다.
S가 크면 -> clear color
I가 크면 -> bright color
원본 영상은 다음과 같다.

Hue 채널에서 원하는 색상 범위의 픽셀을 찾는다.

Saturation(포화) 채널에서 다른 모든 픽셀을 0으로 설정한다.

Hue 채널에 액세스하면 색상의 영역을 변경할 수 있다.

Pseudo Coloring은 grayscale 이미지에서 많이 적용된다.
Grayscale 이미지 내에서 우리 눈은 약 30~50가지의 다른 회색들밖에 구분하지 못한다.
반면에, Color 이미지 내에서 우리 눈은 약 100만가지에 달하는 다른 색깔들을 구분할 수 있다.
따라서, Pseudo Coloring의 목적은 정보를 더 잘 시각화하기 위해 색상을 사용하여 그레이 스케일 영상을 표현하고자 하는 것이다.
또한, 색상이 나타내는 바를 잘 이해하기 위해 이미지에 색상 척도를 포함하는 것이 중요하다. (Coloring)
예를 들어, grayscale 이미지를 다음과 같이 pseudo-coloring을 수행할 수 있다. (Intensity Slicing)

다음은 Pseudo Coloring을 수행하는 코드이다.
int main() {
Mat gray = imread("xray.jpg", 0); // 이미지를 grayscale로 로드함
Mat color;
// Applies a colormap on a given image
// gray: src, color: dst, COLORMAP_JET: the color map to apply
// grayscale 이미지에 COLORMAP_JET 컬러맵을 적용
applyColorMap(gray, color, COLORMAP_JET);
imshow("gray", gray); // 원본 이미지 출력
imshow("image", color); // 컬러맵이 적용된 이미지 출력
waitKey(0);
return 0;
색상의 강도에 대한 글로벌 조정을 Color balancing 이라고 한다.

Color balancing을 하는 간단한 방법

다음은 Color balancing을 수행하는 코드이다.
int main() {
Mat image = imread("lena.png"); // 이미지를 읽어 Mat 객체에 저장함
Mat result;
vector<Mat> ch(3);
int b_sum = 0, g_sum = 0, r_sum = 0;
int b_avg, g_avg, r_avg, b_tmp, g_tmp, r_tmp;
if (image.empty()) {
cerr<< "read fail" << endl;
exit(-1);
}
int rows = image.rows;
int cols = image.cols;
int pixno= rows * cols;
// split by B, G, R channel
// 이미지를 BGR(파랑, 초록, 빨강) 채널로 분리
split(image, ch);
uchar* b;
uchar* g;
uchar* r;
// calculate each channel's average
// 각 채널별로 픽셀 값의 합을 구함
for (int i = 0; i < rows; i++) {
b = ch[0].ptr<uchar>(i);
g = ch[1].ptr<uchar>(i);
r = ch[2].ptr<uchar>(i);
for (int j = 0; j < cols; j++) {
b_sum+= b[j];
g_sum+= g[j];
r_sum+= r[j];
}
}
// 전체 픽셀 수로 나누어 평균 값을 계산함
b_avg= b_sum/ pixno;
g_avg= g_sum/ pixno;
r_avg = r_sum / pixno;
// color balancing using gray world assumsption
for (int i = 0; i < rows; i++) {
b = ch[0].ptr<uchar>(i);
g = ch[1].ptr<uchar>(i);
r = ch[2].ptr<uchar>(i);
for (int j = 0; j < cols; j++) {
// to prevent overflow
// 조정된 값이 255를 초과하지 않도록 하여 오버플로우를 방지
b_tmp= (128 * b[j]) / b_avg;
if (b_tmp> 255) {
b[j] = 255;
}
else {
b[j] = b_tmp;
}
g_tmp = (128 * g[j]) / g_avg;
if (g_tmp> 255) {
g[j] = 255;
}
else {
g[j] = g_tmp;
}
r_tmp = (128 * r[j]) / r_avg;
if (r_tmp > 255) {
r[j] = 255;
}
else {
r[j] = r_tmp;
}
}
}
// merge 3 channel's image, 조정된 채널들을 다시 병합함
merge(ch, result);
imshow("image", image);
imshow("result", result);
waitKey(0);
return 0;
}
Color checker로부터 Color balancing을 수행할 수 있다.

두 가지 가정을 통해서 Color balancing을 수행할 수 있다.
모든 픽셀의 값들의 평균을 내보면 그 값은 회색에 가깝다.
흰색 픽셀이 가장 밝은 값을 가진다.
다음은 Color processing을 수행하는 코드이다.
int main() {
Mat image = imread("colorful.jpg"); // 이미지 로드함
Mat HSV, intensity_change, mask_out, change_color;
// 채널 별로 이미지를 분리할 벡터들을 선언함
vector<Mat> ic(3);
vector<Mat> mo(3);
vector<Mat> cc(3);
int rows = image.rows;
int cols = image.cols;
uchar* h;
uchar* s;
uchar* v;
// BGR 색상 공간에서 HSV 색상 공간으로 이미지를 변환함
cvtColor(image, HSV, CV_BGR2HSV);
// HSV 이미지를 각각 H(색상), S(채도), V(밝기) 채널로 분리함
split(HSV, ic);
split(HSV, mo);
split(HSV, cc);
//eqaulizingthe histogram of I mat
// 밝기(V) 채널의 히스토그램을 평활화하여 이미지의 대비를 개선함
equalizeHist(ic[2], ic[2]);
//masking out except orange
// 오랜지 색을 제외한 모든 색상을 마스킹함
for (int i = 0; i < rows; i++) {
h = mo[0].ptr<uchar>(i);
s = mo[1].ptr<uchar>(i);
for (int j = 0; j < cols; j++) {
if (h[j] > 9 && h[j] < 23) s[j] = s[j];
else s[j] = 0;
}
}
//changing all colors
// 모든 픽셀 색상 값을 50만큼 증가시킴
// 색상 값이 255를 초과하는 경우, 255를 넘어간 만큼을 0부터 다시 시작하는 방식으로 조정
for (int i = 0; i < rows; i++) {
h = cc[0].ptr<uchar>(i);
s = cc[1].ptr<uchar>(i);
for (int j = 0; j < cols; j++) {
if (h[j] + 50 > 255) h[j] = h[j] + 50 -255;
else h[j] += 50;
}
}
// 수정된 채널들을 다시 병합함
merge(ic, intensity_change);
merge(mo, mask_out);
merge(cc, change_color);
// HSV 공간에서 BGR 색상 공간으로 이미지를 다시 변환함
cvtColor(intensity_change, intensity_change, CV_HSV2BGR);
cvtColor(mask_out, mask_out, CV_HSV2BGR);
cvtColor(change_color, change_color, CV_HSV2BGR);
// 원본 이미지와 각각의 처리 결과를 표시함
imshow("image", image);
imshow("intensity change", intensity_change);
imshow("mask out", mask_out);
imshow("change color", change_color);
waitKey(0);
return 0;
}
위 코드를 수행한 결과는 다음과 같다.

참고로, Color processing은 컴퓨터 비전에서 널리 쓰이지는 않는다.
결과는 다음과 같다.
원본 영상

Histogram eqalization을 수행한 결과이다.

Color slicing을 수행한 결과이다.

Color changing을 수행한 결과이다.
