![]() |
OpenCV 4.13.0
Open Source Computer Vision
|
meanshiftの背後にある直感は単純である。点の集合があると考えてみる。(ヒストグラムバックプロジェクションのようなピクセル分布でもよい。)小さなウィンドウ(円でもよい)が与えられ、そのウィンドウをピクセル密度が最大となる領域(または点が最も多い領域)へ移動させる必要がある。これは以下の簡単な図で示される。
最初のウィンドウは「C1」という名前の青い円で示されている。その元の中心は「C1_o」という名前の青い四角形で示されている。しかし、そのウィンドウ内の点の重心を求めると、ウィンドウの実際の重心である「C1_r」という点(小さな青い円で示されている)が得られる。両者は明らかに一致しない。そこで、新しいウィンドウの円が直前の重心と一致するようにウィンドウを移動させる。再び新しい重心を求める。ほとんどの場合、一致しないだろう。そこで再び移動させ、ウィンドウの中心とその重心が同じ位置(または小さな許容誤差の範囲内)に収まるまで反復を続ける。最終的に得られるのは、ピクセル分布が最大となるウィンドウである。それは「C2」という名前の緑の円で示されている。図でわかるように、最も多くの点を含んでいる。この一連の処理は、以下の静止画像で実演されている。
そこで通常は、ヒストグラムをバックプロジェクションした画像と、初期のターゲット位置を渡す。オブジェクトが移動すると、当然その移動はヒストグラムバックプロジェクション画像に反映される。その結果、meanshiftアルゴリズムは、密度が最大となる新しい位置へウィンドウを移動させる。
OpenCV.jsでmeanshiftを使用するには、まずターゲットを設定し、そのヒストグラムを求める必要がある。これにより、meanshiftの計算のために各フレームでターゲットをバックプロジェクションできる。また、ウィンドウの初期位置も指定する必要がある。ここではヒストグラムには色相(Hue)のみを考慮する。さらに、暗い場所での誤った値を避けるため、暗い部分の値は cv.inRange() 関数を用いて破棄する。
次の関数を使用する: cv.meanShift (probImage, window, criteria)
| probImage | オブジェクトヒストグラムのバックプロジェクション。詳細は cv.calcBackProject を参照。 |
| window | 初期探索ウィンドウ。 |
| criteria | 反復探索アルゴリズムの停止条件。 |
先ほどの結果をよく観察しただろうか。問題がある。オブジェクトが遠くにあっても、カメラのごく近くにあっても、ウィンドウのサイズは常に同じである。これはよくない。ターゲットのサイズや回転に合わせてウィンドウサイズを適応させる必要がある。この解決策もまた「OpenCV Labs」から生まれたもので、CAMshift (Continuously Adaptive Meanshift) と呼ばれ、Gary Bradskyが1988年の論文「Computer Vision Face Tracking for Use in a Perceptual User Interface」で発表した。
まずmeanshiftを適用する。meanshiftが収束すると、ウィンドウのサイズを \(s = 2 \times \sqrt{\frac{M_{00}}{256}}\) として更新する。また、それに最もよく当てはまる楕円の向きも計算する。再び、新しくスケーリングした探索ウィンドウと直前のウィンドウ位置でmeanshiftを適用する。この処理は、要求される精度が満たされるまで続けられる。
meanshiftとほぼ同じだが、回転した矩形(これが結果となる)とボックスのパラメータ(次の反復で探索ウィンドウとして渡すために使われる)を返す。
次の関数を使用する: cv.CamShift (probImage, window, criteria)
| probImage | オブジェクトヒストグラムのバックプロジェクション。詳細は cv.calcBackProject を参照。 |
| window | 初期探索ウィンドウ。 |
| criteria | 反復探索アルゴリズムの停止条件。 |