10 1 画像の入力・補正・出力 例題 1 -4 : ヒストグラム平滑化 原画像のヒストグラムを平滑化するプログラムを作成せよ . ただし , 図 1.6 に示した方法を用い , 平滑化後の階調数を 64 階調にせよ . 回答例 : / * ヒストグラム平滑化のプログラム smth_hst. c * / #include く stdio. h> #include く stdlib. h> #include"mypgm. h" #define FINAL_LEVEL 64 / * 最終的な表現階調数 * / void smooth—histgram( ) /*imagel のヒストグラムを平滑化して image2 へ * / long int hist1[GRAYLEVEL], hist2[GRAYLEVEL] ; int trans_tabIe[GRAYLEVEL] ; だ濃度変換表 * / int i, x, y; だループ変数 * / long int target—value; だ変換後の頻度の目標値☆ / int gray; / * 階調用作業変数 * / double gray-step; / * 表現階調間隔ま / printf(" ヒストグラムの平滑化を行います . yn"); / * 原画像のヒストグラムを求める for ( i = 0 ; i く GRAYLEVEL; i + + ) histl[i] = 0 ; for()= 0 ; y<y_sizel; y 十十 ) for(x=0; x<x_sizel; x 十十 ) histl [ imagel [x][y] ] + + ; / * ヒストグラム変換表を作る * / target—value = (int)( x—sizel * y—sizel / (double)FlNAL LEVEL ) ; for ( i = 0 ; i く FINAL—LEVEL; i + + ) hist2 [i] = 0 ; gray = 0 ; for ( i = 0 ; i く GRAYLEVEL; i + + ) { if ( abs( target—value - hist2[gray]) く abs( target-value - ( hist2 [gray] + histl [i]) ) ) { gray 十十 ; if ( gray > = FINAL—LEVEL ) gray = FINAL—LEVEL - 1 ; trans—table[i] = gray; hist2 [gray] = hist2[gray] + histl 国 ; / * ヒストグラムを平滑化した画像を image2 に代入 * /
7 動画像処理 void calc motion_vector( int x, int y, int *vx, int *vy ) だ imagel の点 ( x , y ) の速度べクトル (*vx, * vy ) を決定する . * / だテンプレートに関する変数 * / int i, 」 , m, n, xp, yp, xs, ys; だ制御変数 , 作業用変数 * / だこの値以下の場合は信頼性が低いので対応点検出しない int threshold—for—gray = 30 ; だテンプレート内の階調差が * / int y—offset = 30 ; だ y 方向探索範囲 [-y—offset, y—offset] * / int x—offset = 30 ; だ x 方向探索範囲 [-x—offset, x—offset] * / 4 ; int y—tmp = だ y 方向サイズ [-y_tmp, y_tmp]*/ 4 ; int x—tmp = だ x 方向サイズ [-x_tmp, x_tmp]*/ static unsigned int tmp—image[100][100]; だ最大 100X100 画素 テンプレート内最小 , 最大階調 * / だ誤差率 ( 0 以上 1 以下 ) * / だ誤差の和 , 誤差の最小値響 ート中の画素数 ( 画像外を無視 ) } else { *vx = 0 ; y - y—tmp < 0 凵 y - y—tmp > = y—sizel ) { if ( x - x_tmp < 0 Ⅱ x + x—tmp > = x—sizel Ⅱ / ☆テンプレートの一部が画像外に出る点は速度 0 にする * / double min—gray, max—gray; / * double error ratio; double sum, mln error; int num of_temp; だテンプレ 161 (x,y) を中心とするテンプレート tmp-image の切り出し☆ / num—of_temp = ( 2 * x—tmp + 1 ) * ( 2 * y—tmp + l); だ最小 , 最大階調 * / min—gray = 255 ; max—gray = 0 ; for ( i = - y_tmp; i く = y—tmp; i 十十 ) { for (j = - x—tmp; j <= x—tmp; j 十十 ) { yp = y 十 i; xp = x 十」 ; tmp—image[i 十 y—tmp][j 十 x—tmp] = imagel[yp][xp] ; if ( image I[YP][XP] < min—gray ) min—gray = imagel[yp][xp] ; else if ( image l[yp][xp] > max—gray ) max—gray = imagel[yp][xp] ; if ( ( max—gray - min—gray ) く = threshold—for—gray ) { *vy = 0 ; *vx = 0 ; だテンプレート内の階調変化があまりない場合は速度 = 0 にする☆ /
208 9 遺伝的アルゴリズムによる処理 if ( 0 く = ⅸ 2 & & ix2<x—size2 & & 0 く = iy2 & & iy2<y—size2 ) { sum = sum + abs( image2[iy2][ix2] - imagel[y][x]); if ( image2[iy2][ix2] > max_gray ) max—gray = image2[iy2][ix2] ; if ( image2 [iy2][ix2] く min—gray ) min—gray = image2 [iy2][ix2] ; if ( flag = image2 [iy2][ix2] = (unsigned char)( MAX BRIGHTNESS - image2 [iy2][ix2]); } else sum = sum + MAX BRIGHTNESS; / * あまり平坦な領域は候補としないための処理ま / if ( max—gray - min—gray く MIN RANGE ) sum = 0.1 ; else sum = 1.0 - sum / ( x sizel * y—sizel ) / MAX BRIGHTNESS; return sum; void calculate_fitness( ) / * 全員の適応度を求めるま / int i; だループ変数 * / for ( i = 0 ; i く pop_size; i 十十 ) fitness[i] = fitness_value( i, 0 ) ; void display—elitest( int generation ) だ最良個体の遺伝子型 , 適応度を画面に表示する * / inti;/* ループ変数 * / printf("No. %d : ",generation); for ( i= 0 ; i く gene_slze; i 十十 ) { printf("%d" elite_genotype[i]); if ( ( i + 1 ) % 8 = = 0 ) printf(" " ) ; printf("--> %fVn", elite fitness); void generation_iteration( ) だ世代交代を行う関数 * /
6 立体認識 133 だテンプレートは画像内にあるとして初期化 * / out_flag = 0 ; for ( i = - y_tmp; i <= y_tmp; i 十十 ) { for (j = - x—tmp; 」く = x_tmp; j 十十 ) { xp = xL 十 j; yp = YL 十 i; if ( xp<0 Ⅱ xp>x_sizel Ⅱ yp<O Ⅱ yp>y—sizel ) / * 画像外 * / out_flag = 1 ; else { num of—temp 十十 ; tmp—image[i 十 y—tmp] [j 十 x—tmp] = image I[YP][XP] ; if ( imagel[yp][xp] < min-gray ) min—gray = im a ge l[yp][xp] ; else if ( image l[yp][xp] > max—gray ) max—gray = imagel [yp][xp] ; if ( ( max—gray - min—gray ) く = threshold—for—gray Ⅱ out_flag = *xR=xL- 1 ; *yR = yL; / * テンプレート内の階調変化があまりない場合 , または だテンプレートの一部が画像の外に出てしまうときは * / / * 視差を 1 ( 遠方 ) に設定する * / } else { だ探索点の決定 min_error = 10000.0 ; だ最小誤差の初期化 * / for ( m = - y—offset; m く = y—offset; m + + ) { for ( n = - x offset; n < 0 ; Ⅱ + + ) { ys = yL 十 m; XS = XL 十 n; だ ( xs , ys ) を対応点としたときの誤差の計算 if ( xs>=O & & xs<x—sizel & & ys>=0 & & ys<y—sizel ) { sum= 0.0 ; だ誤差の総和の初期化 * / / * マッチングを行う響 for ( i = - y_tmp; i <= y_tmp; i + + ) { for ( j = - x—tmp; j く = x—tmp; j 十十 ) { xp = xs 十 j; yp = ys 十 i; if ( xp>=0 & & xp<x_sizel & & yp>=0 & & yp<y—size 1 ) { sum = sum 十 abs( tmp_image[i 十 y_tmp][j 十 x_tmp] - image2 [YP][XP]); だ誤差 = 各画素の階調値の差分の絶対値響
1 画像の入力・補正・出力 だ新しい階調 ( 16 階調での値 ) * / int ne w—gray ; int x—block, y—block; だ横・縦のプロック数 * / intx, y, i,j, m, n; だ制御変数 * / int dither_matrix [ 4 Ⅱ 4 ] = { / * Bayer 型デイザ行列 * / { 0 , 8 , 2 , 10 } , { 12 , 4 , 14 , 6 } , 1 , 9 } , { 3 , 11 , { 15 , 7 , 13 , 5 } だ横 , 縦の画素数が BLOCK_SIZE の倍数であるかのチェック * / else image2[y + m][x + 司 = MAX BRIGHTNESS; image2[y + m][x + 司 = 0 ; if ( image2 [y + m][x + 司 <= dither-matrix[m][n]) for ( n = 0 ; n く BLOCK SIZE; n + + ) { for ( m = 0 ; m く BLOCK—SIZE; m + + ) { y = BLOCK SIZE * i; x = BLOCK_SIZE 勹 ; for (j = 0 ; j く x—block; j + + ) { for (i = 0 ; i く y_block; i + + ) { y—block = y—sizel / BLOCK SIZE; / * 縦のプロック数ま / x block = x_sizel / BLOCK—SIZE; / * 横のプロック数 * / printf(" デイザ画像を作ります . vn"); だデイザ画像を作る * / image2[y][x] = (unsigned char)new_gray; new—gray = NEW—LEVEL - 1 ; if ( new—gray > NEW—LEVEL - 1 ) new-gray = (int)( imagel [y][x] / width ) ; for()= 0 ; x<x—sizel; x + + ) { for()= 0 ; y<y_sizel;y + + ){ y—size2 = y—sizel; X Size2 = X sizel; width = MAX BRIGHTNESS / (doubIe)NEW_LEVEL; だ 16 階調の画像を作る * / exit(l); printf(" 原画像の横・縦の画素数が不適切です . vn"); if ( x—sizel % BLOCK—SIZE ! = 0 Ⅱ y_sizel % BLOCK—SIZE ! = 0 ) { 13
付録 B mypgm. h void load_image—data( ) char buffer[MAX_BUFFERSIZE]; / * データ読み込み用作業変数 * / char file—name[MAX FILENAME]; だファイル名用の文字配列 * / だ imagel[ Ⅱ ] , x-sizel, y-sizel にそれぞれ代入する . /*pgm 画像 , 横画素数 , 縦画素数のデータをファイルから読み込み , * / printf(" ファイル形式は pgm, バイナリ形式とします . vn"); printf("- printf(" モノクロ階調画像入力ルーチン¥Ⅱ " ) ; printf("- / * 入力ファイルのオープン * / int x, y; / * ループ変数 * / int max-gray; だ最大階調値 * / FILE *fp; / * ファイルポインタ if(buffer[0] ! = Ⅱ buffer[l] ! = ' 5 ' ) { fgets( buffer, MAX BUFFERSIZE, fp ) ; だファイルタイプ ( = P5 ) の確認 * / exit(l); printf ( " その名前のファイルは存在しません . *n"); if( NULL = = fp ) { fp = fopen( file name, "rb" ) ; scanf("%s",file name); printf(" 入力ファイル名 (*.pgm) : " ) ; /*x-sizel, y-sizel の代入 ( # から始まるコメントは読み飛ばす ) * / exit(l); printf(" ファイルのフォーマットが P5 とは異なります . vn"); fgets( buffer, MAX BUFFERSIZE, fp ) ; while ( max_gray = max—gray = 0 ; /*max-gray の代入 ( # から始まるコメントは読み飛ばす ) sscanf( buffer "%d %d" &x sizel, &y_sizel ) ; if ( buffer[0] ! = ' # つ { fgets( buffer, MAX BUFFERSIZE, fp ) ; while ( x sizel = = 0 Ⅱ y_sizel = y—sizel = 0 ; x_sizel = 0 ; 233
132 解答例 6 立体認識 だステレオマッチングのプログラム stereo. c*/ #include<stdio. h> #include く stdlib. h> #include く limits. h> #include"mypgm. h" void copy_imagel—t0—image2( ) / * imagel を image2 へコヒ。ーする * / int x, y; / * ループ変数ま / x_size2 = X Size1; y—size2 = y_sizel; for (y=0; y<y_sizel; y 十十 ) for()= 0 ; x<x_sizel; x 十十 ) image2[y][x] = imagel[y][x] ; void determine_corresponding—point( int xL, int yL, int *xR, int *yR ) / ☆左画像の ( xL , yL ) の右画像上の対応点 ( * xR , * yR ) を決定する * / だテンプレートに関する変数 * / static unsigned int tmp_image[100][100] ; だ最大 100X100 画素 int x_tmp int y—tmp int x_offset = 128 ; 5 ; 3 ; / * x 方向サイズ [-x_tmp, x_tmp] * / / * y 方向サイズ [-y_tmp, y_tmp] ツ だ x 方向探索範囲 [-x_offset, 0 い / だ左画像を基準にすると視差は負なので正方向には動かさない * / intout—flag; / * テンプレートの一部が外に出るとき 1 , else 0 * / int threshold_for—gray = 20 ; だテンプレート内の階調差が * / だこの値以下の場合は信頼性が低いので対応点検出しない 1 ; / * y 方向探索範囲 [-y_offset, y_offset]*/ int y_offset = だ左右カメラの上下のぶれを考慮しないときは y_offset=o * / int i, j, m, n, xp, yp, xs, ys; int num of—temp = 0 ; double sum, mm_error; double error ratio; だ制御変数 , 作業用変数 * / だテンプレート中の画素数ツ / * 誤差の和 , 誤差の最小値 * / / * 誤差率 ( O 以上 1 以下 ) double min—gray, max_gray;/* テンプレート内の最小 , 最大階調 だ (xL,yL) を中心とするテンプレー num of—temp = 0 ; min—gray = 255.0 ; max—gray = 0.0 ; ト tmp—image の切り出し * / / * テンプレート中の画素数 * / だテンプレート内の最小階調値の初期化 * / / * テンプレート内の最大階調値の初期化 * /
234 付録 B mypgm. h sscanf( buffer, "%d" &max—gray ) ; / * パラメータの画面への表示 * / printf(" 横の画素数 = %d, 縦の画素数 = %d*n", x-sizel, y-sizel ) ; pr ⅲ tf ( " 最大階調値 = %d*n",max-gray); if ( x—sizel > MAX IMAGESIZE Ⅱ y—sizel > MAX IMAGESIZE ) { printf(" 想定値 %d x %d を超えています . *n" MAX IMAGESIZE, MAX_IMAGESIZE); printf(" もう少し小さな画像を使って下さい . *n"); exit(l); if ( max—gray ! = MAX BRIGHTNESS ) { printf ( " 最大階調値が不適切です . *n"); exit(l); だ画像データを読み込んで画像用配列に代入する☆ / for ()= 0 ; y<y—sizel; y + + ) { for()= 0 ; x く x—sizel; x + + ) { imagel[y][x] = (unsigned char)fgetc( fp ) ; printf ( " データは正しく読み込まれました . *n"); printf("- fclose(fp); void save_image—data() だ image2[ Ⅱ ] , x-size2, y-size2 のデータを , それぞれ pgm 画像 , * / だ横画素数 , 縦画素数としてファイルに保存する . char file_name[MAX FILENAME]; だファイル名用の文字配列 FILE*fp;/* ファイルポインタ * / intx, y; / * ループ変数 * / / * 出力ファイルのオープン * / printf("- printf(" モノクロ階調画像 (pgm 形式 ) 出力ルーチン vn"); printf(" - printf(" 出力ファイル名 (). pgm) : " ) ; scanf("%s" file name);
9 遺伝的アルゴリズムによる処理 for ( i = 0 ; i く 8 ; i + + ) { *y = *Y * 2 + code[i + 8]; *x=*x*2 + code[i]; *rate * 2.0 + code[i + 16]; *rate = *angle = *angle * 2.0 十 code[i + 24] ; / 吉コードから実際の値への変換 * / *x = (int)( *x / 255.0 * x size2 ) ; *y = (int)( *y/ 255.0 * y—size2 ) ; / * の適応度を返す ( flag=0 : 通常 , = 1 : 最終画像作成 ) * / / * set—optimizing—task( ) で説明されている個体 No. number double fitness—value( int number, int flag ) if ( *angle < 0 ) *angle = 360.0 + *angle; *angle = ANGLE RANGE * *angle / 255.0 - ANGLE RANGE / 2.0 ; *rate = ( MAX RATE - MIN_RATE ) * *rate / 255.0 + MIN RATE; 207 int x, y; / * 座標用変数 * / だ作業用変数 int xp,yp,ix2,iyX int x—half, y-half, / * 画像サイズの半分 double x1,y1,x2,yX だ空間変換用変数 * / double rate, angle; / * 拡大倍率 , 回転角度 * / だ適応度用作業変数 * / double sum; double min-gray, max-gray; だ領域の最小・最大階調値 * / / * sin, cos 用変数 * / double S1n, cos; / * 遺伝子型から (x,y) へ * / trans_from—genotype—to—parameters( number, &xp, &yp, &rate, &angle ) ; だ適応度の計算ま / y_half = y_sizel / 2 ; x half = x_sizel / 2 ; sum = 0.0 ; min—gray = MAX BRIGHTNESS; max—gray = 0 ; —sin = sin( angle * PI / 180.0 ) ; —cos = cos( angle * PI / 180.0 ) ; for ()= ();y<y_sizel;y 十 + ){ for ()= 0 ; x<x_sizel; x + + ) { だテンプレートの各点 ( xl , yl ) に対する空間変換響 = (int)x2; iy2 = (int)y2; だ画像上の対応点響 x2 = x2 十 xp; y2 = y2 + yp; y2 = —sin * yl; COS * XI - sm * xl 十 cos *yl; yl = yl * rate; xl = xl * rate; yl = y - y—halfi xl = x - x halfi ⅸ 2 x2 = だ対応点での階調値の差分を求める * /
1 画像の入力・補正・出力 buf[y][x] = 0.0 ; for (y = 0 ; y く y—sizel; y + + ) { for()= 0 ; x<x—sizel; x + + ) { 返か出る . と . きは里 2 値化する .. ツ だ近傍に応じて次の式を変える☆ / err3 = err2; image2[y][x] = MAX BRIGHTNESS; } else { err3 = errl; image2 [y][x] = 0 ; if( errl ま errl く err2 * err2 ) { err2 = modified—gray - MAX BRIGHTNESS; errl = modified—gray - 0.0 ; modified-gray = imagel[y][x] + buf[0][x] ; } else { else image2 [y][x] = MAX BRIGHTNESS; image2 [y][x] = 0 ; ・羸Ⅱ効萇 MAX ・ / 2 ) 三 if ( x = = x-sizel - 1 Ⅱ y..r=.y.-sizel - 1 ) { 三← A = buf[l][x] + err3 * 3.0 / 8.0 ; 三 buf[l][x + 1] = buf[l][x + 1] + err3 ☆ 2.0 / 8.0 ; 三ぐーー B ! buf[O][x + 1] = buf[()][x + 1] + err3 * 3.0 / 8.0 ; 三 b uf[ 1 ][x] 17 for ()= 0 ; x<x—sizel; x + + ) { b uf[0][x] = buf[ 1 ][x] ; buf[l][x] = 0.0 ; main( ) だ画像データを imagel に読み込む * / load—image—data( ) ; make-error-difusion-image( ) ; だ誤差拡散画像を作成する * / だ image2 を保存する * / save—image—data( ) ; return 0 ; 実行例 : 図 1.11 ( a ) に示す階調画像を誤差拡散法を用いて 2 値画像として表現した