信号処理論
ディジタル画像処理
C 言語におけるファイル入出力 テキスト バイナリの取り扱い
( )..[4]% gcc Wall o hoge hoge.c..[5]%./hoge 1 : 1 2 : 2 3 : 3 4 : 0 6..[6]%
(! )..[4]% gcc Wall o hoge hoge.c..[5]%!g gcc Wall o hoge hoge.c..[6]%!! gcc Wall o hoge hoge.c..[7]%!../hoge 1 :!g g!!!..!ls!gcc
cp : cp. cp hoge.c hoge2.c hoge.c hoge2.c cp hoge.c jikken1/hoge3.c hoge.c jikken1 hoge3.c mv : ( ) mv. mv hoge.c jikken1/hoge2.c hoge.c jikken1 hoge2.c hoge.c cat : cat cat more. cat hoge.c more hoge.c Return (Enter) 1 q
( ) ( ) C
C ( ) Q1 A1 fopen Q2 A2 Q3 A3 Q4 A4 fclose
#include <stdio.h> #include <stdlib.h> int main(void) { int i, dat, sum = 0; FILE *fp /* exit */ if ( ( fp = fopen( indata.dat, r ) ) == NULL ) { } /* */ printf( n ); exit(1); for (i = 1 ; ; i++){ fscanf(fp, %d, &dat); /* */ if(dat == 0) /* 0 */ break; sum += dat; /* */ } printf( %d n, sum); /* */ } fclose(fp); return(0); /* */
FILE *fp if ( ( fp = fopen( indata.dat, r ) ) == NULL ); /* */ { printf( n ); exit(1); } FILE *fp; C FILE FILE FILE stdio.h stdio.h
FILE *fp; a b /* fp */ FILE *fp; c d e
FILE *fp if ( ( fp = fopen( indata.dat, r ) ) == NULL ); /* */ { printf( n ); exit(1); } fp = fopen(, )
r w a rb wb ab b UNIX Windows C html C
fp = fopen(, ); a /* b */ fp = fopen( b, r ) ; b b c b d e
fp a b c d e f g h i j k l m n o p q r s t u v w x y z k o n o m o j i r e t s u n o n a r a b i n i h a i m i h a a r i m a s e n 2 1
fclose(fp); /* */ fclose (fp);
fclose( fp ) ; /* b a fp */ fclose(fp) ; c b d e b
b d FILE *fp1; FILE *fp2; fp1 = fopen( b, r ); fp2 = fopen( d, w ); fclose( fp2 ); fclose( fp1 ); fp1 b a d fp2 d c b e
FILE *fp if ( ( fp = fopen(, ) ) == NULL ); /* */ { printf( n ); exit(1); } fclose (fp) /* */
fgetc / fputc fgets / fputs fscanf / fprintf fread / fwrite
fgetc / fputc getchar putchar c = fgetc(fp); 8 ( End of File ) c int fputc(c, fp)
C 1 a a b c d e f g h i j k l m n o p q r s b 2 c 3 4 EOF unsigned char int fgetc
mule rsample.txt cat #include <stdio.h> #include <stdlib.h> int main(void) { FILE *fpr; FILE *fpw; int c; /* */ if ( ( fpr = fopen( rsample.txt, r ) ) == NULL ) { return(0); printf( n } ); } exit(1); /* */ if ( ( fpw = fopen( wsample.txt, w ) ) == NULL ) { printf( n ); exit(1); } /* */ while (( c = fgetc(fpr) )!= EOF) { fputc( c, fpw ); } /* */ fclose(fpw); /* */ fclose(fpr);
バイナリ形式 バイナリー (Binary) とは 0 と 1 の 2 種類の数字で表現する 2 進数の意味 2 進数で表されたデータ ( バイナリー データ ) や実行形式のプログラム ( バイナリー コード ) をバイナリー形式と言う 計算機で扱うデータは テキスト形式でなければバイナリー形式である
バイナリ形式の長所 短所 長所 : - 保存するデータに制約がない - 多彩な表現の情報を保存 交換することが可能 ( 任意のヘッダ情報を付加することができる ) 短所 : - ファイルフォーマットが分からないと内容を読むことができない - 互換性に劣る ( テキスト形式に比較して )
バイナリデータとは ( 8 bit の例 ) 10 進数 16 進数 73 60 4 9 3 C 0x49 = 4 16 1 +9 16 0 =73 2 進数 下位のデータ上位のデータ 0 1 0 0 1 0 0 1 0 0 1 1 1 1 0 0 最上位のデータ 最下位のデータ 01001001 = 0 2 7 +1 2 6 +0 2 5 +0 2 4 +1 2 3 +0 2 2 +0 2 1 +1 2 0 =73 = 0x ( 0 2 3 +1 2 2 +0 2 1 +0 2 0 ), 0x ( 1 2 3 +0 2 2 +0 2 1 +1 2 0 ) =0x 49
fgets / fputs gets puts fgets( buf,,fp); NULL buf char fputs(buf, fp)
buf 1 a b c d e n 0 f g h i j k l m n n 0 a b c d e f g h i j k l m n o p q r s t null null 2 3 o p q r s t 0 null
#include <stdio.h> #include <stdlib.h> #define MAX_STRINGS 50 int main(void) { FILE *fpr; FILE *fpw; int c; char data[max_strings]; return(0); /* */ } if ( ( fpr = fopen( rsample.txt, r ) ) == NULL ) { printf( n ); exit(1); } /* */ if ( ( fpw = fopen( wsample.txt, w ) ) == NULL ) { printf( n ); exit(1); } /* */ while ( fgets( data, MAX_STRINGS, fpr )!= NULL) { fputs( data, fpw ); } /* */ fclose(fpw); /* */ fclose(fpr);
fscanf / fprintf scanf printf fscanf (fp,, ); fprintf (fp,, ); scanf / printf
fread/ fwrite 関数 fread( buf, サイズ, カウント, fp); 引数に指定したファイルポインタの初期位置からサイズ ( byte 単位 ) 毎にカウント ( 最大値 ) までデータを読み込む 実際に読み込まれたデータの数を返す例. size = fread( buf, sizeof(long), 100, fp); int や long など, 計算機環境によってサイズ ( byte 数 ) が異なることがあるため,sizeof 演算子でデータ型の大きさ ( バイト単位 ) を計算するのがよい fwrite( buf, サイズ, カウント, fp); 引数に指定したファイルポインタの初期位置からサイズ毎にカウントまでデータを書き込む
本日の課題
課題 : BMP ファイルの入出力 24 bit ( 1677 万色 ) の Windows Bitmap 形式で保存された画像ファイル bmpsample.bmp を読み込み, Red,Blue,Green のいづれかの色情報のみを残して他の色情報を排除した画像を作成しなさい bmpsample.bmp の画像サイズ ( 縦 横の大きさ ) はヘッダ情報を読み込むことで認識しなさい 作成するファイルは縦 横の画素数および色数 が元画像と同じままの Windows Bitmap 形式とする
元の画像 Red だけ Blue+Green Green だけ 2 倍
Bitmap 形式について
BMP ファイル全体の構造 BMP フォーマットはヘッダの種類によって Windows Bitmap と OS/2 Bitmap の 2 種類に分けられる これらの 2 つのフォーマットは, ヘッダのサイズが異なっている BMP ファイル全体の構造 ファイルヘッダ 情報ヘッダ BITMAPFILEHEADER (14byte) BITMAPINFOHEADER (Windows) または BITMAPCOREHEADER (OS/2) + カラーパレット (1, 4, 8 bit の場合必要 ) 画像データ カラーパレーットがない場合 各画素に割り振られた値はそのまま色 ( または明るさ ) を示す カラーパレットがある場合は 各画素の値はパレットを参照するための値であり 色 ( または明るさ ) はパレットで定義されたものとなる
ファイルヘッダ [BITMAPFILEHEADER] 最初に 14 byte 固定のファイルヘッダ部分がある 最初の 2 byte が BM かどうかで ビットマップファイルが識別される bftype bfsize bfreserved1 bfreserved2 bfoffbits 2 byte 4 byte 2 byte 2 byte 4 byte BITMAPFILEHEADER ファイルタイプ ファイルサイズ (byte) 'BM' - OS/2, Windows Bitmap 予約領域常に 0 予約領域常に 0 ファイル先頭から画像データまでのオフセット (byte)
情報ヘッダ < Windows > [BITMAPINFOHEADER] BITMAPINFOHEADER (1) bisize 4 byte 情報ヘッダのサイズ (byte) 40 byte biwidth 4 byte 画像の幅 ( ピクセル ) biheight 4 byte 画像の高さ ( ピクセル ) biheight の値が正数なら, 画像データは下から上へ biheight の値が負数なら, 画像データは上から下へ biplanes 2 byte プレーン数常に 1 bibitcount 2 byte 1 画素あたりのデータサイズ (bit) bicopmression 4 byte 圧縮形式 1-2 色ビットマップ 4-16 色ビットマップ 8-256 色ビットマップ 16-65536 色 (high color) ビットマップ 24-1677 万色 (true color) ビットマップ 32-1677 万色 (true color) ビットマップ 0 - BI_RGB ( 無圧縮 ) 1 - BI_RLE8 (RunLength 8 bits/pixel) 2 - BI_RLE4 (RunLength 4 bits/pixel) 3 Bitfields
情報ヘッダ < Windows > [BITMAPINFOHEADER] BITMAPINFOHEADER (2) bisizeimage 4 byte 画像データ部のサイズ (byte) 96dpi ならば 3780 0 の場合もある bixpixpermeter biypixpermeter biclrused 4 byte 4 byte 4 byte 横方向解像度 (1m あたりの画素数 ) 縦方向解像度 (1m あたりの画素数 ) 格納されているパレット数 ( 使用色数 ) 96dpi ならば 3780 0 の場合もある 96dpi ならば 3780 0 の場合もある 0 の場合もある bicirimportant 4 byte 重要なパレットのインデックス 0 の場合もある
情報ヘッダ < OS/2 > [BITMAPCOREHEADER ] BITMAPCOREHEADER bisize 4 byte 情報ヘッダのサイズ (byte) 12 byte bcwidth 2 byte 画像の幅 ( ピクセル ) bcheight 2 byte 画像の高さ ( ピクセル ) bcheight の値が正数なら, 画像データは下から上へ bcheight の値が負数なら, 画像データは上から下へ bcplanes 2 byte プレーン数常に 1 bcbitcount 2 byte 1 画素あたりのデータサイズ (bit) 1-2 色ビットマップ 4-16 色ビットマップ 8-256 色ビットマップ 16-65536 色 (high color) 24-1677 万色 (true color) ビットマップ 32-1677 万色 (true color) ビットマップ
Windows BMP 24bit の構成 0x42 が B をあらわす 0x4D は? は 1 byte を示しているおり,16 進数で表記している 実際は 実際には 8 個のメモリに 2 進数で保存されている 42 4D BITMAPFILEHEADER ( 14 byte ) BITMAPINFOHEADER ( 40 byte ) Data ( 任意のサイズ )
Windows BMP 24bit のデータ構造 は 1 画素をあらわしている (31,0) (31,31) 32 画素 32 画素のWindows BMP 画像データは基本的に左下から右上へ向かって並んでいるので モニタに表示されるものとは並び順が異なる ( BITMAPINFOHEADER の biheight で決まる ) 各画素は Blue (8bit), Green (8bit), Red (8bit) の 3 byteで表現される (0,0) (0,31) たとえば この画素 (5,30) が白で (5,31) が黒だとすると (5,30) (5,31) 実際の計算機に保存されているのは (2 進数 ) (16 進数 ) FF FF FF 00 00 00 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
ヘッダを読み込む際の注意事項 例.BITMAPINFOHEADER の bisize : 情報ヘッダのサイズ Windows BMP の場合 bisize の値は常に 40 byte bisize は 4 byte で保存されている 10 進数の 40 を 4 byte の 16 進数で表現すると 0x00000028 ( 2 16 + 8 = 40) 計算機の中では右図のように格納されている ( Intel 系の計算機など ) 28 00 00 00 下位データ 上位データ 下のように temp_long に 4 byte を読み込んでみると long temp_long; fread ( &temp_long, 4, 1, fpr ); /* 情報ヘッダサイズ */ long infohead_size = temp_long; 40.0
ヘッダを読み込む際の注意事項 long temp_long; fread ( &temp_long, 4, 1, fpr ); temp_long の中身は 0x00000028 1 前のデータ 28 00 00 00 下位データ 上位データ 次のデータ であれば問題ないのだが 右図のように認識する計算機もある ( 系の計算機 ) など 前のデータ 28 00 00 00 次のデータ この場合の tmp_long の中身は 0x28000000 2 上位データ 下位データ こんなに違う 1: 0x00000028 = 40 ) 10 2: 0x28000000 =671088640 ) 10
エンディアン たとえば 0x0123ABFF を格納する場合に 2 つの方式がある 前のデータ 処理 ( 書込 ) の順番 FF AB 23 01 下位データ 上位データ 次のデータ 0x0123ABFF リトルエンディアン < 今回使う BMP ファイルはこちらに準拠 > 前のデータ 処理 ( 書込 ) の順番 01 23 AB FF 上位データ 次のデータ 上位データ 下位データ 0x0123ABFF ビッグエンディアン < 計算機室のシステムはこちらに準拠 >
リトルエンディアンのつもりで作られたヘッダ情報が 前の 次の データ 28 00 00 00 データデータ 28 00 00 00 前の 次のデータ 下位データ こうすると long temp_long; 上位データ 上位データ 下位データ ビックエンディアンで認識されている! fread ( &temp_long, 4, 1, fpr ); 0x28000000 になってしまうので 上下の byte で中身を入れ替えないと 正しい値を得られない
おまけ fseek 関数 fseek ( fp, offset, int origin ); 引数に指定したファイルポインタの初期位置 origin を基準として,offset だけ移動する offset の単位は byte int origin : SEEK_SET ( ファイルの先頭 ) SEEK_CUR ( ファイルの現在位置 ) SEEK_END ( ファイルの終端 )
発展課題 : 拡張版 BMP 入出力 課題で作成したプログラムを任意に拡張する 例 ) 画像を反転 回転 任意の色を強調 任意の位置を切り出し 24 bit に限らず,8 bit, 32 bit などにも対応 ( カラーパレットについて調べる必要あり ) OS/2 Bitmap にも対応 画像フィルタの適用 など