Microsoft PowerPoint - handout09.ppt

Similar documents
02: 変数と標準入出力

画像ファイルを扱う これまでに学んだ条件分岐, 繰り返し, 配列, ファイル入出力を使って, 画像を扱うプログラムにチャレンジしてみよう

C言語講座 ~ファイル入出力編~

情報処理演習 B8クラス

Microsoft PowerPoint - prog06.ppt

Microsoft PowerPoint - 14th.ppt [互換モード]

Microsoft Word - Cプログラミング演習(10)

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

memo

Microsoft PowerPoint - prog04.ppt

Microsoft PowerPoint - comprog11.pptx

PowerPoint Presentation

AquesTalk2 Win マニュアル

FORTRAN( と C) によるプログラミング 5 ファイル入出力 ここではファイルからデータを読みこんだり ファイルにデータを書き出したりするプログラムを作成してみます はじめに テキスト形式で書かれたデータファイルに書かれているデータを読みこんで配列に代入し 標準出力に書き出すプログラムを作り

Taro-ファイル処理(公開版).jtd

AquesTalk プログラミングガイド

AquesTalk Win Manual

PowerPoint Presentation

Microsoft PowerPoint ppt

Microsoft PowerPoint - kougi2.ppt

ファイル入出力

PowerPoint プレゼンテーション

02: 変数と標準入出力

AquesTalk2 Win マニュアル&ライセンス規定

PowerPoint プレゼンテーション

プログラミング実習I

02: 変数と標準入出力

Microsoft Word - no15.docx

PowerPoint プレゼンテーション

PowerPoint プレゼンテーション

1 C STL(1) C C C libc C C C++ STL(Standard Template Library ) libc libc C++ C STL libc STL iostream Algorithm libc STL string vector l

Ⅰ. 外枠の作成 JTrim ファイルを起動しておきます 1)100*100 の黒を新規作成して背景を白にしますそして 50 でフェードアウトします 1 ファイル 新規作成 横 縦 (100) キャンバスの色 ( 黒 ) OK 2 表示 背景色 白 3 加工 フェードアウト フェードアウト画面が表示

AquesTalk for WinCE プログラミングガイド

Microsoft PowerPoint - kougi4.ppt

格子点データの解析 1 月平均全球客観解析データの解析 客観解析データや衛星観測データのような格子点データは バイナリ形式のデータファイルに記録されていることが多いです バイナリ形式のデータファイルは テキスト形式の場合とは異なり 直接中身を見ることができません プログラムを書いてデータを読み出して

Microsoft Word - Cプログラミング演習(12)

AquesTalk Mac マニュアル

コマンドラインから受け取った文字列の大文字と小文字を変換するプログラムを作成せよ 入力は 1 バイトの表示文字とし アルファベット文字以外は変換しない 1. #include <stdio.h> 2. #include <ctype.h> /*troupper,islower,isupper,tol

第1回 プログラミング演習3 センサーアプリケーション

バイオプログラミング第 1 榊原康文 佐藤健吾 慶應義塾大学理工学部生命情報学科

PowerPoint Presentation

Taro-ポインタ変数Ⅰ(公開版).j

AquesTalk10 Win マニュアル

Transcription:

応用プログラミング第 9 回 ~ プログラミングの応用画像処理その 2~ 本日の内容 1. まずは課題 2. 画像処理の色々 3. 色々とプログラムを手直ししよう 4. 上下左右の入れ替え 回転 5. 縮小 6. 拡大 7. 拡大するのは難しい 電気通信大学電子工学専攻 Intelligent Electronic Systems Group 長井隆行 課題 bitmap.bmpをコンソールに表示してみましょう! ビットマップのフォーマットに注意 各画素がある条件を満たせば特定の文字を表示する ( 例えば (255,0,0) なら " 赤 " など ) ヒントプログラムp9-0forInt.c or p9-0formot.cをdl 可能 表示する (printfを使う) だけなので プログラム中で画像を保存する必要はない 茶 (R,G,B)=(127,127,0) 橙 (R,G,B)=(255,127,0) 課題続き 注意点 ビットマップのフォーマットに注意 左下からデータが並んでいる RGB ではなく BGR の順番 全角か半角かを気にする ( 特にスペース ) 文字はアスキーでもよい bitmap.bmp 赤 (R,G,B)=(255,0,0) サイズ :16 16 各画素 :24bit (R,G,B) ( 但し bitmapはbgrの順で並んでいる ) 各自で試してみる提出しなくてよい うまくいけばこんな感じで表示できます

画像処理とは何か? 画像をみやすくする 明るさ コントラスト 色調などの補正 回転 サイズの変更 ノイズを除去する 画像を圧縮する JPEG MPEG 画像を合成する CG 画像を認識する 文字認識 (OCR) 物体認識 ロボットビジョン ( 立体視など ) さっそく画像処理 と その前に大事な事 1. 画像の入出力はいつも同じなので関数にしておこう! 2. その際にBGRをRGBに入れ替えよう! 3. さらにピクセルが左下からのものを左上からに並べ替えよう! 4. カラー画像を処理するためには RGBそれぞれについて同じ処理をする必要がある R G Bそれぞれを別の箱にしまった方が便利! 関数化 ( ビットマップの読み込み ) unsigned char* LoadBitmap(char* filename, int* width, int* height) int i, size; FILE *fp; unsigned char *buffer; /* 入力画像用メモリのポインタ */ unsigned char tmp_pix; BITMAPFILEHEADER bmfh; BITMAPINFOHEADER bmih; fp = fopen( filename, "rb" ); /* ファイルを開く */ fread ( &bmfh, sizeof(bitmapfileheader), 1, fp ); /* ビットマップのヘッダーを読み込む */ fread ( &bmih, sizeof(bitmapinfoheader), 1, fp ); *width = bmih.biwidth; *height = bmih.biheight; size = (*width) *( *height); /* ビットマップのサイズを算出 */ buffer = (unsigned char*)malloc( 3*size ); /* 必要なサイズのメモリを確保 */ for ( i = (*height) - 1; i >= 0; i-- ) /* 上下を入れ替えながら読み込む */ fread( buffer + (*width) * 3 * i, 1, (*width) * 3, fp ); fclose( fp ); /* 読み終わったのでファイルを閉じる */ 関数化 ( ビットマップの書き込み ) void SaveBitmap(char* filename, unsigned char* buffer, int width, int height) int i; FILE *fp; BITMAPFILEHEADER bmfh; BITMAPINFOHEADER bmih; char *tmp; unsigned char tmp_pix; /* ファイルを書き込み用で開く */ fp = fopen( filename, "wb" ); /* 出力画像のヘッダを生成する */ memset(&bmfh,0, sizeof(bmfh)); memset(&bmih,0, sizeof(bmih)); tmp = (char*) &(bmfh.bftype); tmp[0]='b'; tmp[1]='m'; bmfh.bfoffbits = BMP_HEADER_SIZE; bmfh.bfsize = width*height*3 + BMP_HEADER_SIZE; p9-1.c for ( i = 0; i < size; i++ ) /*BGRをRGBへ変換( 入れ替え )*/ tmp_pix = buffer[ i * 3 ]; buffer[ i * 3 ] = buffer[ i * 3 + 2 ]; buffer[ i * 3 + 2 ] = tmp_pix; return buffer; p9-1.c 次のページに続く

関数化 ( ビットマップの書き込み ) 続き 関数化 (main 関数 ) bmih.bisize=bmp_header_size - 14; bmih.biwidth = width; bmih.biheight = height; bmih.biplanes = 1; bmih.bibitcount = 24; bmih.bicompression = 0; bmih.bisizeimage = width*height*3; /*RGB を BGR に変換する */ for ( i = 0; i < width * height; i++ ) tmp_pix = buffer[ i * 3 ]; buffer[ i * 3 ] = buffer[ i * 3 + 2 ]; buffer[ i * 3 + 2 ] = tmp_pix; fwrite( &bmfh, sizeof(bitmapfileheader), 1, fp ); /* ヘッダを書き込む */ fwrite( &bmih, sizeof(bitmapinfoheader), 1, fp ); /* ビットマップを開く関数のプロトタイプ宣言 */ unsigned char* LoadBitmap(char* filename, int* width, int* height); /* ビットマップを保存する関数 */ void SaveBitmap(char* filename, unsigned char* buffer, int width, int height); /* メイン関数 */ int width, height; int n, x, y; unsigned char *buffer; /* 入力画像用メモリのポインタ */ /* ファイルを開く */ buffer = LoadBitmap("girl.bmp", &width, &height); /* 今はとりあえず何もしない */ /******************* ここまで *********************************/ for ( i = height - 1; i >= 0; i-- ) /* 上下を入れ替えながら書き込む */ fwrite( buffer + width * 3 * i, 1, width * 3, fp ); fclose( fp ); /* ファイルを閉じる */ return; p9-1.c /* ここでは入力画像をそのまま書き出す */ /* メモリを解放する */ free( buffer ); return 0; p9-1.c RGB をそれぞれ別の箱にしまう! int width, height; int n, x, y; BYTE *buffer; /* 入力画像用メモリのポインタ */ BYTE *Rbuffer, *Gbuffer, *Bbuffer; /* ファイルを開く */ buffer = LoadBitmap("girl.bmp", &width, &height); Rbuffer = (BYTE*)malloc( width*height ); /* メモリ確保 */ Gbuffer = (BYTE*)malloc( width*height ); Bbuffer = (BYTE*)malloc( width*height ); RGB2Plane(buffer, Rbuffer, Gbuffer, Bbuffer, width, height); /*RGB を色平面に分解 */ /* 今はとりあえず何もしない */ Plane2RGB(buffer, Rbuffer, Gbuffer, Bbuffer, width, height); /* 色平面を RGB に合成 */ /* メモリを解放する */ free( buffer ); free( Rbuffer ); free( Gbuffer ); free( Bbuffer ); return 0; p9-2.c ミニテスト ( 問 1) 空欄を埋めましょう /*RGB を R,G,B に分解 */ void RGB2Plane(BYTE* buffer, BYTE* R, BYTE* G, BYTE* B, int width, int height) int i; /*RGB を各色平面へ変換 (R,G,B はアドレス渡しになっていることに注意 )*/ for (i=0; i<width*height; i++) /*R,G,B に分解したものを RGB に合成 */ void Plane2RGB(BYTE* buffer, BYTE* R, BYTE* G, BYTE* B, int width, int height) int i; /*RGB を各色平面へ変換 (R,G,B はアドレス渡しになっていることに注意 )*/ for (i=0; i<width*height; i++) buffer[3*i] = R[i]; buffer[3*i+1] = G[i]; buffer[3*i+2] = B[i];

エラー処理をする ファイルを読み込む や メモリを確保する などの処理は 仮に失敗すると後に続く処理ができなくなるという問題がある もし ファイルの読み込みに失敗したら どうするか? もし メモリが足りなくて確保できなかったら どうするか? を考えておく必要がある fp = fopen( "bitmap.bmp", "rb" ); if(fp==null) printf(" ファイルの読み込みに失敗! n"); return 0; /* 処理を継続できないので終了する */ プリントで示すプログラムには スペースの関係でエラー処理を入れていないので注意してください ヘッダファイル (.h) にしてしまう main 関数以外を mybmp.h というファイルに移動する main 関数のあるファイルの先頭に #include mybmp.h を追加 #include <stdio.h> #include <stdlib.h> #include <memory.h> #include "mybmpi.h" /* 自分で作ったヘッダーは "" で囲む */ /* メイン関数 */ 全く同じなので省略 p9-3.c ( 注 )mybmpi.h がインテル用 mybmpm.h がモトローラ用 結局どうなったかというと? #include mybmp.h とすることで 特に何もしなくても以下のようにすることが可能 buffer = LoadBitmap( xxx.bmp", &width, &height); buffer[i] 左上から RGB 順 Rbuffer Gbuffer さあ処理してみよう 画像の左右反転 Rbuffer = (BYTE*)malloc( width*height );/* メモリ確保 */ Gbuffer = (BYTE*)malloc( width*height ); Bbuffer = (BYTE*)malloc( width*height ); RGB2Plane(buffer, Rbuffer, Gbuffer, Bbuffer, width, height); /* 本当はこの間で処理をする */ /* 色平面を RGB に合成 */ Plane2RGB(buffer, Rbuffer, Gbuffer, Bbuffer, width, height); Bbuffer 入力画像 どうすればよいでしょう? 出力画像

各画素にどのようにアクセスするか 色々ありえますが ここでは2 重ループを使って次のように考えます Rbuffer[0] height x width y Rbuffer[height*width-1] 横が x 縦が y のとき Rbuffer[y*width+x]; ここまでで width がいくつあるか? for(y=0; y<height; y++) for(x=0; x<width; x++) Rbuffer2[y*width+x] = Rbuffer[y*width+x]; 0 1 2 実際のメモリ y*width+x y x 画像の左右反転 LoadBmp(); ファイルから読み込み Rbuffer[i] Rbuffer2[i] Rbuffer2[0] Rbuffer[0] 左右反転しながらコピー R,G,B それぞれ行う height height Rbuffer2[(height-1)*width] Rbuffer[1] Rbuffer[2] width 横が x 縦が y のとき Rbuffer[y*width+x]; Rbuffer2[width-1-x] 横が width-1-x 縦が y Rbuffer2[??]; width Rbuffer[x] Rbuffer[width-1] Rbuffer[2*width-1] Rbuffer[height*width-1] Rbuffer2[width-3] Rbuffer2[width-2] Rbuffer2[width-1] 指定したファイル名で保存される SaveBitmap(); 左右反転プログラム 上下の入れ替えも同じ様に 同じ行の最後まで進める :((y+1)*width-1) x 個だけ前に戻る :-x /* 出力用 */ 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+1)*width-1-x] = Rbuffer[y*width+x]; Gbuffer2[(y+1)*width-1-x] = Gbuffer[y*width+x]; Bbuffer2[(y+1)*width-1-x] = Bbuffer[y*width+x]; Plane2RGB(buffer, Rbuffer2, Gbuffer2, Bbuffer2, width, height); /*buffer は入力のものを転用する */ /* 以下省略 */ p9-4.c /* 出力用 */ 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[(height-y-1)*width+x] = Rbuffer[y*width+x]; Gbuffer2[(height-y-1)*width+x] = Gbuffer[y*width+x]; Bbuffer2[(height-y-1)*width+x] = Bbuffer[y*width+x]; Plane2RGB(buffer, Rbuffer2, Gbuffer2, Bbuffer2, width, height); /*buffer は入力のものを転用する */ /* 以下省略 */ p9-5.c

x 方向y方向x方向ミニテスト ( 問 2) カメラをたてにして撮った次の画像を90 度回転したい幅と高さの関係は? Rbuffer2[0] Rbuffer[0] Rbuffer[width-1] ミニテスト ( 問 2) 続き int width2, height2; width2=height; height2=width; for(y=0; y<height; y++) for(x=0; x<width; x++) Plane2RGB(buffer, Rbuffer2, Gbuffer2, Bbuffer2, width2, height2);/*buffer は入力のものを転用する */ SaveBitmap("result.bmp", buffer, width2, height2); 入れ替わる Rbuffer2[width2*(height2-1)] y 方向 /* 以下省略 */ 画像を縮小する 画像を縮小する ( 続き ) 画像を小さくするにはどうすればよいでしょう? 例えば 1/2 のサイズ ( 縦横それぞれ 1/2) にするには? 本当はフィルタをかける必要がある ( サンプリング定理 ) 2/3 倍などはちょっと難しいのでここでは扱わない 一つおきに画素を取り出す ( 残りは捨てる ) 本当はフィルタをかける必要がある ( サンプリング定理 ) 2/3 倍などはちょっと難しいのでここでは扱わない

画像を縮小するプログラム int ratio; ratio=2; /* 倍率 */ height2=height/ratio; width2=width/ratio; /* 出力用 */ Rbuffer2 = (BYTE*)malloc( width2*height2 ); /* メモリ確保 */ Gbuffer2 = (BYTE*)malloc( width2*height2 ); Bbuffer2 = (BYTE*)malloc( width2*height2 ); 画像を拡大する 画像を拡大するにはどうすればよい? for(y=0; y<height2; y++) for(x=0; x<width2; x++) Rbuffer2[y*width2+x] = Rbuffer[y*width*ratio+x*ratio]; Gbuffer2[y*width2+x] = Gbuffer[y*width*ratio+x*ratio]; Bbuffer2[y*width2+x] = Bbuffer[y*width*ratio+x*ratio]; p9-7.c 縮小の逆をやればいいのでは? 画像を拡大する ( 続き ) 画素を一つおきに埋めてゆく 補間の仕方 同じ画素値をコピーする ( 画素を膨らませる ) あれれ 足りない 白いところはどうしよう? 白いところの埋め方は色々な方法がある 間を埋めることを補間という 補間したきりんちゃん オリジナルのきりんちゃん

補間の仕方 ( 線形補間 ) 周りの画素の情報を使う 画像は滑らかなので 周りの画素に近い値をとる可能性が高い 周囲 4 画素の平均 補間のプログラム 同じ画素値を埋める方法のプログラム int ratio; (int) という明示的なキャストは ratio=2; なくてもOK 分かりやすいように height2=height/ratio; つけてある ( この丸めが実はポイント ) width2=width/ratio; /* 出力用 */ buffer2 = (BYTE*)malloc( width2*height2*3 );/* メモリ確保 */ Rbuffer2 = (BYTE*)malloc( width2*height2 ); Gbuffer2 = (BYTE*)malloc( width2*height2 ); Bbuffer2 = (BYTE*)malloc( width2*height2 ); 線形補間の結果 a c q b p 1-q 1-p d 画素値 =(1-p)(1-q)a+ qb +p(1-q)c+qd a,b,c,d: 小さな画像の画素値 for(y=0; y<height2; y++) for(x=0; x<width2; x++) Rbuffer2[y*width2+x] = Rbuffer[((int) (y/ratio))*width + (int) (x/ratio)]; Gbuffer2[y*width2+x] = Gbuffer[((int) (y/ratio))*width + (int) (x/ratio)]; Bbuffer2[y*width2+x] = Bbuffer[((int) (y/ratio))*width + (int) (x/ratio)]; p9-8.c