初めてのAEプラグイン。やさしくしてね。。【前編】
2011/7/11
Tag: AfterEffects,blur,diffraction,plugin,初めて,回折,画像処理
こんにちはー。開発室のひらく[@horonig]です。
去年12月に始まった【DF_talk】も既に半年が経ち、続々とおもろいエントリーが公開されていますが、皆様お楽しみ頂けてますでしょうか?
しかし、聡明な読者の中にはお気づきの方がいらっしゃると思いますが、未だメインソフトの中で言及されてないヤツが一つありますね。
そう!AfterEffectsです!!(あれ?MotionBuilderは?とかいう突っ込みはナシで。(∩゚д゚)アーアーきこえなーい)
AfterEffectsは会社によって呼び方が変わりますよね。
AE(えーいー)、アフエフェ、アフター、AF(エーエフ)、AFX。。
正直、最後から二つ目あたりからは18禁的な印象しか受けない僕は何か間違ってるのかもしれません。
そしてそんな僕はAE(えーいー)派です。ぽぽぽぽ~んのAC(えーしー)じゃないですよ。「えーいー」です。
DFの人たちは、AEもしくはアフターと呼ぶ人が多い気がします。なので今回のエントリーではAEという呼称で進めていきましょう。
DFでは現在、AEのインハウスツールがそれなりに揃ってきておりますが、その中でも僕が初めて作ったプラグインの話をさせて頂きます。
あれは、むかーしむかしの事じゃった。。。ぽわわわ~ん。。。えーしー♪(あ
僕は元々、mayaとAEを使ってCM系のデザイナー業務をしていたのですが、ちょっと変わった3D的な表現はmel(mayaのスクリプト言語)やmayaの既存機能でなんとかなると思っていました。ただ、どう頑張っても手が出ないのが『2D的なギミック』、つまりピクセル単位で何かをするエフェクトでした。って事は、画像処理が出来れば俺最強じゃね?という勘違い意識が僕の中で勃興し、意識し始めたのが僕の画像処理人生の始まりです。とは言え、前の会社ではほとんど画像処理プログラムを書いた事がなかったので、DFに入ってから本格的なR&Dの時間を頂き、初めてAEプラグインを作る事になりました。
1.プラグインのアイディア
社内で「どんなAEプラグインが欲しいか」というヒアリングをしてみたところ、多種多様なアイディアが出てきたのですが、その中でも僕が興味を持ったのは、某Mディレクターが提案してくれた≪光の回折プラグイン≫でした。
これは、キャラと背景を合成したときに、背景の明るい部分がキャラの前方に回り込む光のにじみ効果を作っちゃおうというエフェクトです。要は、合成をなじませるためのエフェクトですね。
色々と検討した結果、この≪回折プラグイン≫を作ることにしたのですが、これを作ろうと思ったポイントは以下の三つです
①間違いなくよく使う
エッジ部分のマスクを作ってそこだけ明るくしたり背景色に転がしたりという事は良くやる手法ですが、意外と手間が掛かるんですよね(エフェクトを三つ四つぶら下げてさらにプリコンして…とか)。なのでこれが一発で出来るだけでも工数削減に繋がるはずだという読みがありました。
②必ず役に立つ
コレを差し込むだけでコンポジットの馴染みが良くなるので、絵のクオリティアップが望めます。
③なんとかインプリ(※)できそう(コレ重要!)
アルゴリズムの検討をしてみた感じでは、僕のつたない画像処理知識の範囲でも何とかなりそうな気がしたんですよね。なのでこれはアリだなと(笑) このあと地獄を見ることになるとは思いもしませんでしたが。。
※インプリ: 実装すること
2.仕様の策定とアルゴリズムの検証
まずは仕様の策定に入ります。諸々検討した結果、以下の二つのモードを搭載する事にしました。
[其の1] コンプでよくやる、エッジ部分のマスクを作って背景素材を合成する方法 【edgeBlendモード】
blend用のマスクを、[アルファ抽出] – [反転] – [ブラー] – [元のマスクで切り取り] で作り、それを使って背景の色をのせるやり方です。
よくやる手法ですが、要は以下の様な流れになります。(クリックすると大きな画像で見れますよ!)
①: キャラ素材 | ②: マスクを抽出(チャンネルシフトを使用) |
③: 反転 | ④: ブラー |
⑤: 元のマスク②で④を切り取る |
※④では、『最大最小』を使って食い込み具合を調整したりもします
この⑤で出てきたマスク素材を使って、背景をぼかしたものを加算したりしてエッジをなじませます。すると以下のようになります。
(クリックすると大きな画像で見れるかも!)
A: 背景 | B: キャラ |
C: AにBをのせただけのもの | D: 更に⑤のマスクを使って馴染ませたver |
簡単な例ですので、『こんなんで合成したとか馴染ませたとか言ってんじゃねぇぞ(#゚Д゚)ゴルァ!!』 とか言わないで下さいね^^^
[其の2] 実際に背景の明るい部分から光が漏れるような、そこそこ本格的なマスクを作って合成する方法【flareモード】
[其の1]は良くある例なので簡単ですが、更に凝った別の手法も実装しました。
説明がメンドクサイので、兎にも角にもリザルトをどうぞ。(クリックすると大きな(ry)
A: 【flareモード】で作ったマスク | B: 【flareモード】での合成結果 |
【flareモード】と言ってもこうはならないので注意してネ!! |
この【flareモード】のアルゴリズムまで言及すると長くなるので、≪初めてのAEプラグイン。やさしくしてね。。【後編】≫でまた詳しく説明しようと思っています。
とまぁこのように、【edgeBlendモード】は簡単なエフェクトの組み合わせで再現できているので、アルゴリズム的な問題はさほどないと思われます。また、【flareモード】はある程度頭の中で理論武装した上で、まぁいけるかな、という感じを持ってから臨んでいます(上ではリザルト出しちゃってますけど)。という訳で、次のチャプターへ進みましょう。
3.SDKの調査&コーディング開始
ある程度の仕様とアルゴリズムが固まったところで、SDK周りの調査を開始したのですが、これがまた大変でした。何故かと言うと、AE_SDKの情報がWEBではほぼ皆無だったのです。。。(海外サイトなら一つ二つサンプルがありましたが) AEどんだけ人気ないんだと思いましたよ(笑) 途中、ちょっとやさぐれて酒飲んだりとかして(笑) ですがSDKに入ってるサンプルがいくつかあるので、それとSDK_Guideを睨みながらコーディングを開始しました。
そして、コーディングを始めて僕が一番衝撃を受けたのは、AEに元から入っているエフェクトはSDKには含まれず、一から自分でインプリしないといけないという事でした。つまり、「ブラー」や「最大最小」なんかのエフェクトが普通にSDKから使えるもんだと勝手に思い込んでいたのですが、そうではないんですよね。。。(今思えば当たり前の事なんですが、ブラーくらいは用意してくれてもバチあたらないと思うww)
なので、かつてインプリしたことのない「ブラー」エフェクトとかから始めたんですが、これがまたやっかいでした。
(※詳しい方は「OpenCV使えば?」と思われるかもしれませんが、この当時、OpenCVの存在なんて毛ほども知らなかったのです)
4.画像処理ェ..
ちょっとAEから話は逸れるのですが、PhotoShopのフィルタに「カスタム」というものがあるのをご存知でしょうか?いわゆる『畳み込み演算』が実現できるフィルタで、この数値次第で画像をボカシたり、シャープにしたり、エッジ検出を掛けたりできます。
例えば、以下の設定だと「ブラー」っぽい効果が得られます。
「ブラー」的な設定例 |
この数値の意味は、各ピクセル値を計算するときに、その周りのピクセル値を上の数値で乗算したものを合算し、最後に【スケール】の値で割り算する、という単純なものです。上の例で言うと、上下左右と斜め4つ、更に自分自身(中央)の9個の値を全て足し算(正確に言うと「1」を掛けて足し算)し、最後にスケール「9」で割ります。すると、周りのピクセル値と混ざっていく感じになるため、ブラーっぽい効果が出るわけです。
更にブラーを強くしたい場合は、以下のような設定で可能です。
強い「ブラー」的な設定例 (ブラー半径を”2″にした状態) |
つまり、より遠くのピクセルをサンプリングする事で、より強いブラーになるわけですね。
「エッジ抽出」的な設定例 |
この辺は色々といじると効果が変わって面白いので、機会があれば是非触ってみてください。
で、何が言いたかったかと言うと、上の「ブラー」的な例でも分かるとおり、より遠くのピクセルをサンプリングすればよりボケる、というのは僕の中では常識でした。そのため、『これと同じ事をAEで実装すれば「ブラー」エフェクトが作れるんでしょ?簡単じゃーん。へへーん。』と勝手に思ってたのですが、これが運のつきでした…。実際に同じようなアルゴリズムでインプリしてみたら、重過ぎてAEが戻ってこないという(笑) 半径(radius)が「1」とか「2」ならまだしも、「20」とか入れただけでAEが固まってしまいまうくらいの重さでした。きゃー。
そしてこのとき僕は悟ったのです。まだ死ぬ運命(さだめ)ではないと。。。じゃなくて、画像処理を甘くみ過ぎていたと。。。
つまり、画像処理ってピクセル数分だけ処理するのが大前提なので、その各ピクセルで他のピクセルをたくさん参照したり余計な計算を入れ込むとハンパなく重くなるんですよね。当時の小さい解像度「640*480」だとしても、それだけで処理の数(ピクセル数)は”307,200″にもなるんですよ!さ、30万。。。
5.google先生のご託宣
「えっと、じゃあどうやったらブラーってインプリできるの?教えて!googleせんせー(^q^)」的な感じでググッてようやく見つけた答えは。。。
①横と縦で二回処理する事で、二次元的に処理したのと同じような結果が得られる(一次元的な処理×2で十分な結果が得られる)
②ピクセルを順に処理する際に、前のピクセルで使った情報を再利用する事で処理が軽くなる
という二点でした。どちらも、処理速度の向上という意味では欠かせない要素です。その当時は思いもしませんでしたが。
①は具体的にどういう事かと言うと、『一度横方向にブラーを掛け、その後縦方向にブラーを掛ければそれっぽくなる』という事です。
(縦横の順番はどちらが先でも問題ありません)
一度横方向にブラーを掛けて… | それを今度は縦方向にブラーを掛ければ、 全体的にブラーが掛かったような結果を得られます |
こうする事で、二次元なピクセルサンプリングをしなくて済むようになるため、劇的に処理が速くなります。(ボックスブラーでブラー半径が「5」だとすると、二次元的なサンプリングでは11×11で121箇所をサンプリングする必要があるが、一次元ならば11箇所のサンプリングだけで済む)
一方、②はどういう事かというと、以下の様な配列のピクセル値に簡単な「ボックスブラー」を半径”3″の設定で掛ける場合で解説してみます。ブラー後のピクセル値を決定する処理の順番はa→hとし、ここではピクセルdとピクセルeの求め方のみを説明します。
a | b | c | d | e | f | g | h |
100 | 10 | 0 | 55 | 20 | 150 | 255 | 10 |
ピクセルdの値を決める場合、半径は3″なので、以下の青い部分のピクセル値と自分自身の値をまずは合算します。
a | b | c | d | e | f | g | h |
100 | 30 | 0 | 45 | 20 | 150 | 255 | 10 |
つまり、(a+b+c+d+e+f+g) = 600 となり、これを7で割った平均を取ると、
600/7 = 85.714 = 86(四捨五入)となり、これが答え(ブラー後のdの値)になります。
次に、ピクセルeの値を求める場合は、上と同様に以下の様な形になるので、
a | b | c | d | e | f | g | h |
100 | 30 | 0 | 45 | 20 | 150 | 255 | 10 |
(b+c+d+e+f+g+h) / 7、つまり 510 / 7 = 73(四捨五入済み)が答え(ブラー後のeの値)になります。
これを全てのピクセルで順次行って行くわけですが、実はここに巧妙なトリックを取り入れることで、計算が劇的に速くなります。
それが、前回の情報の再利用です。
dにしろeにしろ、値を計算するためには「6回の足し算、1回の割り算」が行われますよね。
ところが、前の情報を再利用する事で「1回の足し算、1回の引き算、1回の割り算」で済むのです!
やり方はこうです。
dの値を計算するときに、a+b+c+d+e+f+gの値を$sumという変数で取っておきます。
そして、eの計算をする際には($sum+h-a)が実はeで必要な$sumとなるのです!
何故かというと、eの計算をする際にはaが必要なくなるので$sumからaを引きます。
そして今度はhが必要になるので$sumにhを足す事で必要な$sumが出来上がるわけです。
式で書くと、a+b+c+d+e+f+g + h – a = b+c+d+e+f+g+h という事です。
このやり方は、半径が増えれば増えるほど効果が出ます。どれだけ半径が大きくても前の情報を再利用する事で、基本的に「1回の足し算、1回の引き算、1回の割り算」で済むからです。逆にこれをしないで半径が100だったりすると、「200回(!)の足し算、1回の割り算」という事になり、計算量ががっつり上がります。(実際には、200回の演算もさることながら、201個のピクセルをサンプリングする事自体がかなりのボトルネックとなります)
このやり方を知ったときは、目から鱗でしたよ。コロンブスの卵でしたよ。馬の耳に念(ry
今となっちゃ当たり前で、こういうテクニックを使わないと画像処理プログラムなんてアホらしくて書けないくらいには成長しました。
また実際には、重み付けナシ(正確に言うと全ての重みが「1」)のボックスブラーでは品質が落ちるので、重み付けアリのアルゴリズムでブラーをインプリしましたが、同様の考え方で高速化できます。しかしながら、そこまで言及するとややこいので、ここでは割愛させて頂きます。
と言うわけで、【edgeBlendモード】は無事インプリできたのでした。
他にも「最大最小」などもインプリしつつ、諸々組み合わせてエフェクトを実現しています。
6.シメ
という訳で、今回の≪画像処理入門【前編】 –そして僕は羽ばたいた–≫はいかがだったでしょうか?
内容としてはそんなに難しく無いと思うのですが、画像処理に慣れてないと意外と理解しづらいかもしれませんね。
でも画像処理は面白いですよ。何と言ってもピクセル単位で絵をいじれるのは快感です(・∀・)
今はPixelBenderなんて便利なものもありますし、openCVもありますし、気軽に画像処理プログラムを書ける時代になってますよね。
なので皆さんも機会があれば是非、画像処理プログラムを書いてみてください。
≪画像処理入門【後編】 –そいや【flareモード】はどうなった?–≫ は、そのうちポストします。忘れたらごめんなさい。
それではまた!!アディダス!!
いつも拝見させて頂いております。
大変有益な記事を有難うございます
重み付けはガウシアンを使われているんでしょうか?
機会があれば是非その部分についてもおうかがいしたいです!
Posted at 2011.07.29 22:08 by saratani
こんにちはー(・∀・)
いつも[DF_talk]を読んで頂きまして、ありがとうございます!
ご質問の件ですが、「ガウシアン」ではなく、「一次関数的な重み付け」を使用しています。
こういう重み付けをなんと呼ぶのか良く分からないのですが、要は、一番遠い(半径距離の)点でのサンプリングの重みを「0.0」、一番近い自分自身のサンプリングの重みを「1.0」にして、その間はリニア補間という事です。
本当はガウスブラーが品質としては一番良いと思うのですが、下記の理由により、ガウスブラーをインプリすることは見送りました。
①「一次関数的な重み付け」でのインプリで、品質的には十分だった
②AEのガウスブラーも昔は重かった記憶があるため、インプリしても処理スピードはたかが知れてると思った(記事中のような高速化が出来ない気がした) 。 ※最近のAEだとあまり重くないみたいですけど。。何か変わったのかしら…(汗)
なので、ガウシアンの場合にどうインプリすればいいかは、僕の頭にはないんですよね。。すみません。
「一次関数的な重み付け」であれば、ちょっと計算してみると比較的簡単な事が分かると思いますよー。
こんなんで回答になってますか?
今後とも宜しくお願いしますー 🙂
Posted at 2011.08.1 13:58 by hiraku
ご回答有難うございます!
なるほどリニアなんですね
あまりそのような処理は見かけなかったので試したこともなかったです 🙁
早速試してみようと思います!!
>AEのガウスブラーも昔は重かった記憶があるため
確かにexpが計算に入ってくるようなので重い印象がありますが
最初に作るテーブル部分が少々重い計算 という程度なら
最近のPCではあまり問題にならないのかもしれませんね。。
あとパスカルの三角形を応用する方法もあるようですし・・
(ただ今google先生で勉強中ですw)
Posted at 2011.08.8 11:32 by saratani
こんにちはー。
そうですね。確かにテーブル作る部分では多少工夫したほうが良いでしょうね。
ただ僕が一番問題になりそうだなぁと思ったのは、5-②で言及した、『ピクセルを順に処理する際に、前のピクセルで使った情報を再利用する事で処理が軽くなる』という部分なんです。ちょっと考えただけだと、前の情報をうまく利用してサンプリング回数を減らす、という事が簡単には出来ない気がしたんですよね。。。この辺のことでもし良いアルゴリズムを知っている方がいれば、むしろ聞いてみたいです!! >皆様
Posted at 2011.08.8 16:11 by hiraku
度々ですみません。
なるほど確かに5-②が一番ネックですね。ガウシアンに関しては
そのような処理は初めから諦めてました。。
ちなみにwebで探すとDFT(FFT)を使う方法もあるようですが
まだまだ僕の頭ではついていけないですw
Posted at 2011.08.8 22:05 by saratani
ちょっと難しい話になるかもしれませんが、各ピクセルを単純に処理するだけの画像処理を想定して計算量(オーダー)を考えると、O(n^2)と表せると思うんです。縦横(XY)のピクセル数があるので(この辺は考え方次第ではありますが)
で、ガウスブラーにおいて5-②がうまく出来ないと仮定すると、計算量が一気にO(n^3)に跳ね上がります。これはかなり大きいかなと。
ですが、僕の紹介したボックスブラーやリニア補間を使ったブラーであれば、単純な画像処理と同じO(n^2)で済むため、高速です。
FFTも速いは速いのですが、確か計算量がO(n logn)だったと思うので、画像処理(ブラー)における計算量としてはO(n^2 logn)という事になり、僕が紹介した方法に比べると遅くなります。ただ、やり方次第で綺麗なピンボケを作ったりも出来るので、どちらを取るか、という感じです。(FFTは一ライン毎に処理する感じになるので、O(n^3 logn)ではなくO(n^2 logn)になります)
兎にも角にも、目的によって最適な手段を選ぶ事が重要だという事ですかね。
ではでは~(^ω^)
Posted at 2011.08.9 12:58 by hiraku
なるほど
O(n^2)とO(n^3)では大きな違いですね。
FFTのO(n^2 logn)はO(n^3)に比べればまだ軽いので必要に応じて
選べるとベストなのかもしれませんね..
色々と勉強になりました。有難うございます!!
Posted at 2011.08.11 21:36 by saratani
[…] さて、前回ご紹介した≪画像処理入門【前編】 –そして僕は羽ばたいた–≫ですが、【前編】と書いてしまったからには【後編】を書かねばなりません。あー余計なことしたなー。なんで後編とか言っちゃったんだろうなー。こっそり編集してなかった事にしちゃおうかなー、、、なんて事を言ってる時間が勿体ないので、【後編】いきます。 […]
Posted at 2012.03.26 15:02 by デジタル・フロンティア-Digital Frontier | DF TALK | 初めてのAEプラグイン。やさしくしてね。。【後編】