デジタル画像とC言語
画像の表現 一般的に、画像は2次元配列で表現される 例:320x240(240行、320列)画素の濃淡画像 unsigned char image[240][320]; 説明: unsigned = 符号なし char = 文字型 unsigned char = 符号なしの文字型で 0~255 (= )の値が表現できる
画像の操作(1) 位置が(x,y)である画素は, y行、x列にある画素である。 画素値の読出し: 0 行 1 行 2 行 y 行 画素値の読出し: 例: (x,y)の画素の値を変数vに代入する。 (変数vは既に定義しているものとする) v = image[y][x];
画像の操作(2) 画素値の設定: 例: (x,y)の画素の値を128にセットする。 image[y][x] = 128; y 行 0 行 1 行 2 行 y 行 画素値の設定: 例: (x,y)の画素の値を128にセットする。 image[y][x] = 128;
画像操作の例:90度回転(1) y y’ x x y H x’ W W H 元画像の(x,y)の画素が回転した後の位置(x’,y’)とする。 x’= H -1 – y; y’= x; 元画像を表す配列: image 回転した後の画像を表す配列: image_new とすると、 image_new[x][H-1-y] = image[y][x]; で回転したあとの画素値が設定できる。
画像操作の例:90度回転(2) y y’ x x y H x’ W W H int x,y; for (y = 0; y < H; y++) for (x = 0; x < W ; x++) image_new[x][H-1-y] = image[y][x];
画像の移動(1) y Δy Δx x H H Δx + x W W 画像をX方向にΔx, Y方向にΔyを移動する。 (x,y)の画素が移動後に (x’,y’)なるとすると、 x’= x + Δx; y’= y + Δy;
画像の移動(2) y Δy Δx x H H Δx + x W W Δy + y 元画像を表す配列: image 回転した後の画像を表す配列: image_new とすると、 image_new[y+Δy][x+Δx] = image[y][x]; で移動したあとの画素値が設定できる。
しかし 画像内の移動(3) (x0,y0) 画像を表す配列: image 移動する矩形部分の左上の角の座標: (x0,y0) 横幅、縦幅: w, h 水平、垂直方向の移動量、dx, dy とすると、 int x, y; for (y = y0; y < y0+h; y++) for (x = x0; x < x0+w; x++) { xnew = x + dx; ynew = y + dy; image[ynew][xnew] = image[y][x]; } で図に示すように矩形部分の画像を移動することができる。 h dy w dx しかし
画像内の移動(1) (x0,y0) 移動元 と 移動先 と 重なる 部分があると、 処理は難しくなる。 dy h dx dy h 移動元 と 移動先 と 重なる 部分があると、 処理は難しくなる。 dy h dx dy h (x0,y0) dx
間違った! 画像内の移動 移動の順序(1) int x, xnew; for (x= 0; x < 4; x++) { 画像内の移動 移動の順序(1) int x, xnew; for (x= 0; x < 4; x++) { xnew = x + 2; image[xnew] = image[x]; } 移動前 正しい結果 1 2 3 4 5 6 7 8 9 1 2 1 2 3 4 7 8 9 1 2 1 4 5 6 7 8 9 x: 0, xnew: 2 image[2] = image[0] 1 2 1 2 5 6 7 8 9 x: 1, xnew: 3 image[3] = image[1] 1 2 1 2 1 6 7 8 9 x: 2, xnew: 4 image[4] = image[2] 1 2 1 2 1 2 7 8 9 x: 3, xnew: 5 image[5] = image[3] 間違った!
正解! 画像内の移動 移動の順序(2) int x, xnew; 画像内の移動 移動の順序(2) int x, xnew; for (x= 3; x >= 0; x--) { /* 逆の順でコピーする */ xnew = x + 2; image[xnew] = image[x]; } 移動前 正しい結果 1 2 3 4 5 6 7 8 9 1 2 1 2 3 4 7 8 9 1 2 3 4 5 4 7 8 9 x: 3, xnew: 5 image[5] = image[3] 1 2 3 4 3 4 7 8 9 x: 2, xnew: 4 image[4] = image[2] 1 2 3 2 3 4 7 8 9 x: 1, xnew: 3 image[3] = image[1] 1 2 1 2 3 4 7 8 9 x: 0, xnew: 2 image[2] = image[0] 正解!
画像内の移動 移動範囲 (x0,y0) 移動した後の矩形領域は画像の範囲を超えることがある。 dy 画像内の移動 移動範囲 (x0,y0) 移動した後の矩形領域は画像の範囲を超えることがある。 この場合、移動しようとする矩形の画像範囲からはみ出す部分を削り、移動した後も画像の範囲内になるようにする。 (削り=矩形の形を変える) dy dx (x0,y0) dy dx
実際にプログラムを書いてみよう 画像処理のプログラムを書くために、画像処理用のライブラリが要る。 理由: 下記の機能が必要である。 理由: 下記の機能が必要である。 ① 処理しようとする画像の読込み (ファイルなどから) ② 処理結果を保存する画像の用意 ③ 処理結果をファイルに保存する が、これらの部分を作るのは面倒で、難しい。
RASLIB:画像処理演習用ライブラリ RASLIBは、私(陳謙)が画像処理のプログラムを簡単に書けるために作ったライブラリである。 Linux版とWindows版両方あるが、Linux版をお勧めする。 以降の説明はLinux版に関するものである。 RASLIBのダウンロード ① ダウンロード:RASLIBのWEBページ http://www.wakayama-u.ac.jp/~chen/RASLIB/raslib.htm からダウンロードできます。 そのページの“RASLIBの入手”の章から、raslib.tgzというファイルをダウンロードしてください。 (firefoxのデフォールトのダウンロード先は $HOME/Desktop です。)
RASLIB:画像処理演習用ライブラリ RASLIBのインストール 1.端末ウィンドウを開く。 1.端末ウィンドウを開く。 2.端末ウィンドウで次の命令を入力することにより、 ダウンロードした raslib.tgz ファイルを自分のホームに 移動する。 cd mv $HOME/Desktop/raslib.tgz . 3.以下の命令を実行して、必要なディレクトリを作ってください。 mkdir include lib 4.ダウンロードしたファイルを解凍します。 tar xvzf raslib.tgz 5.ソフトウェアをコンパイルし、インストールします。 cd RASLIB make clean make PREFIX=$HOME install これでインストールが完了します。
RASLIBを使って画像を生成する(1) 16x16画素 0 1 2 . . . 15 15 16 17 . . . 31 0 1 2 . . . 15 16x16画素 15 16 17 . . . 31 32 33 34 . . . 47 240 241 242 . . . 255 256x256画素の濃淡画像: 中身は16x16個=256個の正方形の領域である。 1個の領域の大きさは16x16画素で、画素値は全部同じである。 /* Begin grey_image_16x16.c */ #include “raslib.h” /* RASLIBを使うプログラムにはこれが必要 */ int main(int argc, char **argv) /* main関数はこのように書く */ { Rasimg *img; /* 画像を現す関数。RASLIBでは、画像は Rasimg *型の変数で表現される。*/
RASLIBを使って画像を生成する(2) int block_x; /* 横のブロックの番号 */ int block_y; /* 横のブロックの番号 */ int v; /* ブロックの画素値 */ int x0, y0; /* ブロックの左上の角の座標 */ int x, y; unsigned char **image; /* 画像の中身を現す変数,画像を現す2次元配列のように使える */ img = ras_alloc(256, 256, 8); /* 256x256画素の濃淡画像(8bit)を用意する */ /* ras_alloc(横, 縦, ビット数) は 「横」x「縦」 画素で、 1画素が「ビット数」ビットの画像を用意するための関数である。*/ image = ras_lnidx(img); /* Rasimg *型の変数から、画像の中身を現す変数を取り出す。 その後、imageは2次元配列のように使える */ for (block_x = 0; block_x < 16; block_x++) { for (block_y = 0; block_y < 16; block_y++) { 現す関数。RASLIBでは、画像は Rasimg *型の変数で表現される。*/
RASLIBを使って画像を生成する(3) /* 画素値をセットする */ /* 画素値をセットする */ for (block_x = 0; block_x < 16; block_x++) { x0 = block_x * 16; for (block_y = 0; block_y < 16; block_y++) { y0 = block_y * 16; v = block_y * 16 + block_x; for (x = 0; x < 16; ++x) for (y = 0; y < 16; ++y) image[y+y0][x+x0] = v; } pnm_save(“grey256.pgm", img); return 0; } /* End */
RASLIBを使って画像を生成する(4) コンパイルと実行 1.grey_image_16x16.c を作ります emacs を使って、“ /* Begin grey_image_16x16.c */ から/* End */ までの部分の内容の「grey_image_16x16.c」というファイルを作る。 2 コンパイル grey_image_16x16.c は次のようにコンパイルする。 cc -I$HOME/include -L$HOME/lib grey_image_16x16.c -o grey_image_16x16 -lras 3 コンパイルしたプログラムを実行する ./grey_image_16x16 4 実行結果を確認する gimp grey256.pgm 練習問題1: grey_image_16x16.cを改造して(pnm_saveの前に追加)、作ったグレーブロックの画像を90度回転するプログラムを作りなさい。