Home › Monthly Archives › 10月 2013

(28) freadでBMP画像を読み込み表示

octaveで fopen, freadを使ってバイナリファイルをロードしてみる。

「正しく読めたか?」の確認には、画像データを表示させてみるとわかりやすい。
以下のようなBMPファイル bird.bmp を用意し、これをoctaveで読み込んで表示してみる。

https://www.dogrow.net/octave/wp-content/uploads/2013/10/bird.bmp
(ちなみにこの写真は上野動物園で撮影したハシビロコウです ^^)

octave:1> ls
bird.bmp

まずはバイナリファイルを fopenでオープンする。

octave:4> fid=fopen('bird.bmp','r','b')
fid =  3

BMPファイルの先頭には、BITMAPFILE HEADER BITMAPINFO HEADER が格納されている。
画像データの縦横サイズなどの情報が格納されている。

まずは BITMAPFILE HEADERを読み込んでみる。

octave:5> BfType=fread(fid,1,'uint16');
octave:6> BfSize=fread(fid,1,'uint32');
octave:7> BfReserved1=fread(fid,1,'uint16');
octave:8> BfReserved2=fread(fid,1,'uint16');
octave:9> BfOffBits=fread(fid,1,'uint32');

次に BITMAPINFO HEADERを読み込んでみる。

octave:10> BiSize=fread(fid,1,'uint32');
octave:11> BiWidth=fread(fid,1,'uint32');
octave:12> BiHeight=fread(fid,1,'uint32');
octave:13> BiPlanes=fread(fid,1,'uint16');
octave:14> BiBitCount=fread(fid,1,'uint16');
octave:15> BiCompression=fread(fid,1,'uint32');
octave:16> BiSizeImage=fread(fid,1,'uint32');
octave:17> BiXPelsPerMeter=fread(fid,1,'uint32');
octave:18> BiYPelsPerMeter=fread(fid,1,'uint32');
octave:19> BiClrUsed=fread(fid,1,'uint32');
octave:20> BiClrImportant=fread(fid,1,'uint32');

BITMAPINFO HEADERから読み込んだ BMP画像の縦横サイズを表示してみる。
横幅は BiWidth, 高さは BiHeightに取得してある。

octave:21> BiWidth
BiWidth =  3.5568e+09
octave:22> BiHeight
BiHeight =  2.6172e+09

何かおかしい…
縦横サイズがめちゃくちゃ大きくなっている。

読み込んだデータを16進数で表示してみるとLittle endianで表示されている。

octave:29> printf('%x , %x\n', BiWidth, BiHeight);
d4000000 , 9c000000

swapbytesで Big endianに変換した後に10進数で表示してみると、正しく縦横サイズが表示された。

octave:30> swapbytes(uint32(BiWidth))
ans = 212
octave:31> swapbytes(uint32(BiHeight))
ans = 156
octave:32>

BITMAPFILE HEADER, BITMAPINFO HEADERに続いて格納されているのがいよいよ画像データだ。
」の3バイトで1画素の値が作られており、これが横×縦サイズ分だけ格納されている。
このため、octave的には [ 3 212 156 ] の3次元配列で取得すればよい。

octave:32> img=fread(fid,[3 212* 156],'uint8');
octave:33> size(img)
ans =
       3   33072
octave:34> img=reshape(img,3,212,156);
octave:35> size(img)
ans =
     3   212   156

imshowで画像を表示する場合、入力する画像データ配列を[y][x][color]の順に作る必要がある。
そこで上記のimg配列の次元を permuteで入れ替え、imshowで表示してみる。

octave:38> img=permute(img,[3 2 1]);
octave:39> imshow(uint8(img));

https://www.dogrow.net/octave/wp-content/uploads/2013/10/20131005_01.png

上下が反対だ…
flipdimで行方向に反転する。

octave:40> img=flipdim(img,1);
octave:41> imshow(uint8(img));

https://www.dogrow.net/octave/wp-content/uploads/2013/10/20131005_02.png

色合いがおかしい…
imshowで指定する画像データの3次元目は、RGB()の順にデータを格納する必要がある。
BMPファイルにはBGR()の順にデータが格納されているため、がひっくり返って表示されている。
こちらも flipdimで画像データ配列の3次元目を反転させてのデータを入れ替える。

octave:42> img=flipdim(img,3);
octave:43> imshow(uint8(img));

https://www.dogrow.net/octave/wp-content/uploads/2013/10/20131005_03.png

正しく表示できた!
freadを使ってバイナリファイルの中身を読み込む方法がわかった!

最後は fcloseでファイルをクローズして終わりです。

octave:44> fclose(fid)
ans = 0
octave:45>