2012年6月9日土曜日

AfterEffectsのpremultiply、unpremultiplyについて

チヤマさんがtwitterでこんな事をおっしゃってました。


AEって、標準機能でUnmultできないの!?mjd!?。。。そ、そんなことないよね、、、

あー違った。合成チャンネルを指定してるからそこでUnmultされるのか。んーー。合成チャンネルってそもそも何だ?色指定できるけどこれは。。。?

という事で、僕に分かる範囲で説明してみます。また、僕はCG畑なのでCG目線での解説になります。AEに関しては内部の処理がとにかくBlackBoxになっているので「多分こうだろう・・・」 という憶測でしかありません。本当はどうなっているのかは不明なので、記事としてはあまり意味がありません・・・。きちんと確認したい方はサポートに問い合わせてみるのがいいんじゃないかと思います。また、僕はテクニカルの人間ではないので、例によって間違った事を書いているかもしれません。もし、間違っていたら是非、ご教授お願いします!

計算式が出てくるので、32bitFloatリニアの前提で話をします。それ以外の状態ではこのようにならないかもしれません。AEのバージョンはCS4です。

では、早速。チヤマさんは時々ネット用語を使われます。「mjd!?」とは「マジで!?」という意味になります。そして、チヤマさんが気にされている所は「正しい画像処理(カラコレ等)を行う場合はUnpremultしないと駄目なはずなのに、AEはいったいどうなっているんだろう?」という事を気にされたのではないかと思います。


【一般的な合成について】

AEだけ使っている人には分かり辛いと思うので、まず、正しい画像処理とは何?という所から・・・。「俺、知ってるよ!」って方はすっ飛ばして、下のほうの【AEの合成について】へ。

一般的に背景Bに何かの画像Aを標準で合成(ポン載せ、normal、over)する場合の計算式は以下の式なのだそうです。

O = Argb + Brgb * ( 1 - Aa)

僕はこれを画像処理の神の式と言っているのですが、それくらい大事な式だと思っています。 というのも、CGのレンダリングされる画像もこの式に基づいて用意されるはずなので・・・。いや、詳しくは知らないのですが・・・。少なくともこの式に背く行為をするとCG素材の輪郭に黒いエッジが出たり等、変なことがいっぱい起きてしまいます。

(Overについては Power is power:Nuke tutorial Overノード もしくはデジタル合成基礎講座という本を見るなどして下さい。)

そして、A+B*(1-a)する際のAはpremultiされた状態でなくてはなりません。

Power is power:Nuke tutorial color correction for premultiplied image

premultされた画像は
Argb = Argb * Aa
とする事で作成されます。自分のRGBに自分のαを掛け算(multiply)した画像です。
(大半のCGのレンダリング画像はデフォルトだとpremultされた画像が出力されますし、premultされた画像を扱うことが多いかと思います。)

premultの仕組み。multilplyは掛け算。

そして、その出来上がったAを O = A + B * (1-a) で重ねます。

premultされたAを A + B * (1 - a)で重ねる。

ここがとても重要なポイントです。
premultされた画像は Argb = Argb*Aa という計算で作られているので、premultされた画像をカラコレ等してむやみにrgbの値を変えてしまうと、premultした状態(A * a)が壊れてしまうので正しく標準で合成出来なくなってしまいます。(主にエッジの輪郭のアンチ部分などの半透明部分等)。
 CGのレンダリング画像にガンマをかける処理も同じで、CGのリニアで計算されたpremultiplyの画像に対しrgbにだけガンマをかけると、やはりpremultiplyの状態が壊れてしまうので合成は失敗します。では、アルファチャンネルにも同じガンマをかければよいかと言うと、それでは輪郭の太さが変わってしまう。なので、本来ガンマ(カラコレ)をかけるならば、unpremult→ガンマ→premultとする必要があります。(Nukeのリニア以外のpremultiply画像を読み込むときのpremultipledのチェックは、その用にしてガンマの処理をしている)
NukeのReadノードのlinear以外のpremultuplyの画像を読み込む設定
 CGWORLD.JP  Vol.3:アニマル・ロジック流コンポジット

premultiplyの画像に対してカラコレを行ってしまうとpremultiplyの状態が壊れてしまうので
正しく合成できない(図は輪郭部分に黒エッジが出てしまった)
では、premultされた画像に対してカラコレをしたい場合はどうしたらいいかというと、一度unpremultiplyの状態にしてカラコレした後、premult して合成します。(premultがArgb*Aa なので、unpremult はその逆算のArgb/Aa。AEで言うストレートの状態)
premultiplyされた画像を一度unpremultiplyしてカラコレ、その後再びpremultしてから合成すれば正しく合成される
premult & unpremultはCGソフトの結構色んな所に出てくるので一度しっかり理解しておきたい所ですね


【AEの合成について】


そして、AEです。以上の話を踏まえるとpremultされた画像を特に何もせずに普通にカラコレとかしてるけど、どう処理してるの?という疑問が出てきます。ネットでAEの標準の計算式を検索してみました。(Nukeなどはマニュアル等に計算式が出ているのですが、AEは見当たらなかったので・・・。)

それによると、AEの標準の描画モードの計算式は

O = (A * a) + B * (1 - a)

となっているようです。

O = A + B * (1 - a)

とちょっと様子が違います。Aの部分が(A * a)となっています。つまり、常にPremultしている?!


NukeのNodeで表現したAEの標準
どうやらAEは「Unpremultiplyの状態でデータを保持し、常にpremultして合成(表示)する。」という仕様となっている・・・という憶測。αチャンネルは透明として使うよ!みたいな。

確認してみます。
CGでpremultiplyされた状態の画像を出力
3dsmaxのScanlineでレンダリング
AEで読み込む
premultiplyされた画像なので「合成チャンネル」で読み込む。
恐らくこの時に内部的には画像データをunpremultiplyの状態で格納。
カラーマットは背景色を指定する所です。premultiplyされた画像なのに背景色?と違和感がある人も居るかもしれませんが、詳細は後ほど・・・。
問題なく合成される。ちなみに背景色は G:1.0
そして、αチャンネルを持っていると常にpremultして表示されてしまうようなので、「チャンネルシフト」というエフェクトを使い「アルファを取り込む→フルオン」つまりαチャンネルを1にしてAEがpremultしてもrgbの色が変わらないようにしてみました。常時 Argb * Aa をしてしまうので、Aa = 1 としてあげれば Argb*1でrgbの値が変わらないので、AEが内部的に持っているRGBの情報が見れるのでは?という感じ。

チャンネルシフトでアルファをフルオン
ありがたい事にunpremultiplyされた状態で表示されました。AEの人に分かりやすく説明すると、AEで「合成チャンネル」用の画像は内部的にはストレートにしてから処理をしている。という感じで通じますかね?という事は、内部的には常にunpremultiplyの状態なのでカラコレ程度の画像処理であれば、正しく処理してくれていると言ってよいと思います。

念のため数値を確認
NukeでUnpremultした画像のあるピクセルの数値
同じピクセルのAEの数値
 AEの方が少し違うのですが「32bit floatで計算している」と断言しているので、表示上四捨五入しているだけと信じたい。ついでなので、背景G = 1.0(緑) にティーポットのgainを2.0にして標準でNukeとAEで同じように合成してみました。
あるピクセルのNuke上の数値 【R】0.07788 【G】0.88922 【B】0.09814
同じピクセルのAEでの数値 【R】0.0779 【G】0.8892 【B】0.0981
 同じ結果になりました。どうやら表示上の誤差だけのようです。AEさんなかなかやるじゃないか。

そうすると、後は気になってくるのはブラーなどのαチャンネルにも同時に処理する必要があるフィルターの扱いです。ちょっと集中力も切れてきているので簡単な感じになってしまいますが・・・。Nukeでは、unpremult→カラコレ→premultした後に、Blur→overという順番で合成します。

Nukeでブラー
AEですが・・・
AEでブラー
AEの結果が興味深かったのですが、ちゃんとpremultした後にブラーの処理しているっぽいです。エフェクトの順番変えたら結果変わる?と思って一番上にブラー持ってきてみたのですが・・・。
ブラーとHDRコンパンダの順番変えた
カラーピッカーレベルで全く同じ数値になりました。つまりブラーの処理に関しては順番変えても結果が変わらない・・・。 内部的にちょっと特殊な処理していると考えられます・・・。


Nukeでブラー後にunpremult
AEのチャンネルシフト、アルファフルオン

ちょっとこれやって僕は混乱してしまいましたが、なんでか知らないけど同じような結果になりました・・・。umpremultiplyの状態でデータを格納していると思ったのですが、ちょっと違うのですかね?

ちなみにAEでunpremultiplyの画像を読み込むときはストレートで読み込むのですが、個人的にはunpremultの処理をせず、そのままAEで読み込むので「ストレート」って言葉を使っているのではないかと勝手に思ってます。

なので、AEでunpremultiplyの画像を「合成チャンネル」で読み込んでしまうと内部的にはおそらく
 unpremult→unpremult→premult→over となってしまうため、結果合成は失敗してしまいます。
エッジ部分が白くなってしまう。
Nukeで再現してみた。全く同じ結果(数値)になりました。

【AEの合成チャンネル - カラーマットについて】


ここからは余談です。AEの「合成チャンネル」はpremultされた画像を読み込むモードで、カラーマットは背景色と説明しましたが、正確にはちょっと違います。例えばこんなケースの時に使います。
CGでレンダリングした際に、背景色を黒以外でレンダリングした。ちなみに背景は B 1.0
この場合、この画像はpremultされた画像とは言えない状態です。
カラーマットを黒のまま読み込むと合成は失敗する。輪郭部分に青成分が残ってしまう
なので、背景色を指定するとAEは内部的に正しいpremultされた画像を作っているのだと思います。

CGでレンダリングした際の背景色を指定してあげると、正しく合成できる
AEの「合成チャンネル -カラーマット」はpremultiply+背景色までサポートした読み込みモードです。


【AEの合成チャンネルをNukeで再現】

先ほどの、背景が青い画像をNukeで合成してみます。
この場合のAはpremultされた画像ではないので合成は失敗する




細かい説明は省きますがAはpremultされた画像ではないので、Aの背景色がBに加算されてしまい正しく合成できません。では、Aをpremultしてからoverすればいいのでは?となりますが、それも駄目です。

輪郭部分に青いエッジが出てしまう
では、このCGから出力したAは何者か言うとCG内でA + B *(1-a) して出来上がった画像です。
CG内で合成して出力している。
なので、CGから出した背景が青い画像を合成するためには、一度premultiplyだった時のAに戻す必要があります。これ、意外と簡単でOverの逆算すればpremultiplyだった時のAになります。

O = A + B * (1 - a) なので、元のAを求めたい時は

A = O - B * (1- a)

これで、元のpremultiplyだった時のAになります。overの逆算の合成モードは多分ないので、MergeExpressionノード使って作ります。

Nukeで再現したAEの合成チャンネル - カラーマット
以上になります。

ということで、チヤマさんの疑問


Q.AEって、標準機能でUnmultできないの!?

A.意識してunpremultの状態にして画像処理するのは意外と大変かもしれません。でも、内部的にはunpremultiply→premultiplyとちゃんと行っているようなので、シンプルな画像処理の場合は正しく合成が行われているようです。ただし、計算の順番などはブラックボックスなので保障は全くありません・・・。

(僕、Unmultをunpremultとしていますが、多分チヤマさんの言っているUnmultとは違うと思います。断言できないのですが昔のアナログ編集の時に輪郭出てしまう問題の解決策の奴の気が・・・。そして、普段僕はこれに関してはKeylightやprimatteに頼り切っているので中身に関しては全く分かりません・・・。実写だとティーポットが人物になって、BGがブルーバックになっただけって考えればいいんですかね?実写素材系には本当に疎いです・・・。また、AEのKnoll Unmultというのもありますが、あれはただのルミナンスキーですかね?この辺モヤモヤしています。)

Q.合成チャンネルってそもそも何だ?色指定できるけどこれは。。。?

A.合成チャンネルは、背景単色のA+B*(1-a)された画像を読み込み正しく合成出来る処理をしてくれるモード。premultiplyの状態の画像を読み込む際は黒色にしておけばOK。

【追伸】
twitterで何人かにコメントを頂いたので追加しておきます。
---
KLFさん
面倒な素材が着たときにみつけたやつです。 after effectsのcolor matteをnukeで再現するノード
http://forums.cgsociety.org/archive/index.php/t-858225.html
---
spx808
AEのUnmultはRemove Color Mattingという名前だったと思います。フッテージの読み込み時にこれをかけてしまうのが合成チャンネルだと。
---













5 件のコメント:

  1. 詳細な検証ありがとうございます!!
    私が知りたい情報以上のことがまとめられていてとても参考になりました。

    それにしても、アルファ関係は厄介ですね、、、きちんと検証しないといろいろハマりそうです。

    返信削除
  2. チヤマさんが言っていたUnmultはspx808さんのおっしゃってる「Remove Color Matting(カラーマット削除)」な気がします。AEはαがどのように処理されているか分かりづらいですよね・・・。頑張って下さい!そして、何か分かったらコッソリ教えてください。

    返信削除
  3. 通りがかりの人2013年6月11日 18:37

    HPすごい参考になる事ばかりで勉教になります。
    あいてる時に全部完読してみようと思います。
    新しい記事にも期待してます。
    頑張ってください。

    返信削除
  4. ありがとうございます。
    検証したこと等をアップしているので、参考ぐらいのゆるい気持ちで見て頂けるとと思います。
    考え方が変わっていたり、違っていることもあると思いますので。

    新しい記事頑張ります。応援ありがとうございます。

    返信削除
  5. Nuke → AE の環境になり、フリンジが出ていなくても「自分は今、正しい処理をしているのか?」と不安になったりします。
    その都度ここを参考にさせて頂いております。
    検証内容が分かり易く、とても助かっています。

    返信削除