Morikatron Engineer Blog

モリカトロン開発者ブログ

AnImator#2 ― 3Dをロトスコープする簡易手法

こんにちは、モリカトロンのAIエンジニア兼オタクの銭です。

前回の記事 でアニメ作画におけるスムーズさをAI寄りの視点で考察しましたが、少し抽象的でピンと来ないかもしれません。なので今回はその中の一番最初の仮設ーー動きの情報量が保てばスムーズ--を簡単なアルゴリズムで検証していきたいと思います。それにかねて、具体的な応用として、ロトスコープのサポート・ツールを作ってみました。

ロトスコープとは

モデルの動きをカメラで撮影し、それをトレースしてアニメーションにする手法。*1

ロトスコープ(略して「ロト」)は「トレース」で定義されてましたが、実際は結構曖昧に使われているようです。

一方、元々アニメーターが複雑なモーションを描く際にはほとんど参考が必要で、そこで画力が高ければ「トレース」しなくてかなり正確に再現することは可能です。もう一方、単純な「トレース」じゃ問題が多いので、ロトって言っても実は「トレース」じゃない場合が多いかもしれません。この二つの手法が近づいてきて、ロトの境界が曖昧になっていると、筆者は認識しています。

なので精確に分類するのは避けて、ロトを「動画を高度に参考する」といった汎化した意味合いで使いたいと思います。

では、例を見てみましょう。

トレース

f:id:morika-sen:20200504213120g:plain
作品:「惡の華」 *2

実写をほぼそのままトレースしたようです。「違和感がすごい」という指摘が多いですが、ある意味でテーマに合う演出効果もあると、個人的に感じています。

他にも「花とアリス殺人事件」や今年の「音楽」などが挙げられます。

トレースによる違和感について、いくつかの要素が考えられます:

  • トレースなので当然造形が実写的;
  • モーションも実写的なうえ、重要な動きも無意味な動きもまとめてコピーする。この点は多くの日本アニメが属する「リミテッド・アニメーション」ーーつまり動きを時間と空間において、必要な部分だけを選択して描くーーといった理念に相反するでしょう;
  • 通常なアニメ作画は、原画であろうと中割であろうと、前後との相対位置を意識しながら描くが、トレースだと一枚一枚が動きの絶対位置にあわせることになる → 線のブレが生じます。

参考レベル

トレースじゃなく高度な参考レベルのロトは、たくさんの作品のダンスシーンや演奏シーンなどに部分的に使われていました。ここでは近年話題になった二つの例を挙げます。

f:id:morika-sen:20200504213144g:plain:w320f:id:morika-sen:20200504213135g:plain:w320
作品:「かぐや様は告らせたい」 原画:中山直哉 *3
作品:「星合の空」 原画:江畑諒真 *4

当時、「かぐや様」のこのシーンはロトか否かの熱い議論を起こしていました。ロトだと思う人の理由としては、「人間が想像で描けるものじゃない」;反対の方の理由は、「ロトによくある破綻は見えない」。定義の問題はさておいて、とにかく参考動画を基に、「アニメっぽい」ものを仕上げることを上手に出来たのは確かであります。

トレースとの相違点としては:

  • 見た目はキャラデザイン通り
  • 余計な動きはない
  • 線などが安定

コマ送りで見ると、均一にコマ打ちしてるではなく、動きの状態に合わせて枚数を使う工夫が見られます。更に「かぐや様 線撮」をググって(限定公開の為)見れば分かると思いますが、ちゃんと原画ー中割のフローに取り込んでいます。

続いて「星合の空」は完全に「アニメっぽい」ものになっています。その中、二つ大きなポイントが見られます:

  • キーポーズとキーポーズの間に中割がない(いわば「中抜き」)という作画的な特徴
  • キャラがジャンプしてゆっくり落下するーータイミングを随意に弄る作画ならではの特長

(これロトじゃないと批判されても、反論するつもりはありませんが。。)

要点

前例に基づいて、参考動画をアニメっぽく「ロト」するにあたる要点をまとめると、

  • キャラがデザイン通り
  • 余計な動きを排除・必要な動きを選出
  • タイミングの調整
  • 通常なアニメ作画フローに取り込む


課題と準備

課題

シンプルなアルゴリズムでロトをサポートすることです。

前節で解析した「ロト」の要点の中で、キャラデザインをなんとかするのは難しいので、動きの選出とタイミングの調整に注目します。それで、アルゴリズムのサポートを取り入れた場合のパイプラインを考えてみました。

  1. 参考物の前処理、情報をエンコーディング
  2. キーフレーム抽出
  3. タイミング調整
  4. アニメ作画フローに取り込みやすいための後処理

今回は直接情報を読み取れる3Dアニメーションのモーションデータを参考物にします。

アニメのタイムシートの形 *5 でステップ2と3を表すと、下図のようになります。

f:id:morika-sen:20200512194537p:plain:w340
タイムシートで表すキーフレーム抽出とタイミング調整

表記しやすい為、この三つのタイムシートを「入力タイムシート」、「キータイムシート」と「出力タイムシート」を呼びます。

3Dモーションデータの用意

Adobe mixamo が無料配布した3Dモーションを使わせていただきました。

前処理

3DCGソフトウェアは Blender とそれの Python API 利用させていただいています。

最終的に2Dアニメになったら、動きは2Dになるので(例えば奥行きの移動は見えづらい)、 関節点の3D空間座標を直接使うのではなく、カメラ画面上の2D座標に変換して使います。

前処理の流れは下図のようになっています。

f:id:morika-sen:20200506195259p:plain
Blenderでランダムのアングルで、関節点のカメラ画面上の座標を取る;
スケールを正規化し、ファイルに保存する。


キーフレーム抽出

情報量定義

前回の記事では、最初に「予測できないほど情報量が存在する」みたいなこと言いましたが、それを具体的に詰めます。

f:id:morika-sen:20200506195258p:plain:w320
情報量の損失

上図の中で、ボールが青い矢印が示したように動く5つのフレームが表示されてあります。 その中の3つのキーフレームを選出します。 すると、キーフレームだけの動きはどう見えるのでしょうか?

勿論精確に答えるはずがないので、とりあえず線形的な動きが脳内で補間される(オレンジ色の矢印)と、仮定します。

そうすると、元の動きとの誤差が生じて、緑の矢印で示されています。

元の動きの情報量を0に定義すると、間引いた動きの情報量はマイナスの情報量損失で定義できます:

情報量 = - 誤差関数 ( 線形的補間 ( キータイムシート ) , 入力タイムシート )

キータイムシート = 抽出 ( 入力タイムシート | 密度パラメータ )

誤差関数定義

位置ベース

上図を見ると、一番直感的に浮かんでくる定義は多分、元位置とキーフレームで補間された位置との偏差ベクトルのノルム(例えば長さ)の平均(あるいは平均二乗など)ですね。

キーフレームによる軌跡が正しく元の軌跡を再現できるか、という意味合いが含まれています。

速度ベース

しかし位置ベースの定義だと、下図の左のパターンの誤差は右の方より大きいですが、 主観的には、右の方がより「動き」の変化を逃してしまったように考えられます。

f:id:morika-sen:20200512194933p:plain

ここで速度を考えてみます。

f:id:morika-sen:20200520161119p:plain

補間された軌跡の速度は一律にオレンジの矢印の四分の一になるとして、元軌跡中央のポイントの速度との差は、右の場合が高くなります。

どっち使う?

まず元軌跡の位置、速度、加速度を全てなるべく再現したいのは当然であり、この三つの要素の誤差を重み付けで使うのはジェネラルだと思いますが、実際その必要がないかもしれません。ということを説明するために、単一の要素の誤差をそれぞれ考えます。

  1. 位置ベースの問題は説明済み
  2. 加速度ベースだと、ゆっくり円周を回るみたいな軌跡はスルーされる
  3. 残された疑問は、速度ベースで位置誤差を抑えれるかです

代数で解析するのがしんどいので(ヒントとしては、線形的補間と関わっている)、統計的に結論を示します。

ランダムでキータイムシートを3000個サンプルして、速度と位置の平均二乗誤差の関連性が表しています。その中速度誤差がもっとも低い100個のサンプルを赤くしています。

f:id:morika-sen:20200520161232p:plain:w400
速度の平均二乗誤差 - 位置の平均二乗誤差

※この図はあるモーションとあるキーフレーム数とMSEの結果なんですが、他のセッティングで試しても似たような図が出てきます。

明らかに、速度誤差を減らすことで、位置誤差も抑えれます(線形的補間という前提に要注意)。というわけでここからは速度ベースの誤差を用います。

問題

情報量定義を基に、キーフレーム抽出問題は組合せ最適化問題になります。

キータイムシート* = 抽出* ( 入力タイムシート ) = MAX { 情報量 | キータイムシート }

キーフレーム抽出手法

組合せ最適化を正確に解くにあたっては、様々なアルゴリズムがありますが、いずれにせよ複雑性はO(n)以上でしょう。 勿論近似として、スライディングで局所的に計算していく策を取れば、O(kn)になります(kは「局所」のスケールによる定数)。

が、それは誰でも知っているので、ここでの解説は省きます。代わりに、作画への理解による直感でアルゴリズムを作ってみましょう。

久貝典史の作画

前回でも久貝さんの特徴的な「乱れ打ち」を引用しましたが、ここでは一番分かりやすい例を挙げます。

f:id:morika-sen:20200513180651g:plain
作品:「スペース☆ダンディ」 原画:久貝典史 *6

何となくわかると思いますが、宇宙船の位置・速度に合わせてコマ数が4から9まであがってそしてまた下がっていきます。

久貝さんの別の作画にも見られますが、この状態の変化量によってコマ数を調整する手法は、「原画」そのものに通じているかと、個人的に思います。

加速度累積・閾値手法

一定の「変化量」でコマ打ちするという考えに基づき、前述の加速度誤差を累積して閾値でキーフレームを選定する手法をデザインしました。

まずこの「変化量」は位置の変化量じゃなく、速度のです。(情報量と誤差関数の定義に参照すれば、位置が固定速度で変化しても情報量がないことが分かります。)

そして単純に筆者の直観で、以下のアルゴリズムの主幹がでてきます:

  1. 全フレーム・全関節点の加速度のノルムを計算
  2. 最初のフレーム 1 をキーフレームにする、i=2
  3. 累積変化量 += フレームi加速度のノルム
  4. 累積変化量 > 閾値 なら、フレーム j をキーフレームとする、累積変化量=0
  5. i = i+1、3に戻る

閾値は全体あるいは局所のnフレームの加速度のノルムの総和Aと欲しい密度(kコマ打ち)で決めます。

閾値 = A * k / n

明らかに、この手法の複雑性はO(n)です。

後付けの分析

シンプルです。

|Δv| = |Σa| ≤ Σ|a|

つまり、累積和は速度変化のノルムの上限となっています。累積和が閾値を超える際にキーフレームを切ることで、前キーフレームと現キーフレームの間の全てのフレームの速度の前キーフレームに対する変化量が閾値以下であることを保証します。補間された軌跡との差もある値以下に制限されます。

そして閾値の取り方と加速度のノルムが常に正数であるので、密度が大体指定したように実現されます。

結果

三つの手法を試してみました。

  • 均一に間引く手法(UNI)
  • 加速度累積・閾値手法(ACC)
  • 焼きなまし法(SA): イニシャル状態はUNIと同じ、最大ステップ数は10000

まずは主観的に結果を見てみましょう

f:id:morika-sen:20200520161547g:plain:w220f:id:morika-sen:20200520161559g:plain:w220f:id:morika-sen:20200520161608g:plain:w220
Punch、25枚から5枚抽出 (左から UNI、ACC、SA)

f:id:morika-sen:20200520162141g:plain:w220f:id:morika-sen:20200520162202g:plain:w220f:id:morika-sen:20200520162210g:plain:w220
Dance、72枚から13枚抽出 (左から UNI、ACC、SA)

f:id:morika-sen:20200520162347g:plain:w220f:id:morika-sen:20200520162429g:plain:w220f:id:morika-sen:20200520162439g:plain:w220
Grab、71枚から8枚抽出 (左から UNI、ACC、SA)

まずUNIと他との違いは明らかでしょう。Punchでは、一番重要な手を完全に伸ばしたポーズを逃してしまいました。DanceとGrabでも、キーじゃないフレームを選出したように見られますね。そのほか、均一なので、Danceの場合リズム感が出てこない問題もあります(勿論これは全原画作画としての場合)。

ACCとSAを見比べると、そんなに差が無いように見えますが、所々細かいズレがあるような感じです。

※ここでは適した抽出密度の結果を示してます。人力で数回の試行錯誤が必要です。

数学的パフォーマンス

上に貼ったDanceのSAの収束過程はどういう感じかを見せます。

# key indexs by ACC, MSE
 [0, 7, 15, 25, 30, 35, 47, 52, 55, 59, 66, 70, 71] 0.03902
# steps, key indexs by SA, MSE
0    [0, 5, 12, 19, 24, 30, 35, 42, 48, 53, 60, 66, 71] 0.05246
12   [0, 5, 11, 19, 23, 30, 33, 41, 51, 53, 59, 66, 71] 0.05192
13   [0, 6, 12, 18, 24, 29, 34, 41, 52, 53, 59, 65, 71] 0.05103
708  [0, 3, 5, 14, 21, 29, 34, 47, 50, 54, 59, 66, 71] 0.05078
3439 [0, 1, 7, 11, 16, 26, 31, 35, 50, 53, 59, 66, 71] 0.04979
5495 [0, 9, 13, 19, 20, 27, 35, 44, 51, 54, 58, 66, 71] 0.04916
5635 [0, 10, 15, 23, 26, 30, 34, 45, 52, 58, 65, 70, 71] 0.04875
5641 [0, 9, 15, 22, 26, 30, 35, 45, 53, 58, 65, 70, 71] 0.04707
5644 [0, 9, 16, 21, 26, 29, 34, 46, 53, 58, 66, 70, 71] 0.04448
5901 [0, 10, 15, 24, 27, 29, 34, 47, 52, 54, 58, 65, 71] 0.04373
5910 [0, 11, 14, 25, 27, 30, 35, 48, 52, 54, 58, 66, 71] 0.04340
5917 [0, 9, 14, 23, 27, 29, 34, 48, 51, 55, 58, 66, 71] 0.04321
5941 [0, 9, 14, 19, 27, 30, 34, 46, 52, 54, 58, 65, 71] 0.04214
5951 [0, 8, 14, 20, 27, 29, 35, 47, 52, 54, 59, 66, 71] 0.04144
5955 [0, 8, 15, 21, 27, 29, 35, 47, 52, 54, 59, 66, 71] 0.04102
6568 [0, 9, 17, 24, 27, 30, 34, 47, 52, 54, 58, 66, 71] 0.04035
9101 [0, 8, 15, 25, 30, 34, 36, 48, 52, 54, 58, 66, 71] 0.03977
9382 [0, 7, 15, 23, 28, 30, 34, 47, 51, 54, 58, 66, 71] 0.03902
9388 [0, 7, 14, 22, 27, 30, 34, 48, 51, 54, 58, 66, 71] 0.03813 # <- exceed ACC
9462 [0, 7, 15, 21, 27, 31, 34, 48, 52, 54, 58, 66, 71] 0.03799
9480 [0, 7, 15, 21, 26, 30, 34, 48, 52, 54, 58, 66, 71] 0.03756
9720 [0, 7, 15, 21, 27, 30, 34, 48, 52, 54, 58, 66, 71] 0.03743
9726 [0, 7, 15, 22, 27, 30, 34, 47, 52, 54, 58, 66, 71] 0.03742

このサンプルでは、9388ステップでACCのMSEを下回りましたが、SAはランダム性があるので、もっと早く超えるケースもあり、全10000ステップで超えないケースも少なくはないです。また、問題のスケールや入力自身の特徴にも関係があります。ただし、SAは理論上、時間をかければ必ず最適解にたどり着くという保証があります。

三つのサンプルを各々10回テストして、ACCのパフォーマンスを超えた状況を把握します。

サンプル 超えなかった回数 平均ステップ数 最小ステップ数
Punch 0 8.3 1
Dance 5 8517 5157
Grab 8 9681 9536
Grab(前48フレーム) 0 2221 134
Grab(前24フレーム) 0 220 80

ACCのパフォーマンスを超えるに必要な平均ステップ数が問題スケールによって爆発的に増えることがざっくり見えるでしょう。

計算時間だと、Intel(R) Core(TM) i9-9900KF CPU @ 3.60GHzのシングルスレッドで、Danceの場合、SAは45秒くらいで、ACCは0.00005秒です。

結論

繰り返しますが、ここまでの説明は最初の定義と仮定に基づいたものです。なのでアルゴリズムを評価するには主観と数学モデル内の客観の両方があります。理想としては、数学的に最適したアルゴリズムは、主観でも納得できる結果を出せる、です。

主観の方は、アニメーターでない自分から見ると、確かにそれっぽいだけど、原画になれるかな?みたいなぼんやりした感覚しかないです。なので、もし専門の方から意見頂けるとありがたいです!

数学的には、

  • ACC:理屈合ってないから絶対最適じゃないが、それなりにいい結果出せる;線形的複雑性、超早い。
  • SA:理論上最適解を見つけられる;爆発する複雑性、遅い。

というようなトレードオフになっています。

抽出密度の設定の試行錯誤を考えると、実用的には「ACCが使えそう」と考えています。


タイミング調整

タイミングの調整は個性の出所なので、キーフレーム抽出みたいに何かを定義するのが難しいです。ここは一つのシンプルな試みをお見せしたいです。

中村豊の作画

f:id:morika-sen:20200513180656g:plain
作品:「僕のヒーローアカデミア」 原画:中村豊 *7

中村さんの作画によく見られる手法で、スローモーションで撮る前景とハイスピードで流れる背景で、前景が凄い速度で動きはじめているが、現実時間では一種の「タメ」になります。そして最後に前景が動き出し(画面内の時間が現実に戻ります)、観客が「タメ」た情緒も解放され、並ならぬ迫力が伝わります。画面内の時間の流れの操作にも言えますね。

真似してみよう

Punchのキーフレーム抽出したものを基にして、閾値で加速が早い所を検出して、その前のキーフレームとの間に、大量の中割(線形的補間)を入れてみると、下図のようになります。

f:id:morika-sen:20200520162619g:plain:w300
Punchのキータイムシート+パンチ前に大量中割

勿論これは汎用性がないので、こういうスタイル的なものはやはりクラシックのアルゴリズムじゃなく、AIの出所ではないでしょうか。


まとめ

芸術(作画)を数学で分析して、そして敢えて数学的な解法を使わず、芸術の感性による直感を使ってアルゴリズムをデザインして、最後に一定の正しさ(数学的に)を得られる、且つ感性的にもそれっぽいものができました。この感性と理性がねじり合うような過程を見ると、感性と理性がどこかで通じ合っているような気がしますね。

しかし、そもそも情報量の定義、線形的補間の仮定などは人間の認知にどのくらいに合っていますかが分からないです。もしAIの脳と人間の脳は自然において、同じく唯一の最適解になっていたら、人為に定義するじゃなく、AIが判断すればどうでしょうか。

そして現在のモデルにおいても、ACCあるいはそれみたいな局所的アルゴリズムが最適じゃないのは確かであります。ならもっと最適に近づけられますか。前回紹介した強化学習の枠組みで、AIが学習すれば、一番いい手法が見つかられるでしょうか。

というわけで、今回は伝統的なアルゴリズムで、「動きの情報量が保てばスムーズ」を具体化した仮定で、3Dモーションからキーフレーム抽出をある程度の出来るということを検証してみました。更なる進化を「AIに任せる」手法を考えて行きたいと思います。(今後のテーマ)

*1:ロトスコープ | Wikipedia

*2:©Copyright King Record.Co.,Ltd. All Rights Reserved. ©押見修造・講談社/「惡の華」製作委員会

*3:©赤坂アカ/集英社・かぐや様は告らせたい製作委員会

*4:©赤根和樹・エイトビット/星合の空製作委員会 ©1995-2020, Tokyo Broadcasting System Television, Inc. All Rights Reserved.

*5:タイムシートは原画・動画を時間軸に位置づける指示書です。ここではタイムシートの原画欄の形を使ってます:ナンバーは原画を、点は中割を示しています。また参考物の各フレームは原画扱いとなります。タイムシートについてはこちらに参考してください。

*6:©2014 BONES / Project SPACE DANDY

*7:©堀越耕平/集英社・僕のヒーローアカデミア製作委員会