2009年12月28日月曜日

ImageMagickでHSLとHSV色空間を理解する

前回のRecipeは、画像加工ツールとして有名なImageMagickを取り上げました。

Ubuntu Weekly Recipe:第102回 ImageMagickでコマンドラインから画像加工|gihyo.jp … 技術評論社

写真加工に役に立つ情報はRecipe本編をご覧いただくとして、ここではImageMagickで色空間の説明をします。

RGB

デジカメで撮影したJPEG画像は、Red, Green, Blueの3色の割合で色を表現しています。次の写真をRGBの3つのチャンネルに分けてみます。

RGBのチャンネルに分解して、RGBの順で左から右へ並べるには、以下のコマンドを実行します。

convert P001.jpg -colorspace RGB -separate +append P001_separate.jpg

黒がそのチャンネルの0%を、白が100%を表しています。このままだと少しわかりにくいので、チャンネルごとに着色してみます。RGBのパレットを作って、先ほど分解した画像と重ねます。

convert P001.jpg +level-colors Red \ \( +clone +level-colors Green1 \) \ \( +clone +level-colors Blue \) \ +append \ P001_separate.jpg \ -compose Multiply -composite P001_rgb.jpg


このようなRGB3つのチャンネルが重なり合って1つの画像になっています。ただ、この状態ではどの場所がどの色になるのか非常にわかりにくいです。そこで、色と他の情報を分離するために、HSVやHSLといった色空間が使われます。

HSV, HSL

今度はHSV, HSLに分解してみます。なおImageMagickではHSVをHSBと表記するのでコマンド中ではHSBとしています。

for i in B L; do convert P001.jpg -colorspace HS${i} \ -separate +append P001_HS${i}_separate.jpg; done

比較するために、HSVを上段、HSLを下段として並べます。

convert P001_HS?_separate.jpg \ -bordercolor Black -border 0x5 \ -append -border 10x5 P001_HSB_HSL.jpg

左列のHueは、両色空間の定義から同一になります。また、下段右のLightnessのチャンネルは、GIMPの「Desaturate(脱色)」で、「Lightness(明度)」を選択した時と同一になります。
ちなみにDesaturateツールのLuminosity(光度)は、HSVやHSL色空間と関連がないので、GIMPのドキュメントを見てください。

これでは、HSVやHSLでは、「色という情報を分離している」というのがいまいちわかりにくいので、試しにHueチャンネルをこてこてに着色してみます。HSV色空間でS=100%, V=100%とします。

convert P001.jpg -colorspace HSB -channel R -separate \ \( +clone +level-colors White \) \( +clone \) \ -set colorspace HSB -combine -colorspace RGB P001_Hue.jpg

これが元の画像のHueチャンネルが持っている色の情報です。このように、Hueチャンネルが色に関する情報をすべて持っているので、残りのチャンネルをどんなに加工しても、「青色だったところがいきなり赤色に」なんてことはありません。

HSV, HSL色空間円柱モデルの作成

HSVとHSLの違いを見るために、定義に従ってImageMagickで円柱モデルを作ります。円柱モデルと言っても、水平断面をいくつか組み合わせて作ります。まずは必要なパーツを作成していきます。

Hueは、円柱を水平面で切り取った円では、0度で0%を、360度で100%を取ります。よって以下のコマンドを実行すると、作成できます。

convert -size 100x400 gradient: -rotate -90 \ -distort Arc '360 -90' +repage \ -gravity Center -crop 200x200+0+0 +repage \ -depth 8 Hue.png

円って言ったのに、正方形です。後で円として切り出します。

Saturationは円柱の中心線からの距離です。中心が0%で、外周で100%の値を取ります。よって以下のコマンドで作成します。

convert -size 200x200 radial-gradient:Black-White -depth 8 Saturation.png

ValueまたはLightnessは、円柱の最下部で0%を、最上部で100%を取ります。断面では、特に必要な操作はなく、与えられたパーセントでベタ塗りするだけです。

ついでに、円として切り抜くためのマスクを作っておきます。

convert -size 200x200 xc:Black -fill White -draw 'Circle 99.5,99.5 0,100' +matte -depth 8 Mask.png

作成したパーツを使って円柱モデルを組み上げていきます。ValueまたはLightnessのチャンネルは、0%から100%まで、10%ずつ変化させます。

for i in B L; do convert -size 200x700 xc:none -depth 8 Model_HS${i}.png for j in {0..100..10}; do convert Model_HS${i}.png \ \( Hue.png Saturation.png -size 200x200 xc:Gray${j} \ -set colorspace HS${i} -combine -colorspace RGB \ Mask.png -compose CopyOpacity -composite \ -resize 100%x50%\! \ \) \ -compose Over -geometry +0+$(( 600 - ${j} * 6 )) -composite \ -depth 8 -verbose Model_HS${i}.png done done

ついでに文字も入れてみます。

for i in B L;do convert Model_HS${i}.png -bordercolor none -border 10x10 \ -background none -fill white -size 200x50 -gravity Center label:HS${i} \ -append \ -depth 8 Label_HS${i}.png done

左右に並べて、円柱モデルの完成です。

convert Label_HS?.png +append \ -bordercolor none -border 10x10 \ -background Gray50 +flatten \ -depth 8 Model.png

このように並べると、HSV(ImageMagickの表記ではHSB)とHSLで、かなり違いがあるのがわかります。特に「白」の位置が大きく異なります。

円柱モデルの鉛直断面

先ほど作った円柱モデルの、Hue=0%と50%での鉛直断面を作ってみます。

for i in B L; do \ for j in 0 50; do \ convert -size 200x200 xc:Gray${j} gradient: -rotate 90 gradient: \ -set colorspace HS${i} -combine -colorspace RGB \ -depth 8 Section_Cylindrical_HS${i}_${j}.png done done

convert -set colorspace RGB \ \( Section_Cylindrical_HSB_*.png -append \) \ \( Section_Cylindrical_HSL_*.png -append \) \ +append -depth 8 Section_Cylindrical.png

左列がHSV、右列がHSLで、それぞれ円柱モデルの鉛直断面です。右に行くほどSaturationが大きく、上に行くほどValueまたはLightnessが大きくなっています。
また、左列のHSVに注目すると、GIMPのパレットのデフォルトと同じ分布になっています。(ただし、向きが異なります。)

円錐モデルの鉛直断面

HSVやHSL色空間を表すのには、円柱モデルだけでなく、円錐モデルも使われます。円錐モデルは、HSVでは円錐をひっくり返したような形、HSLでは、円錐を2つつなげてそろばんの玉のような形になります。細かいことはさておき、HSL円錐モデルのHueの6つの値での鉛直断面を作成します。

for i in Red Yellow Green1 Cyan Blue Magenta; do convert \ -size 173x200 xc:${i} -colorspace HSL -channel R -separate \ png:- | convert \ - \ \( -size 173x100 xc:black -fx "i/w*h/(h-j)" -flip \( +clone -flip \) -append \) \ \( -size 173x200 gradient: \) \ -set colorspace HSL -combine -colorspace RGB \ \( -size 173x200 xc:Black -fill White -draw 'Polygon 0,1 172,100 0,199' +matte \) \ -compose CopyOpacity -composite \ -depth 8 -verbose Section_Conic_HSL_${i}.png; done

画像を並べます。

convert -set colorspace RGB \ Section_Conic_HSL_{Red,Yellow,Green1,Cyan,Blue,Magenta}.png \ -bordercolor none -border 20x20 \ +append -border 20x20 \ -background Gray50 +flatten \ -depth 8 Section_Conic_HSL.png

これはGIMPのパレットで、ホイールを選択した場合と同じ分布です。(また向きは違います。)

HSVとHSLの対応

先ほど作成した三角形は、HSLモデルの断面なので、作成方法から、SとLの関係は下の図のようになります。

この図中で、HSVにおけるSとVは何を表しているのか探ってみます。HSVのSとVに分解します。

convert -set colorspace RGB \ Section_Conic_HSL_Red.png -background Black +flatten \ -colorspace HSB \( +clone -channel B -separate \) -channel G -separate \ +append -depth 8 Section_Conic_HSL_separateHSB.png

左側がHSVのSで、右側がVです。変化をわかりやすくするために、8階調に落とします。

convert Section_Conic_HSL_separateHSB.png \ +level 0,7 -level 0,7 Section_Conic_HSL_separateHSB_8.png

この結果を元に先ほどの図に、HSVでのSとV(ImageMagickの表記ではB)の軸を書き込むと下の図になります。

HSVとHSLの関係性はこのようになっています。この図から、「HSVでSを上げると白に近かった部分に色がついてしまう」「HSLでLを下げると白に近かった部分に色がついてしまう」といったことがわかります。なので写真を操作する場合は、HSVのVと、HSLのSを操作すると失敗が少ないでしょう。でないと、雲の白色がおかしくなったりします。

Recipeの例では、-modulateでHSLのSを操作してから、-linear-stretchでHSVのVを操作しています。

0 コメント:

コメントを投稿

スパムコメントを防ぐため、コメント投稿時に確認用の文字列入力にご協力いただいております。

Related Posts with Thumbnails