/**/

チュートリアル 6:
カラーレベルの調整

jit.scalebias オブジェクト

このチュートリアルでは、前の章での色の解説に関してより詳しく見ていきます。さらに、マトリックスのARGBカラープレーンの加工のために特別に設計された、jit.scalebiasオブジェクトを紹介したいと思います。

ここでの「スケール」という語は、特定の係数の値によるスケーリング処理、すなわち、それを与えられた値に掛けることを指します。「バイアス」という語は値に一定の値を加えてオフセットすることを指します。乗算と加算の処理を組み合わせることによって、入力された値を出力する値に線形にマッピング(写像)することができます。

jit.scalebias は画像のARGBカラー情報の加工に関与するため、4プレーンのcharデータ型マトリックスだけを取り扱います(チュートリアル5のARGBカラーとcharデータに関する解説を参照してください)。

charデータでの計算

前の章で述べたように、8ビットの char データは0から255までの整数値、または 0 から1までの小数値を表すことができます。一例として、チュートリアル2では jit.print オブジェクトが char データを0〜255までの整数値として示しているのを見ました。しかし、char型の値をマトリックス内で(そのアトリビュートの1つを変更することによって)加工しようとする多くの場合、Jitterオブジェクトはアトリビュートの値としてfloat を受け取ることを前提としています。これは、ちょっとした混乱を招く恐れがあるので、このチュートリアルパッチで実例を用意しました。

・Jitter Tutorial フォルダにある06jAdjustColorLevelsというチュートリアルパッチを開いて下さい。パッチの中程にあるpatcher explain_scalebias オブジェクトをクリックして、サブパッチ[explain_scalebias] の内容を見て下さい。


charデータにおけるfloatによる計算の説明

上の例では、1つのセルしか持たない、4プレーンのchar データという、非常に小さなマトリックスを作ってみました。これによって、マトリックスの1つの数値に起こることに対して焦点を絞ることができると思います。プレーン2(緑のプレーン)に値100がセットされているのがわかると思います。例の左側では、この整数値を0と1の間の小数で表す方法がわかるようになっています。このケースでは0〜1の間の100/255 なので、0.392です。

jit.scalebias オブジェクトは scale アトリビュートで指定された特定の値で乗算し、その後、 biasアトリビュートで指定された特定の値を加算します。jit.scalebias によってマトリックスが変更される際には、全ての値は計算のためにfloatとして扱われ、その後charデータとしてマトリックスにリストア(再び格納)されます。

ここでは、scale および bias アトリビュートは scale 2.0 および bias 0.2 メッセージによってセットされています。この場合、スケーリング係数(掛け合わせる値)は2.0、バイアス(その後に加算されるオフセット)は0.2になります。そこで、jit.scalebias の内部で何が行われているかを理解するためには、緑の値0.392が 2.0倍されて、0.2を加えられ、結果は0.984になると考える必要があります。jit.iter オブジェクトは各セル(このマトリックスには1つのセルしかありません)の各々のプレーンの値を示してくれるので、その(charとしてマトリックスに格納された時の)値が251(または、0から1にスケールされれば0.984)であるのを見ることができます。

(ちょっとした頭の体操ですが、上の例で jit.scalebias が赤と青のプレーンをどんな値にしているか計算できますか?もともとのマトリックスのこれらのプレーンは0ですから、結果としてのマトリックスの値は0掛ける2.0足す0.2イコール0.2 となります。これは0から255 の値に換算すると51です。このため、下の jit.pwindow オブジェクトに表示されるRGBの値は 51 251 51 になります。)

charデータでの計算の例

前の説明が非常に明解に感じられたのであれば、これ以降の補足的な例は飛ばしてしまいたいかも知れませんが、charデータによる演算が(特に、jit.scalebiasの場合)どのような結果をもたらすかについて確信が持てないという方のために、いくつかの例をあげてみます。

presetオブジェクトのプリセットを、左から右へ順番に1つずつクリックして下さい。以下のパラグラフで、各々のプリセット例について説明します。

  1. もともとのマトリックスの緑のプレーンの値は255です(これは0〜1に換算すると1.0になります)。jit.scalebiasオブジェクトはこれに0.5を掛けますから、結果は127.5 という中間の値になります。しかし、char として格納される場合、jit.scalebiasは小数部を丸める(切り捨てる)ので、127という値が格納されます。

このことは、確かに不正確な結果を生みます(期待される値が0.5であるのに対して、0〜255のスケールにおける127は、0〜1のスケールでは0.498になります)。しかし、これは8ビットのcharデータで可能な最善の値です。これより細かい精度が必要な場合、charデータは不向きです。代わりにlong、float32、float64というデータ型によるマトリックスを用い、jit.op @* および jit.op @+ オブジェクトで演算を行う必要があります。

  1. もともとの値は100で、これを2倍(スケーリング係数2.0)し、期待される答えは 200になります。この場合、精度によるロスはありません。
  2. もともとの値は100(0.392)です。係数1.0を掛けますから、値はそのままで変化しません。そして-0.2 をそれに加えます(これは、0.2を引くことになります)。結果は49(0.192)になります。
  3. 0.392に2.0を掛け、0.2を足します。0〜255のスケールでは251です。
  4. この例と次の例では、乗算、および加算が行われた結果が8ビットcharの範囲を超えた場合にどうなるかを示しています。jit.scalebias は単に結果をcharの最大値または最小値にクリップ(制限)します。ここでは、0.392に4.0を掛けて、1.568 (すなわち、100掛ける4で400)になるので、結果は可能な最大値である255にセットされます。
  5. 逆方向の場合、0.392から0.5 を引くと -0.108なので、結果は0にセットされます。
  6. これまでに説明した誤差や限界は、結果をcharとして格納する時点でのみ生じるということは注目すべき点です。その時点まで、値は内部的にはfloatとして計算されるので、精度は保たれています。内部的には、たとえ乗算の結果が0〜1の範囲を超える値になっても制限は起こらず、加算処理によって値を範囲内にもどすことができます。ここでは、0.392を3.0 倍(=1.176)してから、0.5を引いて、結果は0.676 になります。しかし、この値が charとして格納される際に、小さな誤差が生じます。0.676 は 0〜255 のスケールでは172.38 になりますが、小数部は切り捨てられ、172(すなわち0.675 )が格納されます。
  7. 変更を加えないためには、スケーリング係数は1 、バイアスは0 でなければなりません。

・jit.scalebiasについて、また8ビットcharデータがもたらす結果について十分な理解が得られるまで、他の値で試してみて下さい。終わったら、[explain_scalebias] ウィンドウを閉じて下さい。

画像のカラーレベル調整

jit.scalebias をカラー画像に対して使ってみましょう。チュートリアルパッチの左上隅には、おなじみの組み合わせがあります。jit.qt.movieオブジェクトとムービーを読み込むためのメッセージボックス、jit.qt.movieオブジェクトから jit_matrix メッセージを出力させるトリガとなる metro オブジェクトです。このパッチでは、jit.scalebias の持つ乗算と加算の機能を使ってマトリックスを加工します。


ピクチャまたはムービーを読み込みます

read chillis.jpgというメッセージボックスをクリックして、JPEG画像を読み込んで下さい。jit.qt.movie オブジェクトにビデオではなく静止画増を読み込んでいる点に注意して下さい。QuickTimeは、PICT、またはJPEG形式を含む、様々な広範囲にわたるメディア形式を取り扱うことができます。jit.qt.movie オブジェクトは静止画像を1フレームの長さのビデオのように取り扱います。

jit.qt.movie の出力は jit.scalebias へ送られて処理され、jit.pwindowで表示されます。(今の所、jit.matrix オブジェクトはまだ気にしないで下さい。この使い方に関しては、この章の後の方で説明します。)スケール と バイアス の値は jit.scalebias オブジェクトの scale および bias アトリビュートを変更することによって変えることができます。

toggle をクリックして、metro オブジェクトをスタートさせて下さい。scale $1メッセージボックスの上のナンバーボックスをドラッグして、scale アトリビュートの値を1.25まで大きくして下さい。


画像のブライトネス(明るさ)の増加。scale によって、大きな値はさらに増加します

これによって、画像の4つのプレーン全ての0でない値は係数1.25を掛けられます(25%の増加)。乗算を行うと、より大きな値は、より小さな値に比べて増加する量が大きいことに注意して下さい。例えば、元のマトリックスのあるセルの赤の値が200だとした場合、これは250(結果として50の増加)になりますが、同じセルの青の値が30だったとしたら、これは37(結果として7の増加)にしかなりません。

scale アトリビュートを20といったような非常に大きな値にして下さい。値が13以上になると、元のマトリックスは255 という最大値の方へ押しやられ(そして、非常に小さな値でさえ可視レベルまで押し上げられ)て、人工的な「露出過度」状態を作ります。

scaleアトリビュートを0と1の間まで小さくして下さい。予想できることですが、これは画像を暗くします。scale の値が0以下になると、すべての値は0にセットされます。

scale アトリビュートを1に戻して下さい。今度は bias アトリビュートを調整してみましょう。これはマトリックスのすべての値に一定の量を加算します。正の値は画像を明るくし、負の値は暗くします。


一定の量によって、すべての値のレベルを増加(減少)させます

各プレーンごとの調整

jit.scalebiasオブジェクトでは、各プレーンのレベルを個別に調整することができます。これには、ascaleabiasrscalerbias などのアトリビュートを使います。

・scale の値を1に、biasの値を0に戻して下さい。そして、適当なアトリビュートに新しい値を与えて各々のカラープレーンを個別に調整する実験を行ってみて下さい。


各カラープレーンのレベルを調整します

3つのカラープレーンすべてのスケーリングの調整を一度に行えるようなコントローラを使って、処理を多少「インタラクティブ」にしてみました。swatchオブジェクトをクリック、またはドラッグすると、オブジェクトはマウスが置かれた場所のRGB値を示す3つの要素からなるリストを送り出します。これらの値は0〜255のスケール上で表されているので、vexpr オブジェクトを使って、リストの値すべてを0〜1の範囲に変換します。そして、unpack によってリストを3つの float に分割し、その値を使って jit.scalebias オブジェクトの rscale gscalebscaleアトリビュートを変更します。


swatch からの値は jit.scalebias オブジェクトのアトリビュートとして使用されます

swatchオブジェクトをドラッグして、同時にRGBプレーンのスケールを行って下さい。(これは、0〜1の範囲のスケーリング係数を出力するので、実際にはすべてのレベルを減らすことになります。このため結果としての画像は通常いくぶん暗いものになります。)

・これらすべての操作は様々な画像で試してみることができます。colorswatch.pictやwheel.mov(あるいは何か他の画像)のような、別のカラフルな画像を読み込んでカラーレベル調整の実験を行って下さい。

マトリックスのプレーン再割り当て

前のチュートリアルでは、jit.unpack および jit.pack オブジェクトを用いてマトリックスのプレーンの再割り当てを行いました。同じことを行う別の方法があります。これには、 jit.matrix オブジェクトの planemap アトリビュートを使います。この例では、planemap アトリビュートを説明するために、jit.qt.movie オブジェクトから出力されるマトリックスを jit.matrix に通しています。


jit.matrixを通過する際に、マトリックスのプレーンの再割り当てを行うことができます

jit.matrix オブジェクトの planemap アトリビュートは、入力されるマトリックスのどのプレーンでも「マップ」(再割り当て)することができます。planemapという語の後に、マトリックスの持つプレーン数と同じ数だけの数値を続けます(この場合は4つです)。リストの各プレーンは出力するプレーンを意味し(最初のプレーンは出力のプレーン0を、2番目のプレーンは出力のプレーン1を意味しています。以下同様です。)、その値は、再割り当ての対象である入力されるプレーンを表しています。デフォルトでは、planemapの値は、0 1 2 3 のようになっているため、入力されるマトリックスの各プレーンは出力されるマトリックスの同じプレーンに割り当てられます。しかし、この割り当てを好きなように変えることができます。例えば、jit.matrix オブジェクトに planemap 0 3 2 1 というメッセージを送った場合、入力のプレーン3を出力のプレーン1に(値3がリストの出力プレーン1の場所にあるため)、入力のプレーン1を出力のプレーン3に割り当てます。実際には、画像の赤と青のカラープレーンを入れ替えることになります。

read whiee.mov というメッセージボックスをクリックして、 metro オブジェクトをスタートさせ、ムービーを見てください(もとのままの画像をjit.pwindowに表示させるために、 jit.scalebias オブジェクトの scale アトリビュートは1に、bias アトリビュートは0にセットして下さい。)。パッチの右下部分の、planemap 0 3 2 1 というメッセージボックスをクリックしてマトリックスの赤と青のプレーンを入れ替えて下さい。planemap 0 1 2 3 という message ボックスをクリックして通常のプレーン割り当てに戻して下さい。

出力するRGBの3つのプレーン全てに同じプレーンを適用すると、RGB3つのプレーンすべてが同じ値になるので、結果としてグレースケールの画像になります。

planemap 0 1 1 1 というメッセージボックスをクリックして、この効果を見て下さい。リストのRGB3つのプレーンの各々の場所が1になっているので、もとの画像の赤プレーンが、出力マトリックスのRGB 3つのプレーン全てに適用されます。

すべての異なったカラープレーン交換のしかたを循環させるために、collオブジェクトに様々なプレーン割り当てがすべて(前の章で行ったのと同じ方法で)書き込まれています。そして、これらの割り当てを jit.matrixオブジェクトに送信して、その planemap アトリビュートを変更します。

patcher rotatecolorplans オブジェクトをダブルクリックして、サブパッチの内容を見て下さい。ここでは、メインパッチの coll オブジェクトに格納されている異なったマッピングが順に行われるように、単に1から6までがカウントされています。(そして、オフにされた場合には数1を送り、デフォルトのプレーン割り当てにリセットします。)[rotatecolorplanes]ウィンドウを閉じて下さい。

patcher rotatecolorplanes オブジェクトの上にある toggle をクリックして下さい。すると、1秒に1回の速さで異なったプレーン割り当てが段階的に行われます。右インレットの上にあるナンバーボックスを小さい値(80位)に変えて下さい。素早いプレーンの再割り当てによって引き起こされるフリッカー(点滅)効果を見ることができます。

次のチュートリアルでは、jit.hue を使ったより巧妙な方法によって画像の色相をローテーションさせるやりかたについて、また、jit.brcosa オブジェクトを使った他のカラーレベル調整方法について説明します。

画像の読み込みとインポート

このチュートリアルパッチでは、3つの異なる種類の画像を jit.qt.movie オブジェクトに読み込みました。PICT、JPEGの静止画、そしてQuictTimeムービーです。ムービーを再生するために設計されたオブジェクトに静止画を読み込むことは奇妙に思われるかもしれません。しかし、実際にはQuickTimeは多くのタイプのメディアファイルを読み込むことができ、 jit.qt.movie オブジェクトはそれらすべてを読み込む手段を備えています。(AIFFオーディオファイルでさえ、jit.qt.movie に読み込んで、startstopメッセージによって聞いたり、time アトリビュートによって別の場所へジャンプしたりすることができます。もちろん、この場合には視覚的なマトリックス情報はありません。) 

静止画の場合、チュートリアル3で説明したように、 importmovie メッセージによって簡単に、直接 jit.matrix オブジェクトに読み込むことができます。この方法でQuickTimeムービーをインポートした場合には、ムービーの1フレームだけが jit.matrix に格納されます。

このパッチでは、全ての画像の読み込みに jit.qt.movie オブジェクトを使いました。その理由の第1は、読み込みたいものの1つがムービーそのもの(ムービーの1フレームではなく)であったこと、第2は、jit.matrixオブジェクトの planemap アトリビュートについて説明したかったためです。planemap アトリビュートは、実際に入力されるマトリックス(左インレットで受け取られる jit_matrixメッセージ)にのみ適応されます。importmovie で画像を jit.matrixに直接インポートした場合、planemap アトリビュートは何の効果も及ぼしません。

まとめ

jit.scalebiasオブジェクトは、乗法と加法を用いて、4つのプレーンを持つ char マトリックスのある特定のプレーン(あるいは同時に全てのプレーン)が持つすべての値を加工します。 scale アトリビュートは乗算を行われるマトリックスの全ての値に掛け合わせられる係数です。また bias アトリビュートは乗算が終わったあと、各々の値に加算される値です。scale および bias アトリビュートはマトリックスの4つのプレーンすべてに作用します。いちどに1つのプレーンにだけ作用させたい場合には、ascaleabiasrscalerbias、のような特定のプレーンに対応したアトリビュートを使用します。

これらのアトリビュートには float(小数による値)の値を与えなければなりません。乗算と加算を行うために、jit.scalebias はcharの値を0から1の間の小数として扱い、floatとの演算を行います。その後、計算の結果を char(0から255までの整数)に変換し直し、再び格納します。0から1の範囲を超えた計算結果は、char に変換し直される前に、1または0に制限されます。

jit.matrixオブジェクトの planemap アトリビュートを使用して、マトリックスのプレーンの再割り当てを行うことができます。planemap に対するアーギュメントは出力するプレーンを順に並べたリストで、その値は、再割り当てを行うために入力されるマトリックスのプレーンを表しています。したがって、例えば入力マトリックスのプレーン1を、出力されるマトリックスの4つ全てのプレーンに割り当てたい場合には、アトリビュートを planemap 1 1 1 1 と設定する必要があります。

jit.scalebias オブジェクトは4プレーンのchar(ARGBカラー)マトリックスのカラーレベルを調整するための強力なツールを提供します。このような働きをもつ別のツールに関しては、チュートリアルの次の章で説明します。