(Application) BMPをNetCDFに変換
作成者:山本 博基
概要
BMP画像データをNetCDFデータに変換します。
8/24/32 bit, Windows, OS/2フォーマットに対応し、これらは自動で判別されます。
生成されるNetCDFファイルの、軸の名前 [単位名] は x [pixels], y [pixels]、 変数名は8 bit の場合は I [none] (long name は Intensity) 、 24/32 bit の場合は R [none], G [none], B [none], 及び I [none] (R + G + B)になります。
型は全て Int になります。
使い方
BMPフォーマットのファイル hoge.bmp を与えて実行すると、 hoge.nc が生成されます。
$ ./bmp2nc.rb hoge.bmp
ソースコード
bmp2nc.rb
#!/usr/bin/env ruby
#
# 機能:
# 8/24/32 bit のBMPフォーマットの画像データを読み込んで、NetCDF ファイルを生成する。
# Windows, OS/2 のフォーマットに対応。
# 8/24/32 bit の判別, Windows, OS/2の判別は自動で行われる。
#
# 使用法:
# ruby bmp2nc.rb hoge.bmp
# と実行すると hoge.nc が生成される。
# 軸の名前[単位名]は x [pixels], y [pixels]
# 変数名は8 bit の場合は I [none] (long name は Intensity)
# 24/32 bit の場合は R [none], G[none], B[none], 及び I [none] (R + G + B)である。
#
# 参考URL: http://www.kk.iij4u.or.jp/~kondo/bmp/
require "numru/gphys"
include NumRu
# 入力ファイルを開く
infp = File.open(ARGV[0],"r")
#情報ヘッダ取得
filehead = infp.read(14).unpack("SLSSL")
#データオフセット値
offset = filehead[4]
#Windows, OS/2 のフォーマット判別
flaghead = infp.read(4).unpack("L")
#OS/2 のフォーマットの場合
if flaghead[0] == 12 then
infohead = infp.read(36).unpack("ssSS")
width = infohead[0].abs
height = infohead[1].abs
#Windowsフォーマットの場合
elsif flaghead[0] == 40 then
infohead = infp.read(36).unpack("llSSLLllLL")
width = infohead[0].abs
height = infohead[1].abs
else
p "This file may not be .bmp format"
exit
end
# make x axis
xdata = NArray[0..width-1]
xary = VArray.new(xdata, {"long_name"=>"x", "units"=>"pixels"}, "x")
xaxis = Axis.new
xaxis.pos = xary
# make y axis
ydata = NArray[0..height-1]
yary = VArray.new(ydata, {"long_name"=>"y", "units"=>"pixels"}, "y")
yaxis = Axis.new
yaxis.pos = yary
#8bit bmpの場合
if infohead[3] == 8 then
array = Array.new
infp.pos = offset
height.times{
warray = infp.read(width).unpack("C*")
array << warray
}
na = NArray.to_na(array)
va = VArray.new(na, {"long_name"=>"Intensity", "units"=>"none"},"I")
grid = Grid.new(xaxis, yaxis)
gphys = GPhys.new(grid, va)
p gphys
#書き出し
outfile = NetCDF.create(ARGV[0].sub(".bmp", ".nc"))
GPhys::NetCDF_IO.write( outfile, gphys)
outfile.close
#24bit bmpの場合
elsif infohead[3] ==24 then
arrayR = Array.new
arrayG = Array.new
arrayB = Array.new
infp.pos = offset
height.times{
warrayR = Array.new
warrayG = Array.new
warrayB = Array.new
width.times{
carray = infp.read(3).unpack("C*")
warrayB << carray[0]
warrayG << carray[1]
warrayR << carray[2]
}
arrayR << warrayR
arrayG << warrayG
arrayB << warrayB
}
naR = NArray.to_na(arrayR)
naG = NArray.to_na(arrayG)
naB = NArray.to_na(arrayB)
grid = Grid.new(xaxis, yaxis)
vaR = VArray.new(naR, {"long_name"=>"R", "units"=>"none"},"R")
gphysR = GPhys.new(grid, vaR)
vaG = VArray.new(naG, {"long_name"=>"G", "units"=>"none"},"G")
gphysG = GPhys.new(grid, vaG)
vaB = VArray.new(naB, {"long_name"=>"B", "units"=>"none"},"B")
gphysB = GPhys.new(grid, vaB)
va = VArray.new(naR + naG + naB, {"long_name"=>"R+G+B", "units"=>"none"},"I")
gphys = GPhys.new(grid, va)
p gphys
#書き出し
outfile = NetCDF.create(ARGV[0].sub(".bmp", ".nc"))
GPhys::NetCDF_IO.write( outfile, gphysR)
GPhys::NetCDF_IO.write( outfile, gphysG)
GPhys::NetCDF_IO.write( outfile, gphysB)
GPhys::NetCDF_IO.write( outfile, gphys)
outfile.close
#32bit bmpの場合
elsif infohead[3] ==32 then
arrayR = Array.new
arrayG = Array.new
arrayB = Array.new
infp.pos = offset
height.times{
warrayR = Array.new
warrayG = Array.new
warrayB = Array.new
width.times{
carray = infp.read(4).unpack("C*")
warrayB << carray[0]
warrayG << carray[1]
warrayR << carray[2]
}
arrayR << warrayR
arrayG << warrayG
arrayB << warrayB
}
naR = NArray.to_na(arrayR)
naG = NArray.to_na(arrayG)
naB = NArray.to_na(arrayB)
grid = Grid.new(xaxis, yaxis)
vaR = VArray.new(naR, {"long_name"=>"R", "units"=>"none"},"R")
gphysR = GPhys.new(grid, vaR)
vaG = VArray.new(naG, {"long_name"=>"G", "units"=>"none"},"G")
gphysG = GPhys.new(grid, vaG)
vaB = VArray.new(naB, {"long_name"=>"B", "units"=>"none"},"B")
gphysB = GPhys.new(grid, vaB)
va = VArray.new(naR + naG + naB, {"long_name"=>"R+G+B", "units"=>"none"},"I")
gphys = GPhys.new(grid, va)
p gphys
#書き出し
outfile = NetCDF.create(ARGV[0].sub(".bmp", ".nc"))
GPhys::NetCDF_IO.write( outfile, gphysR)
GPhys::NetCDF_IO.write( outfile, gphysG)
GPhys::NetCDF_IO.write( outfile, gphysB)
GPhys::NetCDF_IO.write( outfile, gphys)
outfile.close
end
infp.close
補足
- BMPからデータを取り出す際に一度 Array オブジェクトで取り出してから、NArrayオブジェクトに変換しているので、無駄が多い & 遅くなっているかと思います。


キーワード:[BMP] [NetCDF]
参照: