// 2値画像の細線化処理(Erode法)プログラム // (2値画像は,背景(黒):MIN_GRAY_LEVEL,図形(白):MAX_GRAY_LEVELのグレイスケール画像とする。) // プログラム名:skl_erode.cpp #include "eps-header.hh" // 元画像(src)をErode法で細線化処理して処理済画像に入れる関数 // // Erode法 // // (1)の細線化条件を満たす画素を背景画素に変更する。 // .. // (4)の細線化条件を満たす画素を背景画素に変更する。 // // (1)〜(4)を繰り返し,背景画素に変更した画素数が0となると,細線化処理を終了する。 // // 注目画素(☆)を除く3×3領域の画素番号(Freemanのチェーンコード) // ┏━┳━┳━┓ // ┃ 3┃ 2┃ 1┃ // ┣━╋━╋━┫ // ┃ 4┃☆┃ 0┃ // ┣━╋━╋━┫ // ┃ 5┃ 6┃ 7┃ ○(図形),●(背景) // ┗━┻━┻━┛ // // (1)の細線化条件 ☆を●(背景)にする。☆は端点のため削ることができる。 // ┏━┳━┳━┓ ┏━┳━┳━┓ ┏━┳━┳━┓ // ┃●┃●┃●┃ ┃●┃●┃ ┃ ┃●┃ ┃○┃ // ┣━╋━╋━┫ ┣━╋━╋━┫ ┣━╋━╋━┫ // ┃ ┃☆┃ ┃ ┃●┃☆┃○┃ ┃●┃☆┃○┃ // ┣━╋━╋━┫ ┣━╋━╋━┫ ┣━╋━╋━┫ // ┃○┃○┃○┃ ┃ ┃○┃○┃ ┃●┃ ┃○┃ // ┗━┻━┻━┛ ┗━┻━┻━┛ ┗━┻━┻━┛ // // (2)の細線化条件 ☆を●(背景)にする。☆は端点のため削ることができる。 // ┏━┳━┳━┓ ┏━┳━┳━┓ ┏━┳━┳━┓ // ┃○┃○┃○┃ ┃○┃○┃ ┃ ┃○┃ ┃●┃ // ┣━╋━╋━┫ ┣━╋━╋━┫ ┣━╋━╋━┫ // ┃ ┃☆┃ ┃ ┃○┃☆┃●┃ ┃○┃☆┃●┃ // ┣━╋━╋━┫ ┣━╋━╋━┫ ┣━╋━╋━┫ // ┃●┃●┃●┃ ┃ ┃●┃●┃ ┃○┃ ┃●┃ // ┗━┻━┻━┛ ┗━┻━┻━┛ ┗━┻━┻━┛ // // (3)の細線化条件 ☆を●(背景)にする。☆は端点のため削ることができる。 // ┏━┳━┳━┓ ┏━┳━┳━┓ ┏━┳━┳━┓ // ┃○┃ ┃●┃ ┃ ┃●┃●┃ ┃●┃●┃●┃ // ┣━╋━╋━┫ ┣━╋━╋━┫ ┣━╋━╋━┫ // ┃○┃☆┃●┃ ┃○┃☆┃●┃ ┃ ┃☆┃ ┃ // ┣━╋━╋━┫ ┣━╋━╋━┫ ┣━╋━╋━┫ // ┃○┃ ┃●┃ ┃○┃○┃ ┃ ┃○┃○┃○┃ // ┗━┻━┻━┛ ┗━┻━┻━┛ ┗━┻━┻━┛ // // (4)の細線化条件 ☆を●(背景)にする。☆は端点のため削ることができる。 // ┏━┳━┳━┓ ┏━┳━┳━┓ ┏━┳━┳━┓ // ┃●┃ ┃○┃ ┃ ┃○┃○┃ ┃○┃○┃○┃ // ┣━╋━╋━┫ ┣━╋━╋━┫ ┣━╋━╋━┫ // ┃●┃☆┃○┃ ┃●┃☆┃○┃ ┃ ┃☆┃ ┃ // ┣━╋━╋━┫ ┣━╋━╋━┫ ┣━╋━╋━┫ // ┃●┃ ┃○┃ ┃●┃●┃ ┃ ┃●┃●┃●┃ // ┗━┻━┻━┛ ┗━┻━┻━┛ ┗━┻━┻━┛ // const unsigned char SKL_GRAY_LEVEL = 128; // 細線化点を示す濃度値 const int LU_RD = 5; // (1)の細線化条件において,基準とする○(図形)の画素番号 const int RD_LU = 1; // (2)の細線化条件において,基準とする○(図形)の画素番号 const int RU_LD = 3; // (3)の細線化条件において,基準とする○(図形)の画素番号 const int LD_RU = 7; // (4)の細線化条件において,基準とする○(図形)の画素番号 const bool BACKGROUND_PIXEL = false; // ●(背景) const bool FIGURE_PIXEL = true; // ○(図形) // 指定された方向で画像を走査し,細線化条件を満たす画素を●(背景)に変更する関数 int // 変更された画素数(戻り値) erode_image( class image& dst, // 処理対象画像クラス(入出力) int direction) // 注目画素の3×3領域の条件判断の開始画素番号 { char * msg; switch (direction) { case LU_RD : msg = "(1)"; break; case RD_LU : msg = "(2)"; break; case RU_LD : msg = "(3)"; break; case LD_RU : msg = "(4)"; break; } bool a[8]; // 符号化された注目画素を除く3×3領域 // Freemanのチェーンコードのオフセット値 // 画素番号 0 1 2 3 4 5 6 7 int offset_x[8] = {+1, +1, 0, -1, -1, -1, 0, +1}; // 注目画素番号からピクセル方向のオフセット int offset_y[8] = { 0, -1, -1, -1, 0, +1, +1, +1}; // 注目画素番号からライン方向のオフセット int nr_lines = dst.get_nr_lines(); // 処理対象画像のライン数 (縦の画素数) int nr_pixels = dst.get_nr_pixels(); // 処理対象画像のピクセル数 (横の画素数) int count = 0; // 細線化点の画素数 for (int iy = 0; iy < nr_lines; iy ++) { for (int ix = 0; ix < nr_pixels; ix ++) { unsigned char b = dst.p[iy][ix]; if (b == MIN_GRAY_LEVEL) continue; // 注目画素がすでに●(背景)の場合,何もしない。 // 注目画素を含む3×3領域を符号化する。 for (int k = 0; k <= 7; k ++) { a[k] = BACKGROUND_PIXEL; int x = ix + offset_x[k]; int y = iy + offset_y[k]; if (0 <= x && x < nr_pixels && 0 <= y && y < nr_lines) { b = dst.p[y][x]; if (b == MAX_GRAY_LEVEL || b == SKL_GRAY_LEVEL) { a[k] = FIGURE_PIXEL; } } } // 細線化条件を検査する。 for (int k = direction; k <= direction + 2; k ++) { // 注目画素を除く3×3領域において // 画素番号((k )%8)から連続する3画素が○(図形)のとき,trueとする。 bool fig = a[(k ) % 8] & a[(k + 1) % 8] & a[(k + 2) % 8]; // 注目画素を除く3×3領域において, // 画素番号((k+4)%8)から連続する3画素が●(背景)のとき,falseとする。 bool bck = a[(k + 4) % 8] | a[(k + 5) % 8] | a[(k + 6) % 8]; if(fig == true && bck == false) { dst.p[iy][ix] = SKL_GRAY_LEVEL; // 「細線化点を示す濃度値」に変更する。 count ++; } } } } if (count != 0) { // 「細線化点を示す濃度値」を●(背景)に変更する。 printf("%sの細線化条件において背景に変更した点は,%d点ありました。\n", msg, count); for (int iy = 0; iy < nr_lines; iy ++) { for (int ix = 0; ix < nr_pixels; ix ++) { if (dst.p[iy][ix] == SKL_GRAY_LEVEL) dst.p[iy][ix] = MIN_GRAY_LEVEL; } } } else { printf("%sの細線化条件において背景に変更した点は,ありませんでした。\n", msg); } return count; } // 元画像(src)をErode法で細線化処理して処理済画像に入れる関数 void skelton_erode( class image& src, // 元画像クラス(入力) class image& dst) // 処理済画像クラス(出力) { if (src.p == NULL) { printf("元画像がありません。"); return; } printf("\n2値画像をErode法で細線化処理します。\n"); int nr_lines = src.get_nr_lines(); // 元画像のライン数 (縦の画素数) int nr_pixels = src.get_nr_pixels(); // 元画像のピクセル数 (横の画素数) dst.gmake(nr_lines, nr_pixels); // 処理済画像の配列を確保 // 2値画像をコピーする。 for (int iy = 0; iy < nr_lines; iy ++) { for (int ix = 0; ix < nr_pixels; ix ++) { dst.p[iy][ix] = MIN_GRAY_LEVEL; unsigned char b = src.p[iy][ix]; if (src.p[iy][ix] == MAX_GRAY_LEVEL) dst.p[iy][ix] = b; } } int times = 0; // 細線化処理の回数 int skl_count; // 細線化点の画素数 do { times ++; printf("\n細線化処理:第%d回目の処理を実行中です。\n", times); // (1)の細線化条件細線化条件を満たす画素を●(背景)に変更する。 skl_count = erode_image(dst, LU_RD); // (2)の細線化条件細線化条件を満たす画素を●(背景)に変更する。 skl_count += erode_image(dst, RD_LU); // (3)の細線化条件細線化条件を満たす画素を●(背景)に変更する。 skl_count += erode_image(dst, RU_LD); // (4)の細線化条件細線化条件を満たす画素を●(背景)に変更する。 skl_count += erode_image(dst, LD_RU); } while (skl_count != 0); } // 元画像(src)に細線化処理した画像を重ね合わせた画像をつくる関数 void overlay( class image& src, // 元画像クラス(入力) class image& dst) // 細線化処理した画像クラス(入出力) { printf("\n細線化処理した画像に元の2値画像をグレイにして重ね合わせます。\n"); int nr_lines = src.get_nr_lines(); // 元画像のライン数 (縦の画素数) int nr_pixels = src.get_nr_pixels(); // 元画像のピクセル数 (横の画素数) for (int iy = 0; iy < nr_lines; iy ++) { for (int ix = 0; ix < nr_pixels; ix ++) { if (dst.p[iy][ix] == MAX_GRAY_LEVEL) continue; if (src.p[iy][ix] == MAX_GRAY_LEVEL) { dst.p[iy][ix] = SKL_GRAY_LEVEL; } } } } // プログラムの開始位置 int main() { class image src; // 元画像クラスを宣言 class image dst; // 処理済画像クラスを宣言 src.gload(); // 元画像をBMPファイルから読み込む // BMPファイルを指定したい場合は, // src.gload("パス付きBMPファイル名"); // とする。 // 元画像(src)をErode法で細線化処理して処理済画像に入れる skelton_erode( src, // 元画像クラス(入力) dst); // 処理済画像クラス(出力) // 元画像(src)に細線化処理した画像を重ね合わせた画像をつくる。 overlay( src, // 元画像クラス(入力) dst); // 処理済画像クラス(出力) dst.gsave(); // 処理済画像をBMPファイルに保存する // BMPファイルを指定したい場合は, // dst.gsave("パス付きBMPファイル名"); // とする。 }