먼저 컬러영상을 처리할 때, RGB 색공간에서 컬러 프로세싱을 하면 영상의 톤이 달라진다던지, 화질 저하 등의 문제가 발생할 수 있기 때문에 HIS나 yCbcR 공간으로 변환 후 I값이나 Y값을 건드려서 컬러 프로세싱을 한다.
Usage of HSI
- intensity 이미지를 분리시킨다. 이 때는 intensity 값만 변경 가능하다.
- Color Slicing(컬러 슬라이싱). Hue(색조)-channel에서 원하는 색상의 픽셀값을 찾고, Saturation(채도)-channel 다른 모든 픽셀의 값을 0으로 설정한다.
- Color Conversion(색상변환). Hue-channel에 접근해서 색상 영역를 변경 가능하다.
Pseudo Coloring
사람의 눈은 gray 이미지에서, 약 30~50 가지의 다른 회색 음영의 색상변화를 인식 가능하다. 그러나 컬러 영상에서는 좀 더 민감하기 때문에 많은 색구별이 가능하다. 따라서, grayscale 이미지에서의 정보를 더 잘 시각화하기위해, 색상을 사용해 이미지를 표시한다. 이 때, 각각의 컬러가 어떠한 의미를 가지는지를 설명, 표시해줄 필요가 있다.
Ex. Intensity Slicing. 각각의 intensity 값에 특정한 컬러값을 할당한다.
Color Balancing(색상 균형 조정)
색상의 intensity를 전체적으로 조정한다.
1. R, G, B 구성 요소의 스케일을 조정
가장 간단하게 color balancing을 하는 방법은 R, G, B 구성 요소의 스케일을 조정하여 중립인 것으로 생각되는 객체, 예를 들어 우리가 흰색이라고 인지하고 있지만 실제 영상에서는 (255,255,255)값의 흰색이 아닌것을 255의 흰색값으로 바꿔주는 연산을 하는 것이다.
2. Color checker을 사용
3. 이미지에서 흰색 추정해내는 방법
- Gray world assumption : 일반 색상 균형이 잘 잡힌 사진에서 모든 색상의 평균은 중간 회색(128,128,128)이라고 가정 후, 실제로 촬영한 영상의 픽셀 값의 평균을 구한 후 회색이 아니라면 그 회색에 맞출 수 있도록 매트릭스를 구해서 맞추는 방법.
- 영상 내에서 가장 밝은 픽셀을 찾았을 때, 그 픽셀이 흰색(255,255,255)이라고 가정하고, 위와 같은 방법으로 매트릭스를 구해서 컬러 프로세싱을 수행하는 방법.
example code
// Usage of HSI
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
int main() {
Mat image = imread("zx.png");
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;
cvtColor(image, HSV, COLOR_BGR2HSV);
split(HSV, ic);
split(HSV, mo);
split(HSV, cc);
//eqaulizing the histogram of I mat
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]; // 주황색에 해당하는부분만 hue값 그대로
else s[j] = 0; // 나머지 hue값 0으로
}
}
//changing all colors
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);
cvtColor(intensity_change, intensity_change, COLOR_HSV2BGR);
cvtColor(mask_out, mask_out, COLOR_HSV2BGR);
cvtColor(change_color, change_color, COLOR_HSV2BGR);
imshow("image", image);
imshow("intensity change", intensity_change);
imshow("mask out", mask_out);
imshow("change color", change_color);
waitKey(0);
return 0;
}
// Pseudo coloring
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
int main() {
Mat gray = imread("zx.png", 0);
Mat color;
// Applies a colormap on a given image
// gray: src, color: dst, COLORMAP_JET: the color map to apply
applyColorMap(gray, color, COLORMAP_COOL); // COLORMAP_COOL : 컬러맵
imshow("gray", gray);
imshow("image", color);
waitKey(0);
return 0;
}
// Color Balancing
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
int main() {
Mat image = imread("zx.png");
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
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
b_tmp = (128 * b[j]) / b_avg; // 특정한 픽셀 값(b[j])이 b_avg일 때, 그 값을 128이 되도록
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;
}
이 게시물은 한동대학교 황성수 교수님의 컴퓨터비전 강의를 공부하며 정리한 내용입니다.
'Computer Vision' 카테고리의 다른 글
[OpenCV] 동영상 분할(Video Segmentation) (0) | 2020.01.19 |
---|---|
[OpenCV] 영상 분할(Image Segmentation) (0) | 2020.01.19 |
[OpenCV] 공간 도메인 필터링(Spatial Filtering) (0) | 2020.01.19 |
[OpenCV] 히스토그램 평활화(Histogram Equalization) (0) | 2020.01.19 |
[OpenCV] 밝기값 변환(Intensity Transformation) (0) | 2020.01.18 |