• 検索結果がありません。

Microsoft PowerPoint - handout10.ppt

N/A
N/A
Protected

Academic year: 2021

シェア "Microsoft PowerPoint - handout10.ppt"

Copied!
8
0
0

読み込み中.... (全文を見る)

全文

(1)

応用プログラミング 第10回

~プログラミングの応用

画像処理その3

電気通信大学電子工学専攻

Intelligent Electronic Systems Group

長井 隆行

2

本日の内容

1. typedefと#define 2. カラーからグレースケールへ 3. 輝度の変換 4. 画像の2値化 5. 画像を認識する † 画像認識 † 文字認識 † パターン(テンプレート)マッチング 6. 数字認識の例 7. 課題

補足

† BYTEについて „ p9-2.cでいきなり出現 unsigned char 型の別名を定義しただけ (定義はmybmp.hに書いてあります) #include <stdio.h>

#include <stdlib.h> /*mallocを使うために必要*/ #include <memory.h> /*memsetを使うために必要*/

#pragma pack(2) /*構造体のメンバーの境界整列を制御(おまじないだと思ってよい)*/ #define BMP_HEADER_SIZE 54 /*ビットマップのヘッダは全部で54バイトあります*/

typedef unsigned char BYTE;

/*ビットマップファイルヘッダのための構造体定義*/ ・・・ mybmpx.hの最初の方

typedef

† typedef を使うと既存の型を自分の好きな呼び名で呼ぶ ことができる † unsigned charというのは長くてうつのが面倒なので、 BYTEという別名を定義した † 構造体などにも使える struct tagBITMAPFILEHEADER bmfh; typedefstruct tagBITMAPFILEHEADER

{

unsigned short bfType; unsigned long bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned long bfOffBits;

}BITMAPFILEHEADER; BITMAPFILEHEADER bmfh;

(2)

5

#define

† 似た機能で #define というのもある „ これは単なる文字列の置き換え(typedefは既存の型の別名を 定義するものなので違いに注意) 例) #define PI 3.1415 † 「PIという文字列がプログラム中に出てきたら、3.1415と いう文字列で置き換えなさい」 † プログラムの文字列レベルで置換が起きる „ プログラムをうつのが楽になる „ 具体的な数字がプログラム中にあるよりも意味のある文字で置き 換えた方が分かりやすい „ 後から値を変更しやすい

† #define BYTEunsigned char とできるが、型の場合はtypedefを使っ

た方がよい セミコロンはいらない! 6

#defineを使った例

#include <stdio.h> #define NUM 5 /*人数*/

typedef unsigned char BYTE;

/*構造体のプロトタイプ宣言*/

typedef struct seiseki {

int code; /*学籍番号*/ BYTE eng; /*英語の点数*/ BYTE math; /*数学の点数*/ char name[50]; /*名前*/ }SEISEKI; /*メイン関数*/ int main(void) { int i; SEISEKI classA[NUM]; /*計算には特に意味はない*/

for(i=0; i<NUM; i++){ classA[i].code=i+1; classA[i].eng = i*10; }

/*表示(構造体配列のポインタに注意!)*/

for(i=0; i<NUM; i++){

printf("code %d score(eng) %d ¥n", (classA+i)->code, (classA+i)->eng); } return 0; } p10-1.c 7

回転の問題 (補足)

規模の小さな具体的な問題で具体的に考えると分かりやすい 1 2 3 4 5 6 7 8 1 23 4 56 7 8 width height width2=height height2=width buf2[(height2-x-1)*width2+y] = buf[y*width+x]; y*width+x=2 (x=2, y=0) (height2-x-1)*width2+y=2 (x=2, y=0) x y x y x*width2+y (height2-x-1)*width2+y y*width+x xとyの入れ替え 上下の入れ替え 8

カラーからグレースケール

† 前回は画素を移動しただけ(回転など) † 画像処理の本質は、画素値を演算によって得ること ⇒フィルタリング(ぼかし、鮮鋭化など:ディジタル信号処理) † 色の変換 † カラー画像を白黒濃淡画像に変換するにはどうすれば?

(3)

9

カラーからグレースケール 続き

† ITU standard: Y = (222*Red+707*Green+71*Blue)/1000 † NTSC standard: Y = 0.2989*R + 0.5870*G + 0.1140*B † RとGとBの値を平均するのが一番簡単 † Y=(R+G+B)/3 † グレースケールのビットマップは、R=G=B=Yとすることで作る (他のやり方もあるがこれが一番簡単) 10

グレースケールへの変換プログラム

#include <stdio.h> #include <stdlib.h> #include "pgm.h" int main(void) { 省略 /*出力用*/

Rbuffer2 = (BYTE*)malloc( width*height ); /*メモリ確保*/

Gbuffer2 = (BYTE*)malloc( width*height ); Bbuffer2 = (BYTE*)malloc( width*height );

/*****************画像処理をここで行う********************/

for(y=0; y<height; y++){ for(x=0; x<width; x++){

Rbuffer2[y*width+x] = (BYTE) ((Rbuffer[y*width+x]+Gbuffer[y*width+x]+Bbuffer[y*width+x])/3.0); Gbuffer2[y*width+x] = Rbuffer2[y*width+x]; Bbuffer2[y*width+x] = Rbuffer2[y*width+x]; } } /*******************ここまで******************************/ /*書き込み処理*/

Plane2RGB(buffer, Rbuffer2, Gbuffer2, Bbuffer2, width, height); /*bufferは入力のものを転用する*/

SaveBitmap("result.bmp", buffer, width, height);

省略 } p10-2.c

輝度の変換

† 全体的に暗い画像を明るくしたい! † 各画素を定数倍する(定数の大きさによって明るさが変化) † カラーでも、グレースケールでも基本は同じ ×定数 ×定数 ×定数 画像の位置によって定数の大きさを変化させれば、特定のものだけを明るくすることもできる

但し・・・

† 単純に定数倍すると失敗する可能性が高い † プログラム上の問題 ⇒解決するにはどうすればいいでしょうか? double tmp_pix; double const_val=2; /*輝度を2倍にする*/ /*****************画像処理をここで行う********************/

for(y=0; y<height; y++){

for(x=0; x<width; x++){

tmp_pix = const_val*Rbuffer[y*width+x]; Rbuffer2[y*width+x] = (BYTE) tmp_pix; tmp_pix = const_val*Gbuffer[y*width+x]; Gbuffer2[y*width+x] = (BYTE) tmp_pix; tmp_pix = const_val*Bbuffer[y*width+x]; Bbuffer2[y*width+x] = (BYTE) tmp_pix; }

(4)

13

ミニテスト(問1)

† 輝度を定数倍するプログラムの問題を解決しましょう † まず、何が問題かを突き止めましょう † プログラムを修正しましょう † ヒント:画素を表現するのに使っている型がポイント

(BYTEは unsigned charを定義しなおしたものです) double tmp_pix;

double const_val=2; /*輝度を2倍にする*/ /*****************画像処理をここで行う********************/

for(y=0; y<height; y++){

for(x=0; x<width; x++){

tmp_pix = const_val*Rbuffer[y*width+x]; Rbuffer2[y*width+x] = (BYTE) tmp_pix; tmp_pix = const_val*Gbuffer[y*width+x]; Gbuffer2[y*width+x] = (BYTE) tmp_pix; tmp_pix = const_val*Bbuffer[y*width+x]; Bbuffer2[y*width+x] = (BYTE) tmp_pix; } } 14

バナナを取り出せ!

† 画像中のバナナだけを取り出すにはどうすればよいか? if(画素値 == バナナの色) { 画素値*1 }else{ 画素値*0 } 注1)閾値はそれぞれの画像で異なっている 注2)別にバナナが死ぬほど好きなわけではない p10-4.c (ネットで集めた果物の画像付) 15

画像から意味のある情報を取り出す

† 2値化 ⇒ 濃淡画像を白黒に変換する „ 意味のある情報を取り出す(情報を圧縮する) „ デザイン効果 16

画像の2値化

width height グレースケール画像 新しい画像用のバッファ (入れ物) width height Color2Gray 指定したファイル名 で保存 出力 画素値 閾値Threshold 255 0 image1[0][x] ハードリミット関数 Rbuffer[0] Rbuffer[1] Rbuffer[2] Rbuffer[width-1] Rbuffer2

(5)

17

ミニテスト(問2)

† 2値化するプログラムをつくりましょう † ヒント „ グレースケールの画素値が閾値(Threshold)より大きけ れば255,小さければ0をRbuffer2[i]に入れればよい „ Gbuffer2[i], Bbuffer2[i]も同じものを入れる „ 「もし~なら・・・、そうでなければ・・・」はどのようにします か?思い出しましょう 18

2値化プログラムの例1

int main(void) { 省略 double tmp_pix; double threshold=100; /*閾値*/ /*出力用*/

Rbuffer2 = (BYTE*)malloc( width*height ); /*メモリ確保*/

Gbuffer2 = (BYTE*)malloc( width*height ); Bbuffer2 = (BYTE*)malloc( width*height );

/*****************画像処理をここで行う********************/

for(y=0; y<height; y++){ for(x=0; x<width; x++){ tmp_pix = ((Rbuffer[y*width+x]+Gbuffer[y*width+x]+Bbuffer[y*width+x])/3.0); if(tmp_pix > threshold) { Rbuffer2[y*width+x] = 255; Gbuffer2[y*width+x] = 255; Bbuffer2[y*width+x] = 255; }else{ Rbuffer2[y*width+x] = 0; Gbuffer2[y*width+x] = 0; Bbuffer2[y*width+x] = 0; } } } /*******************ここまで******************************/ /*書き込み処理*/

Plane2RGB(buffer, Rbuffer2, Gbuffer2, Bbuffer2, width, height); /*bufferは入力のものを転用する*/

SaveBitmap("result.bmp", buffer, width, height); 省略 } p10-5.c 19

2値化プログラムの例2

int main(void) { 省略 double tmp_pix; double threshold=100; /*閾値*/ /*出力用*/

Rbuffer2 = (BYTE*)malloc( width*height ); /*メモリ確保*/

Gbuffer2 = (BYTE*)malloc( width*height ); Bbuffer2 = (BYTE*)malloc( width*height );

/*****************画像処理をここで行う********************/

for(y=0; y<height; y++){ for(x=0; x<width; x++){

tmp_pix = ((Rbuffer[y*width+x]+Gbuffer[y*width+x]+Bbuffer[y*width+x])/3.0);

Rbuffer2[y*width+x] =(tmp_pix > threshold) ? 255:0; Gbuffer2[y*width+x] =(tmp_pix > threshold) ? 255:0; Bbuffer2[y*width+x] =(tmp_pix > threshold) ? 255:0;

} }

/*******************ここまで******************************/ /*書き込み処理*/

Plane2RGB(buffer, Rbuffer2, Gbuffer2, Bbuffer2, width, height);/*bufferは入力のものを転用する*/

SaveBitmap("result.bmp", buffer, width, height); 省略 p10-6.c 20

条件演算子

条件式 ? 式1:式2 条件式が真 ⇒ 式1 条件式が偽 ⇒ 式2

Rbuffer2[i] = (Rbuffer[i] > threshold) ? 255 : 0 ;

(Rbuffer[i] > threshold) が 真の時は255を出力 条件式

(Rbuffer[i] > threshold) が 偽の時は0を出力 ifを使って書き直すことができる

(6)

21

画像認識

† 画像認識とは „ 画像のパターンを判別すること † 予め用意したパターンの辞書と比較 † 入力と最も近いパターンを判別結果とする „ 「近さの基準をどうするか?」が大変重要 システム 物体辞書 物体画像 入力 認識物体 出力 22

例えば文字認識

画像入力 (スキャナorカメラ) 文字パターンの辞書 認識したい文字 全ての形に関する情報 どの文字パターン に最も近いかを判定 レイアウト解析 全ての文字を判別したか? 2値化 一つの文字を取り出す yes no 電 気 通 信 大 学 23

パターンを認識する

† レイアウト解析後に切り出した文字パターンが何か?を判別するには どうすればよいか † 全ての文字に対して基準となるパターンを用意 † 基準パターンと入力パターンの近さを計る † 基準パターンとはどのようなものか? † 基準パターンと入力パターンの近さはどのように定義するか? „ 差の絶対値の和(SAD) „ 正規化相互相関(NCC)

− − − − = n i i n i i i n i i b b a a b b a a b a NCC 2 2 ) ( ) ( ) )( ( ) , ( | | ) , ( i n i i b a b a SAD =

− 平均 24

テンプレートマッチング

† テンプレート(パターン)マッチング † 基準パターンは画像そのもの(テンプレート) „ 基準パターン(テンプレート)に最も近い物を探す „ 一般にテンプレート画像と入力画像は同じ大きさではない „ マッチする場所を探す必要がある „ 大きさの違いや傾きなども考慮する必要がある

(7)

25

数字を認識してみよう

† 64×64ピクセルの画像に数字を書いて入力する † どれと最も近いのかをどのように計算するかが問題 それぞれと比較する 入力 テンプレート(辞書) 26

数字を認識してみよう(続き)

† 2値化した入力画像とテンプレートの画素の一致度(いく つ一致するか)を数える 2値化 テンプレートと比較 黒画素の数が一致した数 黒が多い方が近い?

本当にこれでできるのか?

0 で一致した画素数 2976画素 1 で一致した画素数 2932画素 2 で一致した画素数 2873画素 3 で一致した画素数 2925画素 4 で一致した画素数 3014画素 5 で一致した画素数 2800画素 6 で一致した画素数 2979画素 7 で一致した画素数 2921画素 8 で一致した画素数 2911画素 9 で一致した画素数 2961画素

処理の流れ

† プログラムの流れをつかもう † 興味のある人は是非作ってみましょう 入力画像の読み込み 入力画像の2値化 Rbuffer2へ i番目の数字テンプレート読み込み i番目の数字テンプレートとRbuffer2の比較 一致度をscore[i]へ保存 i<10 ? score[i]の最大値 とそのときのiを求める (max_indexに保存) 結果の表示 i++ No Yes

(8)

29

数字を認識してみよう(続き)

† もっとうまい方法はないか? † まずは単純なマッチングの欠点を考えてみる „ 形のちょっとした変化に弱い „ 位置ずれに弱い † もっと大雑把な数字の特徴をつかんだ方が良い † うまく判別できる特徴を考えてみよう „ 文字認識ではエッジの方向性がよく使われる 特徴量 特徴量 30

最終課題

透明人間になってみたい! ⇒せめて画像処理で楽しみましょう 2枚の画像を使う 自分で用意しても良い(三脚などでカメラを固定する) 自分で作ったプログラムで処理すると透明人間(もどき)に! 31

動画にすればこんな感じ・・・

静止画をつなげたものが動画(ぱらぱら漫画と同じ仕組み) 32

ポイント

† 画像はback.bmpとfront.bmpの2枚をこちらで用意(自分で用意してもいい です) † 画素値はunsigned char型(BYTEで定義しなおしている)なのでオーバーフ ローを気にする必要がある † 演算はdouble型で行って(必要があれば)結果をキャストする † p10-7.cにヒントプログラムがある(やり方はひとつではないので、独自に作っ てももちろんかまいません) † 好きな透明度の画像を最低1枚作ればよい(興味があれば、ビットマップをつ なげてAVIファイルにするフリーソフトがあるので試してみてください)

http://yamatabi.que.ne.jp/soft/avimk/ (AVI Maker)

† ソースコードと画像(できればJPEGに圧縮)をメールで送る

参照

関連したドキュメント

非自明な和として分解できない結び目を 素な結び目 と いう... 定理 (

スライド5頁では

注:一般品についての機種型名は、その部品が最初に使用された機種型名を示します。

町の中心にある「田中 さん家」は、自分の家 のように、料理をした り、畑を作ったり、時 にはのんびり寝てみた

参加者は自分が HLAB で感じたことをアラムナイに ぶつけたり、アラムナイは自分の体験を参加者に語っ たりと、両者にとって自分の

(3)使用済自動車又は解体自 動車の解体の方法(指定回収 物品及び鉛蓄電池等の回収 の方法を含む).

自分ではおかしいと思って も、「自分の体は汚れてい るのではないか」「ひどい ことを周りの人にしたので

最後に,本稿の構成であるが,本稿では具体的な懲戒処分が表現の自由を