パターン認識プログラミング(調査製作WS・荒井担当分)・第1回

画像処理プログラム

※サンプルプログラムのダウンロードはこのページの下の方※

◆プログラムにおける画像データの扱い

画像データをプログラムで扱う場合、二次元配列を利用する。たとえば、上記の3x3の画像データの場合、次のように3x3の二次元配列として表現する。なお、C言語の配列としては、実は正しくないのですが、次のように考えておこう。

↓y x→

x=0

x=1

x=2

y=0

0

0

0

y=1

1

1

0

y=2

1

1

1

上記は画像データで、各々の画素(Pixcel)が0(白)か1(黒)で表現されている。これをC言語で扱う場合には一般的に次のような(x, y)座標の二次元配列として扱う。

(0,0)

(0,1)

(0,2)

(1,0)

(1,1)

(1,2)

(2,0)

(2,1)

(2,2)

例えばこの二次元配列変数をmapとすると、(x,y)=(0,0)の位置は、map[0][0]と表現でき、0(白)が記録されている。また(1,2)の位置はmap[1][2]と表現し1(黒)が記録されている。

二次元配列変数の宣言は int map[3][3]; とし、map[0][0]=0;などと利用することができる。たとえば全ての配列の要素を0で埋める場合、

for( x=0; x<3; x++ ){
  for( y=0; y<3; y++ ){
    map[x][y] = 0;
  }
}

などのようにプログラムすればよい。

※参考;正しいC言語の2次元配列について
本授業では、正方形の配列(画像)のみを扱うので上記のように考えて扱っても問題ないが、実際(正確)には、配列の行列と画像の縦横は逆である。つまり、画像の横xは、配列の列に相当し、画像の縦yは配列の行に相当する。よって、本当は画像データ横方向をx、縦方向をyとする場合、C言語ではmap[x][y]と宣言するのではなく、map[y][x]として宣言するのが正しい。
もしくは、画像データの横をy、縦をxと考えてmap[x][y]と宣言してもよい。

※通常の変数や2次元配列変数については、簡単な説明を→「こちら」のページに記しているので参照のこと!
※配列が分からないと、残念ながらプログラムは完成できません。

ここでmap[][]は縦横につながった変数であり、具体的にmap[0][0]は左上の画素である。for文により、map[y][x]のxとyを次々に0,1,2と変えることにより、上記プログラム例では3x3全ての画素に各々0を代入している。

●C言語による画像処理プログラムの基礎

先に述べたように、画像データは通常二次元配列で表現する。
C言語における二次元配列は、まず宣言を、たとえば
int map[20][20];
などとし、これでは20x20画素の画像データを20x20の二次元配列で表現している。
また配列の各要素、つまり画素にはint(整数)を入れることができる。ここでは、各画素は0(白)、1(黒)のみを入力することにする。
なお、上記のように「int map[20][20];」で宣言した場合、各要素はmap[0][0], map[0][1],・・・,map[0][19], map[1][0],・・・,map[x][y],・・・,map[19][0],・・・,map[19]18], map[19][19]までである。少し数学的な表現をするならば、map[x][y] {但しx=0,…,19, y=0,…,19}となる。

○ヒストグラム(度数分布)

ここでは縦方向のヒストグラムを考える。
例えば、3x3の画像で、次のような画像データである場合、縦方向のヒストグラムを求めるプログラムを考えてみよう。
□■■  0 1 1
□□■  0 0 1
□□□  0 0 0
一番左側の列は、白だけで黒(1)が一つもなく、黒の数は0となる。真ん中の列は黒(1)の数は1、右の列は黒(1)の数は2である。よって、ヒストグラム(図)は、

  ■
 ■■

つまり、数値で表すと
0 1 2
となる。
このように黒の数を縦の列ごとに数えればよい。つまり縦の列ごとに、黒があったらカウントアップしていけばよい。
しかし、ここでちょっと考えてみると、面積と同じように比較的簡単にヒストグラムを求めることができることがわかる。今、白は0で、黒は1で表現されている。そこで、単純に縦の列ごとに合計を求めればよい。真ん中の列を例にすると、□+□+■、つまり0+0+1=1となる。
画像データの二次元配列をm[ ][ ]とし、縦方向の度数を格納する変数を一次元配列ti[ ]とした場合、次のようなプログラム(一部)でヒストグラムを求めることができる。

int m[3][3];
int tx[3];
for( x=0; x<3; x++ ){ //縦方向の列ごとに求める
  tx[ x ] = 0; //合計を求めるのでまずクリアしておく
  for( y=0; y<3; y++ ){ //縦に順番にみていく
    tx[x] = tx[x] + m[y][x];
  }
}

※C言語についての簡単な復習は、→こちらを参照

来週は教科書を持参してくること。勿論若干であればWEBで検索しても大丈夫


◆サンプルプログラム

この授業で使う画像処理のプログラムのひな形を用意しました。

まず⇒「こちらからダウンロード」して、適当な所に保存し、そのZIPファイルを解凍してください。解凍先は必ず自分のホーム内やUSBメモリなど保存できる場所とすること!

解凍すると「PatRcgXXX」というフォルダ(XXXは任意の文字列)が作成されます。

◆プログラムの修正&実行方法

「PatRcgXXX」フォルダの下に、「PatRcg.sln」というファイルがあるので、これをダブルクリックする。
すると、Visual Studio(VS)が起動し、必要なファイルが読み込まれる。

VSの右側(もしくは左側)の「ソリューションエクスプローラー 」の「PatRcg」→「ソースファイル」→「main.c」をダブルクリックすると、中央の大きなウィンドウにC言語による画像処理のサンプルプログラムが表示される。

まず最初に、実行してみよう。

「デバッグ」メニュー→「デバッグ開始」を選択すると、「ビルドしますか?」と聞かれるので→「はい」を選択する

すると、ビルド(つまりコンパイル)されて、エラーがなければプログラムの実行が始まる。

エラーがあった場合は、VSの下「画面」ウィンドウにてエラー内容を確かめ、プログラムを修正して、繰り返す。

・実行すると、まずエラーが出るようになっている。
単純なミスなので、修正して実行し直してみよう。
※「error」(エラー)と「warning」(警告)があるが、まず、errorから見ていくこと!

・修正後実行すると、sankakuMap[][]配列の画像が■と□で表示される。

・次に、面積が表示される。
面積をどうやって求めているかをプログラムをきちんとみて確認しよう。

○面積以外の特徴を抽出するプログラムはまだ未完成です。
よって、順次これらを完成させていこう。

・まず「エッジ抽出」部分のプログラムを完成させよう。

2乗は、pow()関数を使ってもよいが、単純に掛け算を利用してみよう。つまり、(x) * (x) のようにすれば2乗が計算できる。
ルート(√)は、sqrt()関数を使おう。
for文のループ条件に十分注意しよう。単純にi,jを0〜19ではちょっとまずい。なぜなら、隣(右及び下)の配列要素を見るので、はみ出てしまってはいけないからである。

十分に綺麗なエッジではないが、エッジらしく処理されたことを確認しよう。

・次に「ヒストグラム」部分のプログラムを完成させよう。

ヒストグラムは縦と横を間違えなければ比較的簡単。数を数えるのではなく、足していけばよいことを利用しよう。

・そして「3分割ヒストグラム」のプログラムを完成させよう。
大中小を判定していくが、どのような数値にしたらよいのかは各自で考えること。