Continue(s)

Twitter:@dn0t_ GitHub:@ogrew

【TouchDesigner】俺はグレイスケールがわからない。

f:id:taiga006:20191117191204j:plain

どうも、0kawaraです。

この記事はTouchDesignerのAdvent Calender 2019の12/23分の記事となります。

昨日は@satoruhigaさんの「TouchDesignerのパフォーマンス測定」でした。Probeはよく使っていましたが、最初のGeometry COMPでtransformしたほうがただtransform CHOPを使用するよりパフォーマンスが良いというのは知りませんでした。参考になります。

さて、去年のTouchDesignerのアドレカでは私はこの記事を書きました。あれからもう1年なんですね。

さて、今年のアドレカは小ネタです。というのも12月の暇な時間はほとんど先週参加させていただいたVJAM Vol.2の準備に費やしてしまったからです。ごめんなさい…。

言い訳が済んだところで早速内容に入っていきたいと思います。

今回はグレイスケールの話を少しさせていただこうと思います。

GLSLでグレイスケールさせるのには

(color.r + color.g + color.b) / 3.0

した値を使えばとりあえず良いというのは御存知の通りかと思います。

そして、ただこれを計算しても良いけれど、少し賢い書き方として

dot(color.rgb, vec3(1.0/ 3.0))

と書く方法があるのを先日のGLSLスクールで師匠doxas氏に教わりました。

さっそく書いて見るわけです。

// simple gray scale

out vec4 fragColor;
void main()
{
    vec4 color = texture(sTD2DInputs[0], vUV.st);
    float gray = dot(color.rgb, vec3(1.0/ 3.0));
    color = vec4(vec3(gray), 1.0);
    fragColor = TDOutputSwizzle(color);
}

f:id:taiga006:20191117203809j:plain

よしよし、「グレイスケール完全に理解した…2020年もみなさま、よろしくね」と。

…そういえばTouchDesignerにはmonochromeTOPという便利なものがあるのでそれと差分を確認して終わりましょう。

そして「あれれ?」となったわけです。 うっすらと差分があることに! Levelオペレータを使って差分をより見やすくしたものを載せます。

f:id:taiga006:20191117203540j:plain

(下が先程グレイスケール化したもの。上がmonochromeTOPとの差分を見やすくしたもの。)

おうおうおう。

そういえばGLSLスクールのときにdoxas先生が「グレイスケールは沼」みたいなことを言っていたなと思い出しました。

そのとき紹介していたのがこちらの記事なのですがちょっと無知には長くて難しすぎるので一旦別のサイトを転々としてみました。(え。)

そして、まず「NTSC加重平均法」というものに出会います。

なにやら人間の目が感じるRGBのバランスを考慮して荷重を加えて変換する方法がいくつかるようです。

そ、そんなのが…。

ということで実装してみます。(といっても補正定数で決まっているので置き換えるだけですが…。)

// NTSC(BT.601)

out vec4 fragColor;
void main()
{
    vec3 colormatrix = vec3(0.298912, 0.586611, 0.114478);

    vec4 color = texture(sTD2DInputs[0], vUV.st);
    float gray = dot(color.rgb, colormatrix);
    color = vec4(vec3(gray), 1.0);
    fragColor = TDOutputSwizzle(color);
}

先程同様monochromeオペレータとの結果を比較してみると、今度はほとんど差分がありません。でも、完全になくなったわけでもなさそうです。小数点の扱いによる誤差が考えられます。

f:id:taiga006:20191117203337j:plain

他にも、HDTV規格用の係数を利用するケースも有るようです。 これは先程より計算がわかりにくいですが、また別の補正値を導入して計算します。

// HDTV(BT.709)

out vec4 fragColor;
void main()
{
    vec3 colormatrix = vec3(0.222015, 0.706655, 0.071330);
    vec4 color = texture(sTD2DInputs[0], vUV.st);

    float p = 2.4;
    float r = pow(color.r, p) * colormatrix.r;
    float g = pow(color.g, p) * colormatrix.g;
    float b = pow(color.b, p) * colormatrix.b;

    float gray = pow(r + g + b, 1/p);
    color = vec4(vec3(gray), 1.0);
    fragColor = TDOutputSwizzle(color);
}

f:id:taiga006:20191117203412j:plain

PhotoShopのグレースケール化にはこれが使われているそうです。 p = 2.4の結果を載せています。この補正値をどう置くかでだいぶ結果が変わってきます。

(ちなみにここまで出てきたBTというのはこれらの色域を使ったテレビ放送用の規格のことを指すようです。)

また、上記2つの方法で用いた係数からわかるように心理的に6,7割がRGBのGに左右されるのであればGだけで計算するという大胆な方法もあります。

// only G channel

out vec4 fragColor;
void main()
{
    vec4 color = texture(sTD2DInputs[0], vUV.st);

    color = vec4(vec3(color.g), 1.0);
    fragColor = TDOutputSwizzle(color);
}

f:id:taiga006:20191117203625j:plain

だいぶ大胆ですが、今回サンプルとして使用した画像がクリスマスツリーだったというのもあって、ほとんど違和感のないグレイスケールが手に入りました。(monochromeTOPとの差分はこれまでで一番大きいことがわかります。)

(MEMO:後もう一つ実験してみたいことができたので、ここに追記する。)

ここまでの結果を一覧にしてみます。

f:id:taiga006:20191117203719j:plain

※念の為ですが、monochromeTOPとの差分の部分は見やすくするためにLevelTOPでコントラストを上げたりして調整しています。手元の環境で試していただければわかりますが、実際目に見える差分はもっと小さいです。あしからず。

最後に、NTSCを使ってグレースケール化したものをセピア色に変えてみましょう。 こちらも簡単です。

// sepia

out vec4 fragColor;

void main()
{
    vec4 color = texture(sTD2DInputs[0], vUV.st);
    vec3 ntsc = vec3(0.298912, 0.586611, 0.114478);
    float v = color.r * ntsc.r + color.g * ntsc.g + color.b * ntsc.b;

    color.r = v * 1.07;
    color.g = v * .74;
    color.b = v * .43; 

    fragColor = TDOutputSwizzle(color);
}

f:id:taiga006:20191117195233j:plain

以上です。

明日は@hideki_eguchiさんの「TOP1つで簡単に作れるクレイジーなGlitchについて書く予定です。」です。え~~~、そんな魔法があるの~。明日も目が離せない~~。

参考文献

k75thunderbird.hatenablog.com

wgld.org

ofo.jp

qiita.com