이번에는 팔레트 구현을 알아보겠습니다.

일단 아래와 같은 배경지식을 알고 갔으면 좋겠습니다.
* 그림판 프로그램 : RGB 기반 색 표현
* 팔레트 기능 : HSV 기반 색 표현
* RGB <-> HSV 서로 변환 가능
구현하고자 하는 프로그램은 RGB 기반으로 색을 표현합니다.
HSV 기반인 팔레트 기능을 구현하려면 먼저 HSV 색을 RGB로 표현하는 방법을 알아야 합니다.
double* hsv_to_rgb(double H, double S, double V) {
//H, S and V input range = 0 ÷ 1.0
//R, G and B output range = 0 ÷ 1.0
double R, G, B;
if (S == 0)
{
R = V * 255;
G = V * 255;
B = V * 255;
}
else
{
double var_h, var_i, var_g, var_r, var_1, var_2, var_3, var_b;
var_h = H * 6;
if (var_h == 6) var_h = 0; //H must be < 1
var_i = int(var_h); //Or ... var_i = floor( var_h )
var_1 = V * (1 - S);
var_2 = V * (1 - S * (var_h - var_i));
var_3 = V * (1 - S * (1 - (var_h - var_i)));
if (var_i == 0) { var_r = V; var_g = var_3; var_b = var_1; }
else if (var_i == 1) { var_r = var_2; var_g = V; var_b = var_1; }
else if (var_i == 2) { var_r = var_1; var_g = V; var_b = var_3; }
else if (var_i == 3) { var_r = var_1; var_g = var_2; var_b = V; }
else if (var_i == 4) { var_r = var_3; var_g = var_1; var_b = V; }
else { var_r = V; var_g = var_1; var_b = var_2; }
R = var_r;
G = var_g;
B = var_b;
double arr[3] = { R, G, B };
return arr;
}
}
위 코드는 HSV 값을 받아 RGB로 출력하는 코드입니다.

RGB는 0~255의 값을 갖고
HSV의 경우 , H는 0~360도의 값을, (최대 360도)
S, V는 0~100%의 값을 갖습니다.
또한 H의 경우 색상을, S와 V는 각각 채도와 명도를 나타냅니다.
제가 구현하는 그림판 프로그램의 경우 RGB를 0~1로 정규화 하여 구현합니다.
그리고 HSV 또한 0~1 사이의 실수로 정규화 하여 표현합니다.
따라서 HSV 값을 0~1 사이의 실수 값으로 받고, 출력값 또한 0~1사이의 실수값으로 RGB를 출력합니다.
위는 공식이기 때문에 공식을 찾아 그것을 프로그램에서 작동할 수 있도록 옮겨 적은 것이기 때문에 이 과정만 수월하게 한다면 HSV를 RGB로 바꾸는 데는 어려움은 없을것입니다.
/* color_bar*/
void color_bar() {
/* H */
/* x : ww+400 ~ ww+500 */
/* y : wh ~ wh - 360 */
for (int i = 0; i < 360; i++) {
double* rgbp = hsv_to_rgb(i / 360.0, 1.0, 1.0);
double r = rgbp[0];
double g = rgbp[1];
double b = rgbp[2];
glColor3f(r, g, b);
glBegin(GL_QUADS);
glVertex2f(ww + 500, wh - i);
glVertex2f(ww + 500, wh - i - 1);
glVertex2f(ww + 450, wh - i - 1);
glVertex2f(ww + 450, wh - i);
glEnd();
}
}

다음은 color_bar를 구현하는 방법입니다. 먼저, 100 * 360의 사이즈로 구현했습니다.
HSV 모델에서 색상을 표현하는 범위가 360도이기 때문에 구현에 편리함을 위해 세로 사이즈를 360픽셀로 정했습니다.
( 여담이지만 이또한 비율로 구현했다면 임의의 변수 X에 대하여 100X * 360X 값으로 자유자재로 변환할 수 있는 팔레트가 될 수 있었을텐데 아쉽습니다. )
먼저 RGB로 표현한 HSV를 구하기 위하여 for문을 돌렸습니다.
i는 0부터 360까지 증가하고 이 값을 360으로 나누어 0~1 사이의 소수로 정규화 시켰습니다.
또한 컬러바에는 색상 자체를 표현해야하기 때문에 S와V는 1값을 준 순수 색인 HSV를 RGB로 변환해서,
HSV 기반의 RGB 컬러를 상단부터 하단까지 360픽셀만큼 쭈욱 출력합니다.
가로 50픽셀, 세로 1픽셀짜리 직사각형을 360개 그리는 방식으로 구현했습니다.
/* h = 전역변수로 선언된 hsv 기반의 컬러 값 */
void palette() {
/* S, V */
for (int i = 200; i >= 0; i -= 2) {
for (int j = 200; j >= 0; j -= 2) {
double* rgbp = hsv_to_rgb(h, j / 200.0, i / 200.0);
double r = rgbp[0];
double g = rgbp[1];
double b = rgbp[2];
glColor3f(r, g, b);
glBegin(GL_QUADS);
glVertex2f(ww + 248 + j, wh - i);
glVertex2f(ww + 248 + j, wh - i - 2);
glVertex2f(ww + 248 + j + 2, wh - i - 2);
glVertex2f(ww + 248 + j + 2, wh - i);
glEnd();
}
}
}
이번엔 왼쪽 팔레트에 대한 구현입니다.
먼저 h값은 전역변수로 선언되어있습니다.
if (y >= 640 && x >= wh + 350) {
draw_mode = 0;
h = (y - 1000) * (-1.0) / 360.0;
//printf("%f\n", h);
palette();
color_bar();
return 0;
}
h값을 구하는 방식은 위와 같은데,
컬러바의 경우 위에서부터 360픽셀만큼 그려져 있고, 0과 1 사이로 정규화 하기 위해 y값에서 1000을 빼고 ( 0~-360의 값을 가지게됨 ) -1을 곱하여 양수로 만든 뒤 , 360으로 나누었습니다.
컬러바가 구현되는 방식과 같은 원리로 구한다고 보시면 되겠습니다.
여기서 y = wh - y의 값을 가집니다. 쉽게 표현하자면 y는 2차원 좌표상 마우스의 y좌표라고 보시면 되겠습니다.
이 부분은 마우스 클릭 이벤트를 활용해 구현하였습니다. 컬러바에 마우스 클릭을 하게 된다면 그 좌표를 기반으로 h값을 정한다고 생각하시면 됩니다.
else if (y >= 800 && x >= wh + 150) {
draw_mode = 0;
double s = (x - 1150) / (200.0);
double v = (y - 1000) * (-1.0) / (200.0);
double* rgbp = hsv_to_rgb(h, s, v);
double nr = rgbp[0];
double ng = rgbp[1];
double nb = rgbp[2];
r = nr;
g = ng;
b = nb;
palette();
return 0;
}
컬러바 왼쪽의 팔레트에서 값을 선택하는 기능입니다.
S와 V의 값은 0~100의 값을 가지고 팔레트의 사이즈는 200X200으로 0~1 사이의 값으로 정규화 하기 위해 200을 나누었습니다.
이렇게 구해진 값을 기반으로 ( 팔레트 상에 있는 값은 HSV 이므로 ) hsv_to_rbg 함수를 활용해 그리기 위한 rgb 컬러로 만들어 전역변수 rgb를 구한 값으로 초기화합니다.
크게 구현에 있어서 어려운 부분은 없으나,
rgp <-> hsv
컬러 변환에 대한 이해만 있다면 쉽게 구현할 수 있을것이라 생각합니다.
이 포스팅 말고도 컬러모델에 관한 자료는 많으니 다른 참고도 참고하시면 좋을 것 같습니다.
'Computer Graphics > 그림판 프로그램' 카테고리의 다른 글
| 그림판 프로그램 기능 확장 - 1 : 도트확장, 브러쉬, 별 그리기 (0) | 2020.11.21 |
|---|








