画像解析入門: 画像のフォーマットに関する実習
前章で, 画像のファイル形式(フォーマット)をいろいろ紹介しましたが, 実際にそれらを試してみましょう。
課題1: まず, 下の画像を右クリックして「名前をつけて画像を保存」などのメニューを選ぶことによって, 自分のPCのハードディスクのホームディレクトリ(~/)に"lake.jpg"というファイル名で保存して下さい:

ちなみにここに写っているのは北海道のオンネトーという湖です。
課題2: では, コンソールを開いて(ホームディレクトリにいるという前提で), 以下のコマンドを打って下さい:
$ cd ~/ $ ls -l lake.jpg
すると, 以下のような表示が出ればこのファイルがちゃんとあるということです(成功):
-rw-rw-r-- 1 xxxxxx xxxxxx 80981 x月 xx xx:xx lake.jpg
(この表示のxの部分は利用環境によって異なる表示になります)
質問: うまくいきません。「ls: 'lake.jpg' にアクセスできません: そのようなファイルやディレクトリはありません」というエラーメッセージが出てしまいました。
回答: 別のディレクトリにダウンロードしてしまった可能性があります。以下のコマンドで探してみて下さい:
$ find ~/ -name "lake.jpg"
課題3: 次はこのファイルを画像として表示してみましょう。以下のコマンドを打って下さい:
$ display lake.jpg
湖の画像が画面に表示されましたか? ちなみにdisplayコマンドは, Imagemagickのコマンドのひとつです。
課題4: この画像に関する詳細情報(メタデータ)を見てみましょう。コンソールで以下のコマンドを打って下さい。
$ identify lake.jpg
以下のような表示が出れば成功です。identifyもImagemagickのコマンドです。
lake.jpg JPEG 800x600 800x600+0+0 8-bit sRGB 80981B 0.000u 0:00.000
これを見ると, lake.jpgはJPEG形式のファイルであり, 横800ピクセル, 縦600ピクセルで構成され, 各ピクセルは三原色(RGB)がそれぞれ8ビット(1バイト)で構成されており, ファイルサイズは80981バイトであることがわかります。
課題5: もっと詳細なメタ情報を表示させてみましょう。こうやるのです:
$ identify -verbose lake-small.jpg
すると, 画面が流れるくらいたくさんの情報が出てくるでしょう。
画像の拡大縮小
課題6: ではこの画像を縮小してみましょう。以下のコマンドを打って下さい:
$ convert lake.jpg -resize 400 lake-small.jpg
この400は, 新たな画像ファイルの横幅(ピクセル数)です。ではできたファイルを確認しましょう:
$ ls -l lake-small.jpg -rw-rw-r-- 1 xxxxx xxxxxx 21338 x月 xx xx:xx lake-small.jpg
ちゃんとlake-small.jpgという名のファイルができていますね。ファイルサイズはもとのlake.jpgよりもだいぶ小さくなっているはずです(80981バイト→21338バイト)
では, できたファイルを表示してみましょう:
$ display lake-small.jpg
もとの画像の半分の大きさの画像が画面に現れましたか?
JPEG画像の品質
JPEG画像は非可逆圧縮ですから, 情報をたくさん切り落とすことで, ファイルサイズを小さくできます。その程度を表すのがQualityというパラメータです。
課題7: まず, 課題6で作ったlake-small.jpgのQualityパラメータを調べてみましょう:
$ identify -verbose lake-small.jpg
するとたくさん出てくる情報の中で, 次の行が見つかるでしょう:
Quality: 75
この75は75パーセントを意味します。最高品質(情報欠損がほぼ無い場合)で100パーセントです。
この行だけを表示するには以下のようにパイプでgrepコマンドにつなぐとよいです(この意味がわからない人はLinuxの入門書を見て下さい):
$ identify -verbose lake-small.jpg | grep Quality
課題8: では, 課題6をもっと低品質の画像に作り直してみましょう。以下のコマンドを打って下さい:
$ convert lake.jpg -resize 400 -quality 25 lake-small2.jpg
これは課題6のコマンドに"-quality 25"というオプションを付け足したものです(出力先のファイル名も変えています)。
できたファイルを確認しましょう:
$ ls -l lake-small2.jpg -rw-rw-r-- 1 xxxx xxxx 7897 x月 xx xx:xx lake-small2.jpg
ファイルサイズはlake-small.jpgよりも劇的に小さくなっていますね(21338バイト→7897バイト)。Qualityパラメータも確認しましょう:
$ identify -verbose lake-small2.jpg | grep Quality Quality: 25
確かに25パーセントになっていますね。
以下にこの2つの画像を一緒に表示してみてください。こういうふうになります:
$ display lake-small.jpg &
... 品質75% (lake-small.jpg)
$ display lake-small2.jpg &
... 品質25% (lake-small2.jpg)
ぱっと見ではあまり変わりませんが, よく見ると中央の森のあたりは明らかに画質が違います。奥の山の輪郭も, 品質25パーセントではぼやけています。品質25パーセントは, 品質を犠牲にしてファイルサイズを小さくしていることがわかったでしょうか?
質問: 上のdisplayコマンドの最後の&は何ですか?
回答: バックグラウンドで実行せよという意味です。2つの画像を同時に表示させるためにそうしました。わからない人はLinuxの入門書を見て下さい。
ちなみにJPEGに限らず, データ圧縮では, どのくらい圧縮できるか(圧縮効率)はデータの種類や性質に大きく依存します。単調だったり規則的なデータはよく圧縮できますが, 複雑なデータはあまり圧縮できません。
PNG, BMP, TIFF, PNM
こんどは, JPEG以外の圧縮形式, 特に, 可逆圧縮および非圧縮のファイル形式を試してみましょう。
課題9: 以下のコマンドを打ってください。それぞれ順に, PNG形式, BMP形式, TIFF形式, PPM形式のファイルに変換するコマンドです。
$ convert lake.jpg lake.png $ convert lake.jpg lake.bmp $ convert lake.jpg lake.tif $ convert lake.jpg lake.ppm
できたファイルを確認しましょう:
$ ls -l lake.*
以下のように表示されれば成功です(xは状況次第で変わる部分):
-rw-rw-r-- 1 xxxx xxxx 1440138 x月 xx xx:xx lake.bmp -rw-rw-r-- 1 xxxx xxxx 80981 x月 xx xx:xx lake.jpg -rw-rw-r-- 1 xxxx xxxx 670716 x月 xx xx:xx lake.png -rw-rw-r-- 1 xxxx xxxx 1440038 x月 xx xx:xx lake.ppm -rw-rw-r-- 1 xxxx xxxx 1440350 x月 xx xx:xx lake.tif
この中で, PNG形式(lake.png)は可逆圧縮です。もともとのlake.jpgの約8倍のファイルサイズになってしまいました(80981バイト→670716バイト)。写真のファイルサイズを小さくするには, JPEGのような非可逆圧縮が強力だとわかりますね。
BMP, PPM, TIFFの3つの形式(lake.bmp, lake.ppm, lake.tif)は非圧縮のファイル形式です(注: PPM形式は, PNM形式の一種です)。それぞれ1440138バイト, 1440038バイト, 1440350バイトと, 互いにとても近い値であることに注目して下さい。
この大きさは, 先に述べた式で決まっているのです。つまり, これらの画像の横のピクセル数は800, 縦のピクセル数は600で, カラーの1ピクセルは3バイト(RGB3原色に各1バイト)とすると, 画像全体の情報量は
800 × 600 × 3 バイト = 1440000 バイト
となるわけです。
非圧縮のファイル形式は, このように単純な計算でファイルサイズが決まります(実際のファイルサイズがこれよりもちょっと大きいことは次節で解説します)。これは様々な処理がうまくいっているどうかのチェックに使えます。つまり, 何らかの処理の結果としてできた非圧縮画像ファイルのサイズがこの計算結果と大きく異なる場合には何か不具合が生じているはずだとわかるのです。
ヘッダー情報
ところで, ここで調べたlake.bmp, lake.ppm, lake.tifという3つのファイルは, そのサイズが正確に1440000バイトにはならず, わずか余分があるのはなぜでしょうか? 実はその余分は画像のフォーマットに関する付帯情報なのです。そのような付帯情報は, 画像データの先頭に記述されることが多く, その場合は「ヘッダー情報」とも呼ばれます。
ためしにlake.ppmのヘッダー情報を見てみましょう。1440038バイトのうちの最初の38バイトがヘッダー情報だと見当がつきます。このような推測というか, いわば「ノリ」はITの学習で重要です。そしてこの「38」という値はあなたの計算環境では微妙に違うかもしれないので, 調整して下さい。
課題10: そのヘッダー情報とおぼしき部分をまず切り出しましょう。以下のコマンドを打って下さい:
$ dd ibs=38 count=1 < lake.ppm > head.txt
(38は適宜, 自分の状況に合わせて変えて下さい)
このddというコマンドは, バイナリーファイルの一部を切り出したりするときによく使うので, 覚えておいて下さい。コマンドの使いかたについての詳しい説明は, $ man ddのようにしてオンラインマニュアルを見て下さい。<と>は標準入出力のリダイレクトです(わからない人はLinuxのテキストを復習しましょう)。
課題11: このコマンドの結果, lake.ppmのヘッダー情報はhead.txtというファイルに入ったはずです。その中を見てみましょう:
$ cat head.txt P6 #Created with The GIMP 800 600 255
これらの情報の意味はPNM形式の仕様で決まっており, 具体的には以下のとおりです:
1行目: 画像の種類 P1 ・・・ 白黒2値画像 (ASCII形式) P2 ・・・ モノクロ濃淡画像 (ASCII形式) P3 ・・・ RGBカラー画像 (ASCII形式) P4 ・・・ 白黒2値画像 (Binary形式) P5 ・・・ モノクロ濃淡画像 (Binary形式) P6 ・・・ RGBカラー画像 (Binary形式) 2行目: #からはじまる, コメント行。 3行目: 画像の横ピクセル数と縦ピクセル数 4行目: データの最大値
lake.bmpとlake.tifもヘッダー情報を持っていますが, lake.ppmよりもちょっと面倒なので, スルーして先に進みます。
rawバイナリーファイル
このように, 非圧縮のファイル形式にはヘッダー情報がついている(ことが多い)のですが, ヘッダー情報は画像データそのものではない(画像データをどう表しているかに関する情報)ので, 時には邪魔になることがあります。そこで, ヘッダー情報を取り去って, まさに各ピクセルの情報だけを単純に並べただけのシンプルな画像ファイルを扱うことがあります。(これは特に, 気象データや衛星観測データを扱う時によくある状況です)。
そのような画像ファイルを, rawバイナリーファイルと呼びます。rawは「生」, つまり何も余分なことをされていない状態, という意味です。
課題12: では上の画像のrawバイナリーファイルを作ってみましょう。それには例えば, lake.ppmから, ヘッダー情報(54バイト)を削除すればよろしい。これにもddコマンドを使います(先ほどのddコマンドとよく似た使いかたですが, どこがどう違うか, 考えてみて下さい):
$ dd ibs=38 skip=1 < lake.ppm > lake.raw
(38は適宜, 自分の状況に合わせて変えて下さい)
こうして作られたlake.rawは, rawバイナリー, つまり, ヘッダーを全く含まない非圧縮ファイルのはずなので, ファイルサイズは正確に1440000バイトのはずです。そうなっているか, $ ls -l lake.rawで確かめて下さい。
Keyword(s):
References:[C言語による画像処理: 画像の切り出し] [画像解析入門]