ステータス: ドラフト (2026-10-13)、一部実測。 論文の数値は原文を開いて条件とともに確認しました。自分で試したものはノートPCのCPUによるnumpyのサンプル(
code/05_flow_toy.py, 1秒未満)です。卓球動画のオプティカルフロー実測(Farneback)はリポジトリdocs/tt/PERFORMANCE.md2.9.7の値であり、RAFTは私たちの動画では実行していません(未実測)。 シリーズ「ビジョンモデルを読む 2」第5編。ここからは「動き」です。次回: 動画モデル.
目次
- 1. 直感:ピクセルごとに1つの矢印
- 2. 古典的手法の仮定とその限界
- 3. 学習モデルは正解をどこから得るのか
- 4. 図解:RAFT
- 5. どのように学習させるのか
- 6. 実際に動かしてみる
- 7. 論文の数値
- 8. 限界
- 9. 我々のプロジェクトとのつながり
- 参考文献
1. 直感:ピクセルごとに1つの矢印
動画の2フレームを重ねてみると、動いたものはズレており、止まっているものは重なります。 オプティカルフローは、最初のフレームのピクセル一つひとつに「次のフレームのどこへ行ったか」を示す矢印(水平移動u、垂直移動v)を1つずつ付与したマップです。1080pのフレームであれば、矢印は200万個ほどになります。
オプティカルフローは「何が」動いたのかは告げず、「どこがどれだけ」動いたのかだけを伝えます。そのため、対象物を知らなくても使用できます。卓球動画では、選手が大きく動く区間(ラリー中)とうろうろしている区間(ラリーの間)が、オプティカルフローの大きさだけでもかなり区別できます。
2. 古典的手法の仮定とその限界
古典的手法は2つの仮定から出発します。
- 明るさは一定である。 点が1つ動いても、その点の明るさは変化しない: I₁(x, y) = I₂(x+u, y+v)。
- 動きは小さい。 そのため、右辺を1次テーラー展開できる: I_x·u + I_y·v + I_t ≈ 0。
式は1つですが未知数は2つ(u, v)あります。Lucas–Kanade(1981)は「小さなウィンドウ内のピクセルは一緒に動く」と仮定し、ウィンドウ内の式を集めて最小二乗法で解きます。
この方法が破綻する箇所が3つあります。
- アパーチャ問題(aperture problem)。 縞模様のように一方向にしかパターンが変化しない場所では、縞に沿った動きは明るさに何ら痕跡を残しません。式が解けなくなります。
- 大きな動き。 1次展開は動きが1〜2ピクセルのときのみ成り立ちます。速いボールのように1フレームで数十ピクセル移動する場合は間違った結果になります。画像を縮小して大きな動きを小さくしてから再度拡大する ピラミッドが標準的な対処法です。
- 明るさが変化する場所。 影、反射、ブレにより最初の仮定が崩れます。卓球ボールのブレはまさにこれに該当します。
3. 学習モデルは正解をどこから得るのか
写真においてピクセルごとに正解の矢印を手動で付与することはできません。そのため、学習型のオプティカルフローは 合成データから始まりました。FlowNet(2015)は写真の背景上に3Dの椅子モデル809種類をレンダリングして貼り付け、アフィン変換で動かした Flying Chairs(22,872ペア)を作成しました。動きを直接作成しているため、正解が正確に分かっています(論文)。以降、よりリアルなFlyingThings3D、アニメ映画から抽出したSintel、自動車の公道KITTIへと続く学習の順序が標準となりました。
損失はたいてい エンドポイント誤差(EPE, End-Point Error) です。予測された矢印の終点と正解の矢印の終点の間の距離(ピクセル)を平均します。
4. 図解:RAFT
RAFT(Teed & Deng, ECCV 2020)は3つのコンポーネントで構成されています。
- 特徴量エンコーダ。 2つのフレームを同じCNNに入力し、⅛解像度の特徴量(256次元)を抽出します。明るさではなく特徴量を比較するため、「明るさは一定」という仮定が緩やかになります。
- すべてのペアの相関ボリューム(all-pairs correlation volume)。 最初のフレームのすべての位置と2番目のフレームのすべての位置の間の内積を一度に計算し、4次元テーブル(H×W×H×W)として保持します。そして後ろの2つの次元を1・2・4・8ステップでプーリングし、4段階のピラミッドを作成します。一度計算すれば終わりです。
- 反復更新器。 現在のフロー推定が指し示す場所の周囲半径4ピクセル分を、4段階のピラミッドからすべてルックアップし、その値を畳み込みGRUに入力して「推定をどれだけ修正するか」(Δ)を出力します。同じ重みのGRUを学習時は12回、評価時はSintelで32回、KITTIで24回繰り返します。200回まで回しても発散しなかったと記載されています(論文)。
ピラミッドを「粗い解像度で解いて細かい解像度に降りていく」段階的な構造として用いていた従来の手法(PWC-Netなど)とは異なり、RAFTは ⅛解像度という単一の解像度ですべての距離のペアをすでに把握しているため、素早く大きく移動したオブジェクトも最初から捉えることができます。
5. どのように学習させるのか
L = Σᵢ γ^(N−i) · ‖ fᵢ − f_정답 ‖₁, γ = 0.8, N = 반복 횟수
すべての反復の出力に対して損失を課しますが、後の反復ほど重みを大きくします(論文)。序盤の反復では大きく外れても構いませんが、徐々に正解に近づくべきであることを意味します。この損失のおかげで、GRUは「一発で当てる」のではなく「少しずつ修正する」ことを学習します。
⅛解像度のフローをもとの解像度に拡大する際は、単純な補間の代わりに、近傍3×3ピクセルの加重平均をネットワークが学習した重みで計算します(凸結合アップサンプリング)。オブジェクトの境界でフローがぼやけないようにするためです。
学習の順序はゼロから(事前学習なしで)Flying Chairsで10万ステップ → FlyingThingsで10万ステップ → SintelやKITTIなどを混ぜて10万ステップ → KITTIで5万ステップであり、デスクトップ向けのGPU2枚で学習を行いました(論文)。
6. 実際に動かしてみる
code/05_flow_toy.py はnumpyだけでもRAFTの2つの発想を模倣しています。
- 滑らかな模様のある64×64の画像を(3.4, −2.2)ピクセル分だけ平行移動させて2番目のフレームを作成します(フーリエシフトを用いているため、小数点の移動も正確です)。
- ピクセルごとに周囲5×5のパッチを特徴量とし、2つのフレームの すべてのピクセルペアの類似度を4,096×4,096 = 1,680万エントリのテーブルとして一度に計算します(相関ボリューム)。
- 出発点(0, 0)の周囲半径8ピクセルの範囲内で最も類似している場所を選択します(ルックアップ)。整数単位までしか一致しません。
- その推定値を出発点として、「現在の推定通りに2番目のフレームを巻き戻し、残った明るさの差分を勾配で割って修正する」という処理を繰り返します。RAFTのGRUが 学習によって 行うことを、ここではLucas–Kanadeの式をベースにした 手動で記述した ルールで代用しました。
[무늬 있는 그림] 상관 부피 4,096×4,096 = 16.8M 칸
반경 안 argmax(정수) 추정: EPE 평균 0.6546px · 중앙 0.4472px, 가장 흔한 값 (3, -2)
갱신 1회: EPE 평균 0.1649px · 중앙 0.0414px
갱신 2회: EPE 평균 0.1726px · 중앙 0.0602px
갱신 5회: EPE 평균 0.1593px · 중앙 0.0499px
すべてのペアの比較だけでは整数(3, −2)までしか捉えられず、誤差の中央値は0.45px(真の値3.4, −2.2と整数との間の距離)となります。1回の更新で0.04pxに減少しました。それ以降さらに減少しなかったのは、手動で記述したルールの限界(巻き戻し時に用いる双一次補間の誤差)によるものです。RAFTがGRUを学習させる理由はここにあります。「どれだけ修正するか」をルールではなくデータから学習すれば、補間誤差やオクルージョンといった状況も考慮することができます。
同じことを縦縞模様に対して試してみました。
[세로줄(구경 문제)]
반경 안 argmax(정수) 추정: EPE 평균 7.5758px, 가장 흔한 값 (-4, 0)
갱신 1–5회: 변화 없음 (식이 풀리지 않는 화소 100.0%)
→ 가로 움직임 중앙값 -4.00(참값 3.4), 세로 움직임은 17가지 값으로 흩어짐
縦縞は上下に動いても同じように見えるため、縦方向の動きを知る術はありません(17通りの値に分散する)。横方向の動きも、縞の間隔が8ピクセルであるため3.4と3.4−8 = −4.6の区がつきません(最も近い整数である−4が選ばれました)。更新式はそもそも解けません。アパーチャ問題を数値として確認したことになります。学習モデルもこの場合には、周囲のコンテキスト(オブジェクトの境界、他の部分の動き)から推測するほかありません。
7. 論文の数値
| モデル | 数値(論文) | 条件 |
|---|---|---|
| FlowNetS / FlowNetC(2015) | Sintel final test EPE 7.42 / 7.28 | Flying Chairsで学習。デスクトップ向けGPUで0.08 / 0.15秒 |
| PWC-Net(2018) | Sintel final 5.04, KITTI-15 Fl-all 9.60%, パラメータ数875万 | 1024×436で約35fps(デスクトップ向けGPU) |
| RAFT(2020) | Sintel clean/final 1.94/3.18(2フレーム)、1.61/2.86(前方のフローから開始)、KITTI-15 Fl-all 5.10% | パラメータ数530万(小型版100万)。1088×436で10回反復0.10秒(デスクトップ向けGPU)、1080pで12回反復550ms |
| RAFT、合成データのみで学習 | Sintel学習セット clean 1.43 · final 2.71、KITTI-15 EPE 5.04 · Fl-all 17.4% | Chairs → Thingsのみ学習し、他のデータへ直接適用 |
| SEA-RAFT(2024) | Springベンチマーク 1pxエラー率 3.686、EPE 0.363 | 反復4回(学習)・4〜12回(推論)、540×960でRAFTの140.7msに対して70.96ms(デスクトップ向けGPU) |
Fl-allは、エンドポイント誤差が3ピクセルおよび正解の大きさの5%の双方を超えるピクセルの割合です。低いほど優れています。
SEA-RAFTは、RAFTの損失を「2つのラプラス分布を混合した負対数尤度」に変更しました。当てやすいピクセルに対してはL1のように、本来あいまいなピクセル(オクルージョン、アパーチャ問題)に対しては誤差を過剰にペナルティしないよう、ネットワーク自身が不確実性を同時に出力するようにしたものです。初期推定値を0の代わりに直接回帰することで反復回数を削減しています(論文)。
8. 限界
- 計算が重い。 RAFTは1080pの1フレームあたり0.5秒程度かかりました(デスクトップ向けGPU、論文)。60fpsの1フレームあたりの予算(16.7ms)とは桁違いです。
- 小さくて速いオブジェクトに弱い。 ⅛解像度では、直径数ピクセルの卓球ボールは特徴量の1マスよりも小さくなります。ボールの動きは、オプティカルフローよりもボール検出結果をつなぎ合わせる方が正確です(第9編)。
- ブレは明るさの仮定を崩す。 ブレたボールはフレームごとに形が変わり、「同じ点」を見つけることが困難になります。
9. 我々のプロジェクトとのつながり
- 実測:安価で荒いシグナルとしては十分に活用できた。 OpenTTGames のテスト7試合(51,060フレーム)において、160×90 に縮小した映像の Farneback 光流(古典的な手法)で「今ラリー中か」を1秒単位で判定しました。選手側の光流の AUC が 0.798、映像全体のフレーム差分が 0.770、BlurBall のボールヒートマップの最大値が 0.860、ボールと光流をランク平均で合わせると 0.876 であり、CPU で1フレームあたり 2.5–2.8ms でした(リポジトリ
docs/tt/PERFORMANCE.md2.9.7)。ボールが遮られた際に「まだラリー中」であることを伝える補助信号として使えるということです。 - バウンド判定にはまだ根拠がない。 同じ光流・差分の値を学習型バウンド判定器(第4回)の入力に単純に連結してみた初期テストではメリットは見られず、確定した結果はまだありません(2026-10-13 の研究ノート基準、進行中の研究 — ノートはまだリポジトリ外)。「連結する」という結合方式しか試していないため、他の結合方法は開かれています。
- ボールトラッカー内の動き。 第9回の TrackNetV4・V5 は光流の代わりに フレーム差分をアテンションマップとして使って動くボールを強調し、TOTNet は光流を入力に加えたバージョンの方がオクルージョン区間でより正確でしたが、その分遅くなりました(第9回)。
TT の一言。 ストライプのシャツが上下に動いても、コンピュータにはそれが動いたかどうかわかりません。本当です、例を使って自分で確認しました。だから光流は「大体どこがどれくらい動いているか」に使い、ボールは別に見つけます。
参考文献
- Lucas & Kanade, An Iterative Image Registration Technique with an Application to Stereo Vision, IJCAI 1981.
- Farnebäck, Two-Frame Motion Estimation Based on Polynomial Expansion, SCIA 2003. https://doi.org/10.1007/3-540-45103-X_50
- Dosovitskiy et al., FlowNet: Learning Optical Flow with Convolutional Networks, ICCV 2015. https://arxiv.org/abs/1504.06852
- Sun et al., PWC-Net: CNNs for Optical Flow Using Pyramid, Warping, and Cost Volume, CVPR 2018. https://arxiv.org/abs/1709.02371
- Teed & Deng, RAFT: Recurrent All-Pairs Field Transforms for Optical Flow, ECCV 2020. https://arxiv.org/abs/2003.12039
- Wang, Lipson, Deng, SEA-RAFT: Simple, Efficient, Accurate RAFT for Optical Flow, ECCV 2024. https://arxiv.org/abs/2405.14793
- 我々の測定: リポジトリ
docs/tt/PERFORMANCE.md2.9.7. サンプルコードと出力:code/05_flow_toy.py,code/05_flow_toy.out.txt