はじめに
ImageMagick のガンマ補正解説です。なお、PNG 出力結果は非直感的で個人的に不具合だと思いますが、それを含めて現状を説明します。
ImageMagick のガンマ補正
ImageMagick のガンマ補正オプションには、-gamma, +gamma があります。あと実は -level もそうです。
Gamma adjusts the image's channel values pixel-by-pixel according to a power law, namely, pow(pixel,1/gamma) or pixel^(1/gamma), where pixel is the normalized or 0 to 1 color value. For example, using a value of gamma=2 is the same as taking the square root of the image.
つまり、指定した値の逆数で輝度0〜1(max)の値をべき乗計算します。
(c) https://ja.wikipedia.org/wiki/ガンマ値 |
-level は本来レベル補正(線形コントラスト補正)ですが、同時にガンマ補正も行えます。
-level black_point{,white_point}{%}{,gamma}
(略)
Gamma will do a -gamma adjustment of the values. If it is omitted, the default of 1.0 (no gamma correction) is assumed.
これらのうち、-gamma は出力先が JPEG や TIFF の際には直感的に使えますが、PNG では恐らく意図しない結果になるでしょう。
PNG の場合は画像のRGBデータと一緒にメタデータのガンマ値(gAMAチャンク)まで弄る為です。
PNG gAMA チャンクについては以下の記事を参考にどうぞ。
- PNG 画像のガンマ補正
サンプル画像
以下のコマンドで生成した画像をサンプルとして用います。グレースケールとカラー画像の2つです。
% convert -size 200x100 xc:white -fx "floor(i/w*5)/4*u" -depth 8 white.png
% convert -size 200x100 xc:cyan -fx "floor(i/w*5)/4*u" png24:cyan.png
white.png | cyan.png |
---|---|
-gamma
このオプションは低輝度と高輝度をなるべくそのままに、中輝度の明るさを調整したい。といった事に便利です。
こちらだとブラウザで試せるので、単純なガンマ補正を体感したい方はどうぞ。
JPEG の挙動
まず、JPEG 出力で試してみます。
% convert white.png -gamma 2.0 white-2.0.jpg
% convert cyan.png -gamma 2.0 cyan-2.0.jpg
white-2.0.jpg | cyan-2.0.jpg |
---|---|
この画像は確かに $ pixel^{1.0/2.0} $ の明るさに変化しています。
これが本来意図した -gamma の挙動でしょう。
PNG の挙動
PNG 出力だと、結果が明るすぎます。(ただし、画像ビューアによっては JPEG と同じ明るさに見える事もある)
JPEG 出力だと -gamma 2.0 を二回適用したのと同等です。
% convert white.png -gamma 2.0 white-2.0.png
% convert cyan.png -gamma 2.0 cyan-2.0.png
% convert white.png -gamma 2.0 -gamma 2.0 white-2.0-2.0.jpg
% convert cyan.png -gamma 2.0 -gamma 2.0 cyan-2.0-2.0.jpg
white-2.0.png | cyan-2.0.png |
---|---|
white-2.0.jpg | cyan-2.0.jpg |
white-2.0-2.0.jpg | cyan-2.0-2.0.jpg |
先ほど言及したように、PNG のメタデータのガンマ値が変化しているのが原因です。
% identify -verbose cyan.png | grep gamma
png:gAMA: gamma=0.45455 (See Gamma, above)
% identify -verbose cyan-2.0.png | grep gamma
png:gAMA: gamma=0.9091 (See Gamma, above)
0.45455=(1.0/2.2) から 0.9091=(1.0/(2.2/2.0) = 1.0/1.1) に変化しています。
まともな画像ビューアはこの gAMA 値で補正して表示する為、余計に色が明るくなるのです。(たまに無視するのもいます)
これ自体は、+gamma で対処可能です。
とはいえ、この挙動には自分も納得いっていませんし、ワークアラウンド扱いです。
あと、-level はガンマ補正もできて、かつ gAMA を弄らないので、こちらを使う方が良いかもしれません。
+gamma
+gamma は画像データはそのままで、メタデータのガンマ値だけ上書きするオプションです。なお、0.45455 は 1.0/2.2 相当です。
% convert white-2.0.png +gamma 0.45455 white-2.0+0.45455.png
% convert cyan-2.0.png +gamma 0.45455 cyan-2.0+0.45455.png
これでガンマ値が元に戻るので、JPEG と同様の表示になる PNG 画像が作れます。
white-2.0+0.45455.png | cyan-2.0+0.45455.png |
---|---|
white-2.0.jpg | cyan-2.0.jpg |
% identify -verbose cyan-2.0+0.45455.png | grep gamma
png:gAMA: gamma=0.45455 (See Gamma, above)
なお、JPEG や GIF はメタデータとしてガンマ値を置けないので、+gamma を使っても表示が変わりません。
-level
% convert white.png -level "0,100%,2.0" white-levelgamma-2.0.png
% convert cyan.png -level "0,100%,2.0" cyan-levelgamma-2.0.png
こっちは見た目も JPEG と同じです。
white-levelgamma-2.0.png | cyan-levelgamma-2.0.png |
---|---|
white-2.0.jpg | cyan-2.0.jpg |
-gamma と違って gAMA が不変で、RGB データだけ変換するので直感的に使えます。
% identify -verbose cyan-levelgamma-2.0.png | grep gamma
Filename: cyan-levelgamma-2.0.png
png:gAMA: gamma=0.45455 (See Gamma, above)
PNG 生成
ついでに -gamma/+gamma 関係なく、PNG 生成する時に gAMA がどう扱われるかの、簡単なまとめです。
新規 PNG 生成
ImageMagick で PNG ファイルを一から生成すると 0.45455(=1.0/2.2) の gAMA チャンクが付与されます。
% convert -size 200x100 xc:white -depth 8 -fx "floor(i/w*5)/4*u" white.png
% convert -size 200x100 xc:cyan -fx "floor(i/w*5)/4*u" png24:cyan.png
PNG から変換
画像ファイルを渡して PNG ファイルに変換する場合は、元のガンマ値を引継ぎます。
% identify -verbose cyan-2.0.png | grep gamma
png:gAMA: gamma=0.9091 (See Gamma, above)
% convert cyan-2.0.png -resize 50% cyan-2.0-x50%.png
% identify -verbose cyan-2.0-x50%.png | grep gamma
png:gAMA: gamma=0.9091 (See Gamma, above)
JPEG から変換
JPEG のメタデータにはガンマ値を含められないので、2.2 相当(実際には 1.0/2.2)のガンマ値として PNG 生成されます。
% convert cyan-2.0.png cyan-2.0.png.jpg # メタデータのガンマ値が消える
% convert white-2.0.png white-2.0.png.jpg # 〃〃
% convert white-2.0.png.jpg white-2.0.png.jpg.png # ガンマ値がないので、0.45455 が埋まる
% convert cyan-2.0.png.jpg cyan-2.0.png.jpg.png # 〃〃
% identify -verbose white-2.0.png.jpg.png | grep gamma
png:gAMA: gamma=0.45455 (See Gamma, above)
% identify -verbose cyan-2.0.png.jpg.png | grep gamma
png:gAMA: gamma=0.45455 (See Gamma, above)