OpenCV 4.13.0
Open Source Computer Vision
読み込み中...
検索中...
見つかりません
🤖 AIによる機械翻訳(非公式) — これは OpenCV 4.13.0 公式リファレンス(英語)を AI (Claude) で自動翻訳したものです。訳に誤りを含む場合があります。正確な情報は 公式英語版(原文) を参照してください。
オプティカルフロー

前のチュートリアル: MeanshiftとCamshift
次のチュートリアル: カスケード分類器

目的

本章では、

  • オプティカルフローの概念と、Lucas-Kanade 法を用いたその推定について理解する。
  • cv.calcOpticalFlowPyrLK() のような関数を使って、動画中の特徴点を追跡する。
  • cv.calcOpticalFlowFarneback() メソッドを使って、密なオプティカルフロー場を生成する。

オプティカルフロー

オプティカルフローとは、物体やカメラの動きによって生じる、連続する2枚のフレーム間での画像中の物体の見かけの動きのパターンである。これは2次元のベクトル場であり、各ベクトルは最初のフレームから2番目のフレームへの点の移動を示す変位ベクトルである。下の画像を見てほしい(画像提供: オプティカルフローに関する Wikipedia の記事)。

image

これは連続する5枚のフレーム中をボールが移動している様子を示している。矢印はその変位ベクトルを表す。オプティカルフローは次のような分野で多くの応用がある:

  • Structure from Motion
  • 動画圧縮
  • 動画の手ブレ補正 ...

オプティカルフローはいくつかの仮定の上に成り立つ:

  1. ある物体のピクセル強度は連続するフレーム間で変化しない。
  2. 近傍のピクセルは同様の動きをする。

最初のフレーム中のピクセル \(I(x,y,t)\) を考える(ここで新たに時間という次元が追加されていることに注意。これまでは画像だけを扱っていたので時間は不要だった)。このピクセルは、\(dt\) 時間後に撮影された次のフレームで距離 \((dx,dy)\) だけ移動する。これらのピクセルは同一であり強度も変化しないので、次のように表せる。

\[I(x,y,t) = I(x+dx, y+dy, t+dt)\]

次に右辺をテイラー級数で近似し、共通項を消去して \(dt\) で割ると、次の式が得られる。

\[f_x u + f_y v + f_t = 0 \;\]

ここで:

\[f_x = \frac{\partial f}{\partial x} \; ; \; f_y = \frac{\partial f}{\partial y}\]

\[u = \frac{dx}{dt} \; ; \; v = \frac{dy}{dt}\]

上の式はオプティカルフロー方程式と呼ばれる。この式では \(f_x\) と \(f_y\) を求めることができ、これらは画像勾配である。同様に \(f_t\) は時間方向の勾配である。しかし \((u,v)\) は未知である。この1本の方程式を2つの未知変数について解くことはできない。そこでこの問題を解くためにいくつかの手法が提供されており、その1つが Lucas-Kanade である。

Lucas-Kanade 法

先ほど、近傍のピクセルはすべて同様の動きをするという仮定を見た。Lucas-Kanade 法では、対象点の周囲の 3x3 のパッチを取る。したがって9個の点はすべて同じ動きをする。これら9個の点について \((f_x, f_y, f_t)\) を求めることができる。こうして問題は、2つの未知変数を持つ9本の方程式を解くことになり、これは過剰決定系である。より良い解は最小二乗法によって得られる。以下が最終的な解であり、これは未知数2つ・方程式2つの問題となっていて、解いて答えを得る。

\[\begin{bmatrix} u \\ v \end{bmatrix} = \begin{bmatrix} \sum_{i}{f_{x_i}}^2 & \sum_{i}{f_{x_i} f_{y_i} } \\ \sum_{i}{f_{x_i} f_{y_i}} & \sum_{i}{f_{y_i}}^2 \end{bmatrix}^{-1} \begin{bmatrix} - \sum_{i}{f_{x_i} f_{t_i}} \\ - \sum_{i}{f_{y_i} f_{t_i}} \end{bmatrix}\]

(この逆行列が Harris コーナー検出器と類似していることに注目。これはコーナーが追跡に適した点であることを示している。)

そのため、ユーザの視点から見ると考え方は単純で、追跡したい点をいくつか与えると、それらの点のオプティカルフローベクトルが返ってくる。しかし、ここでもいくつか問題がある。これまでは小さな動きを扱ってきたので、大きな動きがあると失敗する。これに対処するために、ピラミッドを使う。ピラミッドを上っていくと、小さな動きは取り除かれ、大きな動きが小さな動きになる。そこで Lucas-Kanade を適用することで、スケールとともにオプティカルフローが得られる。

OpenCV での Lucas-Kanade オプティカルフロー

OpenCV はこれらすべてを1つの関数 cv.calcOpticalFlowPyrLK() で提供している。ここでは、動画中のいくつかの点を追跡する簡単なアプリケーションを作成する。追跡する点を決めるために cv.goodFeaturesToTrack() を使う。最初のフレームを取得し、その中で Shi-Tomasi コーナー点をいくつか検出し、それらの点を Lucas-Kanade オプティカルフローを使って反復的に追跡する。関数 cv.calcOpticalFlowPyrLK() には、前のフレーム、前の点、次のフレームを渡す。この関数は次の点を返すとともに、いくつかのステータス値を返す。ステータス値は、次の点が見つかった場合は 1、そうでない場合は 0 となる。これらの次の点を、次のステップで前の点として反復的に渡していく。以下のコードを参照してほしい。

(このコードは、次のキーポイントがどれだけ正確かをチェックしていない。そのため、ある特徴点が画像中で消えてしまっても、オプティカルフローがそれに近く見える次の点を見つけてしまう可能性がある。したがって、頑健な追跡のためには、特定の間隔でコーナー点を検出すべきである。OpenCV のサンプルには、5フレームごとに特徴点を見つけるサンプルが用意されている。これは、得られたオプティカルフローの点に対して逆方向のチェックも行い、良い点だけを選別している。samples/python/lk_track.py を参照してほしい。)

得られた結果を見てみよう。

image

OpenCV での密なオプティカルフロー

Lucas-Kanade 法は、疎な特徴点集合(この例では Shi-Tomasi アルゴリズムで検出したコーナー)についてオプティカルフローを計算する。OpenCV は密なオプティカルフローを求める別のアルゴリズムも提供している。これはフレーム中のすべての点についてオプティカルフローを計算する。これは Gunnar Farneback のアルゴリズムに基づいており、2003年に Gunnar Farneback による "Two-Frame Motion Estimation Based on Polynomial Expansion" で説明されている。

以下のサンプルは、上記のアルゴリズムを使って密なオプティカルフローを求める方法を示している。オプティカルフローベクトル \((u,v)\) を持つ2チャンネルの配列が得られる。その大きさと方向を求める。結果を見やすくするために色分けする。方向は画像の色相 (Hue) 値に対応する。大きさは明度 (Value) 面に対応する。以下のコードを参照してほしい。

以下の結果を参照のこと。

image