上のフルーツのカラー画像のBMP形式、fruit-color.bmpは
圧縮ファイルfruit_color.zipをダウンロードし、
それを展開して得られる。
この画像のR, G, B各プレーンのヒストグラムを、3章のヒストグラムをファイル出力
する関数を利用して出力し、gnuplotを用いてグラフを描いた例を以下に示す。
いずれのプレーンも0〜50に山ができている。これは背景のようである。
このように、面積の小さい領域の分布の山は、背景などの大きな面積の領域の分布の
山に埋もれてしまい、見分けがつかなくなってしまうことがある。
そこで、2つのプレーンの関係をみるために、2次元ヒストグラムを利用する。
2次元ヒストグラムをを求めて画像化する関数を用いて、
2次元ヒストグラムを画像化した。
グラフの軸や数値は、図9.3と同じである。
横軸にR、縦軸にGをとった。
RとGを同じ割ありで混ぜると黄色になることから、
RとGがほぼ同じ割合で現れている部分がバナナ、
ややRの方が強く出ている方がオレンジ、
Rがほとんどを占めているのがりんごであろう。
横軸にR、縦軸にBをとった。
今回のサンプルでは見づらいが、Bが最も強く出ている部分がリンゴのハイライト、
少量のBを含み多くの画素がでているのがバナナ、
Bをほとんど含まないのがオレンジであろう。
色の分布を使って、バナナを切り出した例を示す。
Rの値に注目して、R = 100以上の値を抜き出した。
背景が取り除かれた。
次にG = 110以上の値の画素を抜き出した。
赤いリンゴが除去された。
次にBが50〜150の画素を取り出した。
オレンジが除去されたが、今回の画像では、オレンジとバナナの色が近かったため、
バナナも一部除去されてしまった。
上の画像のBMP形式は、chroma.zipをダウンロードし、
解凍して得られる。
この画像に対して、ハード・キー、ソフト・キーを用いた
画像合成例を示す。
背景には下の画像を用いる。
(9.1式)で得られる値に対して、閾値-50で合成キー信号を作成した。
閾値で黒か白か分離されているので、2値画像になっている。
上のキー信号を元に画像を合成した。
ガタガタしており、グラスの質感は認識しづらい。
-100〜0で合成キー信号を作成した。
ハード・キーに対して、前景と背景がミックスされるようになるので、
キーはグレー画像になっているのがわかる。
上のキー信号を元に画像を合成した。
グラスの質感も認識できる。
しかし、まだ背景画像の色がぼやけている。 これをのぞくために、境界部色消し付きの画像合成を行う関数を利用して、 画像合成した結果を以下に示す。
多少色は残ったものの、背景画像の色が消され、違和感のない画像になった。
#include "Params.h" #define BIAS 128 /* ヒストグラム画像のバイアス値 */ /*--- hist2_image --- 2次元ヒストグラムを求め画像化する ---------------------- image_in1: 画像データ X軸用 image_in2: 画像データ Y軸用 image_hist: 2次元ヒストグラム -----------------------------------------------------------------------------*/ void hist2_image(unsigned char image_in1[Y_SIZE][X_SIZE], unsigned char image_in2[Y_SIZE][X_SIZE], unsigned char image_hist[Y_SIZE][X_SIZE]) { int i, j, kx, ky; int hx, hy, max, kk; for (i = 0; i < Y_SIZE; i++) /* 初期化 */ for (j = 0; j < X_SIZE; j++) image_hist[i][j] = 0; max = 0; ky = 256 / Y_SIZE; kx = 256 / X_SIZE; for (i = 0; i < Y_SIZE; i++) { for (j = 0; j < X_SIZE; j++) { hy = (HIGH - (int)image_in2[i][j]) / ky; hx = ((int)image_in1[i][j]) / kx; if (image_hist[hy][hx] < HIGH) image_hist[hy][hx]++; if (max < image_hist[hy][hx]) max = image_hist[hy][hx]; } } for (i = 0; i < Y_SIZE; i++) { for (j = 0; j < X_SIZE; j++) { if (image_hist[i][j] != 0) { kk = (long)image_hist[i][j] * HIGH / max + BIAS; if (kk > HIGH) image_hist[i][j] = HIGH; else image_hist[i][j] = kk; } } } for (i = 0; i < Y_SIZE; i++) image_hist[i][0] = HIGH; /* X軸 */ for (j = 0; j < X_SIZE; j++) image_hist[Y_SIZE-1][j] = HIGH; /* Y軸 */ }
#include "Params.h"
/*--- thresh_color --- R,G,B値による閾値処理 ----------------------------------
image_in_r: 入力R画像
image_in_g: 入力G画像
image_in_b: 入力B画像
image_out_r: 出力R画像
image_out_g: 出力G画像
image_out_b: 出力B画像
thdrl, thdrm: Rの閾値 (min,max)
thdgl, thdgm: Gの閾値 (min,max)
thdbl, thdbm: Bの閾値 (min,max)
-----------------------------------------------------------------------------*/
void thresh_color(unsigned char image_in_r[Y_SIZE][X_SIZE],
unsigned char image_in_g[Y_SIZE][X_SIZE],
unsigned char image_in_b[Y_SIZE][X_SIZE],
unsigned char image_out_r[Y_SIZE][X_SIZE],
unsigned char image_out_g[Y_SIZE][X_SIZE],
unsigned char image_out_b[Y_SIZE][X_SIZE],
int thdrl, int thdrm, int thdgl, int thdgm, int thdbl, int thdbm)
{
int i, j;
for (i = 0; i < Y_SIZE; i++) {
for (j = 0; j < X_SIZE; j++) {
image_out_r[i][j] = image_in_r[i][j];
image_out_g[i][j] = image_in_g[i][j];
image_out_b[i][j] = image_in_b[i][j];
}
}
for (i = 0; i < Y_SIZE; i++) {
for (j = 0; j < X_SIZE; j++) {
if (image_out_r[i][j] < thdrl)
image_out_r[i][j] = image_out_g[i][j] = image_out_b[i][j] = 0;
if (image_out_r[i][j] > thdrm)
image_out_r[i][j] = image_out_g[i][j] = image_out_b[i][j] = 0;
if (image_out_g[i][j] < thdgl)
image_out_r[i][j] = image_out_g[i][j] = image_out_b[i][j] = 0;
if (image_out_g[i][j] > thdgm)
image_out_r[i][j] = image_out_g[i][j] = image_out_b[i][j] = 0;
if (image_out_b[i][j] < thdbl)
image_out_r[i][j] = image_out_g[i][j] = image_out_b[i][j] = 0;
if (image_out_b[i][j] > thdbm)
image_out_r[i][j] = image_out_g[i][j] = image_out_b[i][j] = 0;
}
}
}
#include "Params.h"
/*--- hard_mask --- 合成キー(ハードキー)の生成 ------------------------------
image_in_r: 入力R画像
image_in_g: 入力G画像
image_in_b: 入力R画像
image_key: 入力B画像
thresh: 閾値
-----------------------------------------------------------------------------*/
void hard_mask(unsigned char image_in_r[Y_SIZE][X_SIZE],
unsigned char image_in_g[Y_SIZE][X_SIZE],
unsigned char image_in_b[Y_SIZE][X_SIZE],
unsigned char image_key[Y_SIZE][X_SIZE], int thresh)
{
int i, j, d;
for (i = 0; i < Y_SIZE; i++) {
for (j = 0; j < X_SIZE; j++) {
d = ((int)image_in_r[i][j] + (int)image_in_g[i][j]) / 2
- (int)image_in_b[i][j];
if (d >= thresh) image_key[i][j] = 255;
else image_key[i][j] = 0;
}
}
}
#include "Params.h"
/*--- synth --- クロマキーによる画面合成 --------------------------------------
image_in1_r: 入力前景R画像
image_in1_g: 入力前景G画像
image_in1_b: 入力前景B画像
image_in2_r: 入力背景R画像
image_in2_g: 入力背景G画像
image_in2_b: 入力背景B画像
image_out_r: 出力合成R画像
image_out_g: 出力合成G画像
image_out_b: 出力合成B画像
image_key: 合成用キー画像
-----------------------------------------------------------------------------*/
void synth(unsigned char image_in1_r[Y_SIZE][X_SIZE],
unsigned char image_in1_g[Y_SIZE][X_SIZE],
unsigned char image_in1_b[Y_SIZE][X_SIZE],
unsigned char image_in2_r[Y_SIZE][X_SIZE],
unsigned char image_in2_g[Y_SIZE][X_SIZE],
unsigned char image_in2_b[Y_SIZE][X_SIZE],
unsigned char image_out_r[Y_SIZE][X_SIZE],
unsigned char image_out_g[Y_SIZE][X_SIZE],
unsigned char image_out_b[Y_SIZE][X_SIZE],
unsigned char image_key[Y_SIZE][X_SIZE])
{
int i, j;
int rr1, gg1, bb1;
int rr2, gg2, bb2;
long kk;
for (i = 0; i < Y_SIZE; i++) {
for (j = 0; j < X_SIZE; j++) {
rr1 = (int)image_in1_r[i][j];
gg1 = (int)image_in1_g[i][j];
bb1 = (int)image_in1_b[i][j];
rr2 = (int)image_in2_r[i][j];
gg2 = (int)image_in2_g[i][j];
bb2 = (int)image_in2_b[i][j];
kk = (long)image_key[i][j];
image_out_r[i][j] = (unsigned char)((rr1*kk+rr2*(255-kk))/255);
image_out_g[i][j] = (unsigned char)((gg1*kk+gg2*(255-kk))/255);
image_out_b[i][j] = (unsigned char)((bb1*kk+bb2*(255-kk))/255);
}
}
}
#include "Params.h"
/*--- soft_mask --- 合成用キー(ソフトキー)の生成 ----------------------------
image_in_r: 入力R画像
image_in_g: 入力G画像
image_in_b: 入力B画像
image_key: 合成用キー画像
thdh, thdl: 閾値 (max,min)
-----------------------------------------------------------------------------*/
void soft_mask(unsigned char image_in_r[Y_SIZE][X_SIZE],
unsigned char image_in_g[Y_SIZE][X_SIZE],
unsigned char image_in_b[Y_SIZE][X_SIZE],
unsigned char image_key[Y_SIZE][X_SIZE], int thdh, int thdl)
{
int i, j, d;
int kk;
for (i = 0; i < Y_SIZE; i++) {
for (j = 0; j < X_SIZE; j++) {
d = ((int)image_in_r[i][j] + (int)image_in_g[i][j]) / 2
- (int)image_in_b[i][j];
kk = ((long)(d - thdl) * 255 / (thdh - thdl));
if (kk > 255) image_key[i][j] = 255;
else if (kk < 0) image_key[i][j] = 0;
else image_key[i][j] = kk;
}
}
}
#include "Params.h" /*--- s_synth --- クロマキーによる画面合成(境界部色消し)--------------------- image_in1_r: 入力前景R画像 image_in1_g: 入力前景G画像 image_in1_b: 入力前景B画像 image_in2_r: 入力背景R画像 image_in2_g: 入力背景G画像 image_in2_b: 入力背景B画像 image_out_r: 出力合成R画像 image_out_g: 出力合成G画像 image_out_b: 出力合成B画像 image_key: 合成用キー画像 -----------------------------------------------------------------------------*/ void s_synth(unsigned char image_in1_r[Y_SIZE][X_SIZE], unsigned char image_in1_g[Y_SIZE][X_SIZE], unsigned char image_in1_b[Y_SIZE][X_SIZE], unsigned char image_in2_r[Y_SIZE][X_SIZE], unsigned char image_in2_g[Y_SIZE][X_SIZE], unsigned char image_in2_b[Y_SIZE][X_SIZE], unsigned char image_out_r[Y_SIZE][X_SIZE], unsigned char image_out_g[Y_SIZE][X_SIZE], unsigned char image_out_b[Y_SIZE][X_SIZE], unsigned char image_key[Y_SIZE][X_SIZE]) { int i, j; int rr1, gg1, bb1; int rr2, gg2, bb2; long kk; for (i = 0; i < Y_SIZE; i++) { for (j = 0; j < X_SIZE; j++) { rr1 = (int)image_in1_r[i][j]; gg1 = (int)image_in1_g[i][j]; bb1 = (int)image_in1_b[i][j]; rr2 = (int)image_in2_r[i][j]; gg2 = (int)image_in2_g[i][j]; bb2 = (int)image_in2_b[i][j]; kk = (long)image_key[i][j]; if (kk == 255 || kk == 0) { /* 前景または背景 */ image_out_r[i][j] = (unsigned char)((rr1*kk+rr2*(255-kk))/255); image_out_g[i][j] = (unsigned char)((gg1*kk+gg2*(255-kk))/255); image_out_b[i][j] = (unsigned char)((bb1*kk+bb2*(255-kk))/255); } else { /* 境界部 */ image_out_r[i][j] = (unsigned char)((gg1*kk+rr2*(255-kk))/255); image_out_g[i][j] = (unsigned char)((gg1*kk+gg2*(255-kk))/255); image_out_b[i][j] = (unsigned char)((gg1*kk+bb2*(255-kk))/255); } } } }