Home › Category Archives › ファイルアクセス
Sponsored Link

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

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

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

https://octave.dogrow.net/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配列の次元を premuteで入れ替え、imshowで表示してみる。

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

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

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

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

https://octave.dogrow.net/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://octave.dogrow.net/wp-content/uploads/2013/10/20131005_03.png

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

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

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

(26) imread, imwriteで画像ファイル読み書き

imreadで任意の形式の画像ファイルを配列データとして読み込める。
※imreadに失敗する場合は「(25) imreadを使えるようにする」を参照のこと

octave:1> ls
gfish.png
octave:2> img=imread('gfish.png');
octave:3> size(img)
ans =
   238   307     3
octave:4>

imfinfoで画像ファイルの情報を表示することができる。
この画像は、縦238ピクセル、横307ピクセル、RGB 3バンドのPNG画像ファイルだ。

octave:5> imfinfo('gfish.png')
ans =
  scalar structure containing the fields:
    Filename = /home/temp/work/gfish.png
    FileModDate = 19-Sep-2013 00:03:27
    FileSize =  125173
    Height =  238
    Width =  307
    BitDepth =  8
    Format = PNG
    LongFormat = Portable Network Graphics
    XResolution =  37.790
    YResolution =  37.790
    TotalColors =  40382
    TileName = 
    AnimationDelay = 0
    AnimationIterations = 0
    ByteOrder = undefined
    Gamma =  0.45455
    Matte = 0
    ModulusDepth =  8
    Quality =  75
    QuantizeColors =  256
    ResolutionUnits = undefined
    ColorType = truecolor
    View = 
octave:6>

imshowで変数に読み込んだ画像データを表示することができる。

octave:6> imshow(img)
octave:7>

http://octave.dogrow.net/wp-content/uploads/2013/09/20130920_01.png

変数に読み込んだ画像データは、配列データとして扱うことができる。
例えば、各ピクセルのRGBバンドの平均値(画像データ配列の3次元目の平均値)を算出し、グレースケール画像を作成してみる。

octave:7> gimg = uint8(mean(img,3));
octave:8> imshow(gimg)
octave:9>

グレースケール画像ができた。
http://octave.dogrow.net/wp-content/uploads/2013/09/20130920_02.png

作成したグレースケール画像を imwriteでPNGファイル出力してみる。

octave:9> imwrite(gimg,'gray.png','png')
octave:10> ls
gfish.png  gray.png
octave:11>

(24) csvwriteでCSVファイル出力

任意の配列を csvwrite でCSVファイルとして出力できる。

octave:1> a=rand(5)
a =
   0.542996   0.489232   0.047035   0.599449   0.292406
   0.645112   0.505513   0.170523   0.144984   0.458485
   0.321232   0.073533   0.298546   0.088937   0.861154
   0.930462   0.157901   0.486024   0.130868   0.111856
   0.714509   0.815946   0.053521   0.206195   0.887324
octave:2>
octave:2> csvwrite('temp.csv', a)

出力したファイルは、「,」区切りのCSVファイルとなっている。

[user@dog-server]$ cat temp.csv
0.5429963046629652,0.4892324282133353,0.04703543400988712,0.5994492495798024,0.2924063414552014
0.6451117490214259,0.5055131090427051,0.1705233495889967,0.1449835559314347,0.4584854134958692
0.3212318726559802,0.07353300388710242,0.2985459491039432,0.08893719071145494,0.8611542924326369
0.9304620335200237,0.1579012055122481,0.4860241431674273,0.1308681261672557,0.1118555082863725
0.7145092069852456,0.8159457131196939,0.05352063406290257,0.2061950295261054,0.887324445259423
[user@dog-server]$

出力したCSVファイルは、Excelで入力していろいろと加工できる。

(19) csvread()でCSVファイルのデータをロード

こんなCSVファイルを用意した。

[user@dog-server]$ cat test.csv
10,1
20,6
30,18
40,11
50,14
[user@dog-server$

このCSVファイルを csvread でロードする。

octave:5> M=csvread('test.csv')
M =
   10    1
   20    6
   30   18
   40   11
   50   14

octave:6>

ロードしたデータを折れ線グラフで表示してみる。

octave:7> plot(M(:,1),M(:,2))

http://octave.dogrow.net/wp-content/uploads/2013/08/20130828_001.jpg

折れ線グラフではなく、赤色「r」のマーカー「+」でプロットしてみる。

octave:8> plot(M(:,1),M(:,2),'r+')

http://octave.dogrow.net/wp-content/uploads/2013/08/20130828_002.jpg

今度は棒グラフで表示してみる。

octave:9> bar(M(:,1),M(:,2))

http://octave.dogrow.net/wp-content/uploads/2013/08/20130828_003.jpg