ImageMagickで「自然な彩度」強調

ID: 164
creation date: 2014/07/05 00:40
modification date: 2014/07/05 00:40
owner: fallabs

Photoshop等で実装されている「自然な彩度」強調機能と似たようなことをImageMagickでもできないかと思って検討してみた。

自然な彩度とは

Adobe Photoshopの最近の版では、色を濃くしたり薄くしたりするための設定として、「彩度」と「自然な彩度」の二種類がある。Android標準の写真編集機能にもその二つがある。Adobeのページによると、"従来の「彩度」が適用範囲の彩度を均等に調整するのに対して、「自然な彩度」は彩度が高いカラーへの影響を抑えながら、彩度が低いすべてのカラーの彩度を調整します。" とのこと。

ソースが公開されているわけでもないので具体的なアルゴリズムは謎だが、自分なりに想像してみる。まず、「彩度」に関しては、HSL色空間のSチャンネル(Saturation=彩度)の値に係数を掛ける線形操作であろう。例えばパラメータ1.2(UI上は120とか?)で適用すると、Sが0.5(8ビットなら127)のピクセルは 0.5 * 1.2 = 0.6(153)になる。ここで問題となるのは、単に掛け算をすると簡単に値が変域の上限(1.0=255)を振り切ることだ。つまり色飽和しやすいということである。

一方、「自然な彩度」は、処理後の値が上限を振り切って色飽和しないように配慮しているはずである。おそらくHSL色空間のSチャンネルに対してガンマ補正的なことをしているのであろう。例えばパラメータ1.2で適用すると、Sが0.5のピクセルは 0.5 ^ (1/1.2) = 0.56で、Sが0.9のピクセルは 0.9 ^ (1/1.2) = 0.91になる。もっと複雑な計算をしている可能性が高そうだが、とにかく線形でない変換をしていることは間違いない。

ImageMagickの機能

ImageMagickで彩度を操作するオペレータとして、-moduleteがある。これはHSL色空間の各チャンネルに線形変換をかけるものだ。例えば、-modulete 100,150,100 とすると、Hチャンネル(Hue=色相)とLチャンネル(Lightness=輝度)は変えずに、Sチャンネルだけ1.5倍する。これはPhotoship等における「彩度」設定とほぼ同じものと言える。

ImageMagickは何でもありなツールで、線形変換以外の操作もサポートしている。-colorspaceオペレータによる色空間変換と、-evaluateオペレータや-fxオペレータによる任意の数値演算を組み合わせれば、たいていの画調変換は実装できる。

実験

いろいろ実験してみよう。元画像としてこんな画像を用意した。よく撮れているので修正の必要はないと思うが、敢えて彩度をさらに上げて派手な画像を作ってみよう。

image:1:1404488256-default.jpg

彩度を線形に上げるにはこうすればいい。1.5倍するならこんな感じ。

convert original.jpg \
  -modulate 100,150,100 \
  linear-result.jpg

すると、こうなる。派手になったのはいいが、ペットボトルの蓋のところや背景の葉っぱが色飽和している。

image:2:1404488284-linear.jpg

色飽和を防ぐべく、ガンマ補正をしてみる。HSLのSチャンネルにガンマ補正1.4をかけるにはこうすればいい。

convert original.jpg \
  -colorspace HSL -channel G \
  -gamma 1.4 \
  -colorspace RGB \
  gamma-result.jpg

結果はこうなる。線形変換で色飽和していた部分をよーく見比べると、階調が若干多く残っているっぽい。その点では期待通りだ。

image:3:1404488305-gamma.jpg

ただし、ガンマ補正は値が低い部分ほど強力にかかるので、もともと彩度が低い部分が色転びしやすくなるという問題がある。上の例だと、髪の毛をオレンジや紫に染めたみたいになってしまっている。

これを解決するには、ガンマ補正に加えてシグモイド補正もかけてあげるとよい。つまり0.5未満の値を小さくしようすることで、ガンマ補正による急激な増加を相殺する。一方で0.5を超える値はより大きくしようとするので、全体の彩度は上がることになる。シグモイド補正のパラメータの設定は難しいのだが、いろいろ試してみた結果、ガンマ値に対して log2(gamma) * 8 くらいにするとよさげなことがわかった。つまりガンマ値1.5の場合には適正シグモイド値は log2(1.5) * 8 = 4.679である。

convert original.jpg \
  -colorspace HSL -channel G \
  -gamma 1.4 \
  -sigmoidal-contrast 4.679 \
  -colorspace RGB \
  sigmoid-result.jpg

結果はこうなる。髪の部分の彩度はだいぶ落ち着いて自然な感じになっている。

image:4:1404488323-sigmoid.jpg

実際のところ、ガンマ補正1.5とかは明らかにやりすぎなので、1.2くらいに抑えておいた方がいい。その場合の適正シグモイド値は2.1くらいである。

image:5:1404488429-pale-default.jpg
image:6:1404488442-pale-sigmoid.jpg

一様分布のグラデーション画像に対してガンマ・シグモイド補正をかけた場合のヒストグラムを以下に示す。ガンマ値1.2とシグモイド値2.1、ガンマ値1.5とシグモイド値4.7、ガンマ値2.0とシグモイド値8.0の例である。シグモイド補正をかけているおかげでシャドー部のヒストグラムが平坦になっていることがわかる。すなわちシャドー部の増加が線形に近いということだ。一方でハイライト部はオーバーハングした山になっていて、これは飽和させないように増加がガンマカーブを描いていることを示している。

image:7:1404490316-histogram-1.2.png
image:8:1404490323-histogram-1.5.png
image:9:1404490330-histogram-2.0.png

まとめ

「自然な彩度」強調をImageMagickでもできることを示した。HSL色空間のSチャンネルに対してガンマ1.2とシグモイド2を適用すると、自然に彩度が上がった画像が得られる。おためしあれ。

0 comments
riddle for guest comment authorization:
Where is the capital city of Japan? ...