PNMという画像フォーマットが使いやすい
Intro
画像データを扱いたいがフォーマットとかが複雑そうで、勉強する気がわかなかったが、pnmという形式によって一気にはかどったのでその話を。
PNMとはなんぞや
画像フォーマットの一つ。(他の画像フォーマットは知らないが、)データをテキストでも扱えるため、計算結果を画像フォーマットに整形するために色々考える必要がない。以下のような種類がある。
- バイナリ・ビットマップ
- 情報がバイナリ形式。また表せる色も、白or黒。
- バイナリ・グレースケール
- 情報がバイナリ形式。表せる色は、白からグレー、黒。
- バイナリ・RGB
- 情報がバイナリ形式。色はRGBを使える。
- テキスト・ビットマップ
- 情報がテキスト形式。また表せる色も、白or黒。
- テキスト・グレースケール←これを使用
- 情報がテキスト形式。表せる色は、白からグレー、黒。
- テキスト・RGB
- 情報がテキスト形式。色はRGBを使える。
どう使う?
matlabとかで計算させたい画像を持ってくる。今回は、NxM画素、グレースケールの"test.png"とおく。
PNG to PNM
png2pnmというコマンドを準備する。自分はarchを使っているが、libpngというパッケージをインストールした(気がする)。
png2pnm -n test.png > test.pnm
で、pnm形式に変換してくれる。ただし書式ルールで、一行の文字数が決まってるらしく、各行M個のフィールドがあるわけではないので、整形に関して後述する。
PNM to PNG
pnm2pngというコマンドを準備する。これもlibpngに入ってたかな。
pnm2png test.pnm > test2.png
でpng形式に変換してくれる。
PNM形式 to 行列
NxM画素の画像データだから、NxM行列で扱いたいと思うのが一般だと思う。NxM行列としてoctaveやらに読み込めるように、以下の手順を踏む。
- PNM形式 to すべてのフィールドを一行にまとめた、test.tmp ( step1.awk )
- test.tmp to 各行のフィールド数がM個にした、test.mat ( step2.awk )
- octaveでは、dlmread("test.mat")をNxM行列として読み込めるため、完了。
Step1
PNM形式の、今回使う、テキスト・グレースケールのフォーマットを簡単に説明する。
- 一行目は、6種類のうち、どの形式で書かれているか。今回はテキスト・グレースケールのため、"P2"
- 二行目は、画像の大きさ。NxM画素のため、 "N M"
- 三行目は、グレースケールでの最大値。恐らくいくつでもいいと思うが、pngを変換した結果、"65535"
- 四行目以下は、画像左上からの、各画素の値。区切り文字はスペース。
例はこんな感じ。実際はもっと長いが途中省略する。
P2 16 16 65535 32632 28557 31507 33464 33510 42367 46113 48265 49762 51108 51933 53282 42071 37332 36162 17002 30002 27844 30897 32782 ...
四行目以降に注目して、(2,2)の値を見ると"42367"となっているが、実際にはこの値は(1,6)のものであることに注意する必要がある。これを、以下みたいな感じにするスクリプトを書く。
16 16 32632 28557 31507 33464 33510 42367 46113 48265 ...
実際に書いたスクリプトはこれ。
NR == 2 { print $0 } NR > 3 { for(i=1; i<=NF; i++) printf("%d ", $i) } END { printf("\n") }
これを"step1.awk"と名づけて以下のコマンドを実行すると、step1の結果が出てくる。
awk -f step1.awk test.pnm > step1.txt
Step2
以下のスクリプトで、各行にM個のフィールドがあるよう整形します。
NR == 1 { row = $1 column = $2 } NR > 1 { for(i=1; i<=NF; i++) printf("%d%s", $i, i%column==0 ? "\n" : " ") }
これを"step2.awk"と名付け、以下のコマンドを実行します。
awk -f step2.awk step1.txt > test.mat
これで、PNM形式からNxM行列の形に整形できたので、octaveやらに読み込ませることができます。