上のような、白、黄、シアン、緑、マゼンタ、赤、緑、黒の順に並んだカラー・バーを作成する。
色の詳細は以下の通りである。
このようなカラーバーを作るためには、R,G,Bのプレーンをしたの用にデータを
書き込めばよい。
白が明るくする部分である。
Rプレーン | Gプレーン | Bプレーン |
カラー・バーを元に、輝度や色相(Hue)や彩度(Saturation)を表示する。
左から順に輝度が変化しているのがわかる。
(本書に輝度情報を画像に表示するプログラムはないが、
R, G, BとY, R-Y, B-Yの変換を行う関数のリスト中の y が輝度情報を保持しているので、 y を0〜255に変換し、
画像にすればよい。ここではそのプログラムの実装は行わない。)
赤色(113.2°)を基準にした色相を表示した。
赤から離れるほど暗くなっているのがわかる。
鮮やかな色ほど明るく表示されているのがわかる。
カラー画像をR,G,Bの信号ではなく輝度信号と色差信号に分離して扱うと、
そのカラー画像の色の特徴がよくわかる。
そこで、輝度、色相、彩度に分けたカラー画像を画像処理した後、
R,G,B成分に変換すれば、輝度、色相、彩度を自在に扱うことができる。
上の画像に対して、色を変える処理を行い、その例を以下に示す。
輝度を2倍した(彩度等倍、色相の増分を0°)。
明るくなったのがわかる。
色度を2倍にした(輝度1倍、色相の増分を0°)。
鮮やかになったのがわかる。
色相を90°ずらした(輝度、彩度等倍)。
明るさや鮮やかさは変わっていないが、色相が変化したのがわかる。
#include "Params.h" /*---- colorbar --- カラーバーを作る ------------------------------------------ image_r: 出力画像配列 R image_g: 出力画像配列 G image_b: 出力画像配列 B level: 濃度値 -----------------------------------------------------------------------------*/ void colorbar(unsigned char image_r[Y_SIZE][X_SIZE], unsigned char image_g[Y_SIZE][X_SIZE], unsigned char image_b[Y_SIZE][X_SIZE], int level) { int i, j, width; width = X_SIZE / 8; for (i = 0; i < Y_SIZE; i++){ for (j = 0; j < X_SIZE; j++){ if (((j >= 0) && (j < 2*width)) || /* Rプレーン */ ((j >= 4*width) && (j < 6*width))) image_r[i][j] = level; else image_r[i][j] = 0; if ((j >= 0) && (j < 4*width )) /* Gプレーン */ image_g[i][j] = level; else image_g[i][j] = 0; if (((j >= 0) && (j < width )) || /* Bプレーン */ ((j >= 2*width) && (j < 3*width)) || ((j >= 4*width) && (j < 5*width)) || ((j >= 6*width) && (j < 7*width))) image_b[i][j] = level; else image_b[i][j] = 0; } } }
#include "Params.h" /*--- rgb_to_yc --- R,G,Bから輝度,色差信号に変換する ----------------------- image_r: 入力画像配列 R image_g: 入力画像配列 G image_b: 入力画像配列 B y: 出力データ配列 Y c1: 出力データ配列R−Y c2: 出力データ配列B−Y -----------------------------------------------------------------------------*/ void rgb_to_yc(unsigned char image_r[Y_SIZE][X_SIZE], unsigned char image_g[Y_SIZE][X_SIZE], unsigned char image_b[Y_SIZE][X_SIZE], int y[Y_SIZE][X_SIZE], int c1[Y_SIZE][X_SIZE], int c2[Y_SIZE][X_SIZE]) { int i, j; float fr, fg, fb; for (i = 0; i < Y_SIZE; i++) { for (j = 0; j < X_SIZE; j++) { fr = (float)image_r[i][j]; fg = (float)image_g[i][j]; fb = (float)image_b[i][j]; y[i][j] = (int)(0.3 * fr + 0.59 * fg + 0.11 * fb); c1[i][j] = (int)(0.7 * fr - 0.59 * fg - 0.11 * fb); c2[i][j] = (int)(-0.3 * fr - 0.59 * fg + 0.89 * fb); } } } /*--- yc_to_rgb --- 輝度,色差信号からR,G,B信号に変換する ------------------- y: 入力データ配列 Y c1: 入力データ配列R−Y c2: 入力データ配列B−Y image_r: 出力画像配列 R image_g: 出力画像配列 G image_b: 出力画像配列 B ------------------------------------------------------------------------------*/ void yc_to_rgb(int y[Y_SIZE][X_SIZE], int c1[Y_SIZE][X_SIZE], int c2[Y_SIZE][X_SIZE], unsigned char image_r[Y_SIZE][X_SIZE], unsigned char image_g[Y_SIZE][X_SIZE], unsigned char image_b[Y_SIZE][X_SIZE]) { int i, j; int ir, ig, ib; for (i = 0; i < Y_SIZE; i++) { for (j = 0; j < X_SIZE; j++) { ir = y[i][j] + c1[i][j]; if (ir > 255) ir = 255; if (ir < 0) ir = 0; ig = (int)(y[i][j] - 0.3 / 0.59 * c1[i][j] - 0.11 / 0.59 * c2[i][j]); if (ig > 255) ig = 255; if (ig < 0) ig = 0; ib = y[i][j] + c2[i][j]; if (ib > 255) ib = 255; if (ib < 0) ib = 0; image_r[i][j] = (unsigned char)ir; image_g[i][j] = (unsigned char)ig; image_b[i][j] = (unsigned char)ib; } } }
#include <math.h> #include "Params.h" #define PI 3.141592 #define THRESHOLD 0.0 /* 彩度の有無を判断する閾値 */ #define NONE 0.0 /* 彩度がない場合に代入する値 */ /*---- c_to_sh --- 色差信号から彩度,色相を計算する ---------------------------- c1: 入力データ配列R−Y c2: 入力データ配列B−Y sat: 彩度のデータ配列 hue: 色相のデータ配列 -----------------------------------------------------------------------------*/ void c_to_sh(int c1[Y_SIZE][X_SIZE], int c2[Y_SIZE][X_SIZE], int sat[Y_SIZE][X_SIZE], int hue[Y_SIZE][X_SIZE]) { int i, j; float fhue, length; for (i = 0; i < Y_SIZE; i++) { for (j = 0; j < X_SIZE; j++) { length =(float)c1[i][j] * (float)c1[i][j] +(float)c2[i][j] * (float)c2[i][j]; sat[i][j] = (int)(sqrt((double)length)); if ((sat[i][j]) > THRESHOLD){ fhue = (float)(atan2((double)c1[i][j], (double)c2[i][j]) * 180.0 / PI); if (fhue < 0 ) fhue = fhue + (float)360.0; hue[i][j] = (int)fhue; } else hue[i][j] = (int)NONE; /* 彩度が閾値以下の時 */ } } } /*--- sh_to_c --- 彩度,色相から色差信号を計算する ----------------------------- c1: 入力データ配列R−Y c2: 入力データ配列B−Y sat: 彩度のデータ配列 hue: 色相のデータ配列 -----------------------------------------------------------------------------*/ void sh_to_c(int sat[Y_SIZE][X_SIZE], int hue[Y_SIZE][X_SIZE], int c1[Y_SIZE][X_SIZE], int c2[Y_SIZE][X_SIZE]) { int i, j; float rad; for (i = 0; i < Y_SIZE; i++) { for (j = 0; j < X_SIZE; j++) { rad = (float)(PI * hue[i][j] / 180.0); c1[i][j] = (int)(sat[i][j] * sin((double)rad)); c2[i][j] = (int)(sat[i][j] * cos((double)rad)); } } }
#include <math.h> #include "Params.h" /*--- sat_image --- 彩度データを濃淡画像化する -------------------------------- sat: 彩度のデータ配列 image_out: 出力画像配列 -----------------------------------------------------------------------------*/ int sat_image(int sat[Y_SIZE][X_SIZE], unsigned char image_out[Y_SIZE][X_SIZE]) { int i, j; int min, max; int isat; min = 255; max = 0; for (i = 0; i < Y_SIZE; i++){ for (j = 0; j < X_SIZE; j++ ){ if (sat[i][j] > max) max = sat[i][j]; if (sat[i][j] < min) min = sat[i][j]; } } if (min == max) return -1; for (i = 0; i < Y_SIZE; i++){ for (j = 0; j < X_SIZE; j++ ){ isat = 255 * (sat[i][j] - min) / (max - min); image_out[i][j] = (unsigned char)(isat); } } return 0; } /*--- hue_image --- 色相データを画像化する ------------------------------------ sat: 彩度のデータ配列 hue: 色相のデータ配列 stdhue: 基準となる色相値 image_out: 出力画像配列 -----------------------------------------------------------------------------*/ void hue_image(int sat[Y_SIZE][X_SIZE], int hue[Y_SIZE][X_SIZE], float stdhue, unsigned char image_out[Y_SIZE][X_SIZE]) { int i, j; int ihue; float delt; for (i = 0; i < Y_SIZE; i++){ for (j = 0; j < X_SIZE; j++){ if (sat[i][j] > 0){ delt = (float)(fabs((double)hue[i][j] - (double)stdhue)); if (delt > 180.0) delt = (float)360.0 - delt; ihue = (int)(255.0 - delt * 255.0 / 180.0); image_out[i][j] = (unsigned char)ihue; } else image_out[i][j]=0; } } }
#include "Params.h"
/*--- tran_ysh --- 輝度,彩度,色相を変える -------------------------------------
in_y: 入力データ配列 Y
in_sat: 入力データ配列 SAT
in_hue: 入力データ配列 HUE
out_y: 出力データ配列 Y
out_sat: 出力データ配列 SAT
out_hue: 出力データ配列 HUE
ym: 輝度の乗数
sm: 彩度の乗数
hd: 色相の増分
-----------------------------------------------------------------------------*/
void tran_ysh(int in_y[Y_SIZE][X_SIZE], int in_sat[Y_SIZE][X_SIZE],
int in_hue[Y_SIZE][X_SIZE], int out_y[Y_SIZE][X_SIZE],
int out_sat[Y_SIZE][X_SIZE], int out_hue[Y_SIZE][X_SIZE],
float ym, float sm, float hd)
{
int i, j;
for (i = 0; i < Y_SIZE; i++){
for (j = 0; j < X_SIZE; j++){
out_y[i][j] = (int)(in_y[i][j] * ym);
out_sat[i][j] = (int)(in_sat[i][j] * sm);
out_hue[i][j] = (int)(in_hue[i][j] + hd);
if(out_hue[i][j]>360) out_hue[i][j] = out_hue[i][j] - 360;
if(out_hue[i][j]< 0) out_hue[i][j] = out_hue[i][j] + 360;
}
}
}