【Python/OpenCV】オプティカルフロー(Lucas-Kanade法)で物体追跡

Python版OpenCVでLucas-Kanade法を実装し、物体追跡(オプティカルフローを計算)する方法をソースコード付きで解説します。

オプティカルフローで物体追跡

オプティカルフローとは、デジタル画像中の物体の動きを「ベクトル」で表したものです。
主に移動物体の検出や、その動作の解析などによく用いられています。

実行例

しかしオプティカルフロー(=物体の移動ベクトル)を一意的に求めることは困難です。
一般的には推定によって動き(ベクトル)を求めます。
オプティカルフローを推定する手法は代表的なモノに「LucasKanade法」や「Horn-Schunk法」があります。
今回は、Shi-Tomasi法で求めた特徴点を「LucasKanade法」で追跡してみます。

【オプティカルフローとは】推定の原理・特徴・計算式
オプティカルフローとは?移動量の推定方法、原理、計算式についてまとめました。

サンプルコード

サンプルプログラムのソースコードです。


サンプルコードの詳細解説

サンプルコードの各部分を詳しく解説します。

1. ライブラリのインポート

import cv2
import numpy as np
  • cv2: OpenCVライブラリをインポートします。OpenCVはコンピュータビジョンのための強力なツールセットを提供します。
  • numpy: NumPyライブラリをインポートします。NumPyは数値計算を効率的に行うためのライブラリです。

2. ビデオキャプチャーの設定

cap = cv2.VideoCapture("/Users/github/sample/python/opencv/video/input2.mp4")
  • cv2.VideoCapture: 指定されたビデオファイルを読み込みます。ここでは、input2.mp4というファイルを読み込んでいます。

3. Shi-Tomasi法のパラメータ設定

ft_params = dict(maxCorners=100, qualityLevel=0.3, minDistance=7, blockSize=7)
  • maxCorners: 検出する最大の特徴点数を指定します。ここでは最大100個の特徴点を検出します。
  • qualityLevel: 特徴点の品質を決めるしきい値です。値が高いほど、品質の高い特徴点のみが選ばれます。
  • minDistance: 特徴点間の最小距離を指定します。これにより、近接する特徴点が除外されます。
  • blockSize: 特徴点を計算するためのブロックサイズを指定します。

4. Lucas-Kanade法のパラメータ設定

lk_params = dict(winSize=(15, 15), maxLevel=2, criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
  • winSize: オプティカルフローを計算するためのウィンドウサイズを指定します。ここでは15×15ピクセルのウィンドウを使用します。
  • maxLevel: ピラミッドのレベル数を指定します。ここでは2レベルのピラミッドを使用します。
  • criteria: 探索アルゴリズムの終了条件を指定します。ここでは、10回の反復または0.03の精度に達するまで計算を続けます。

5. 最初のフレームの取得とグレースケール変換

ret, frame = cap.read()
gray1 = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  • cap.read(): ビデオから最初のフレームを取得します。
  • cv2.cvtColor: フレームをグレースケールに変換します。カラー画像をグレースケールにすることで、計算が高速化されます。

6. Shi-Tomasi法で特徴点の検出

ft1 = cv2.goodFeaturesToTrack(gray1, mask=None, **ft_params)
  • cv2.goodFeaturesToTrack: Shi-Tomasi法を使用して、グレースケール画像から特徴点を検出します。

7. マスク用の配列を生成

mask = np.zeros_like(frame)
  • np.zeros_like: フレームと同じサイズのゼロ配列(黒い画像)を生成します。これは特徴点の軌跡を描画するために使用されます。

8. フレームごとの処理

while(cap.isOpened()):
    ret, frame = cap.read()
    gray2 = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    ft2, status, err = cv2.calcOpticalFlowPyrLK(gray1, gray2, ft1, None, **lk_params)
    good1 = ft1[status == 1]
    good2 = ft2[status == 1]
    for i, (pt2, pt1) in enumerate(zip(good2, good1)):
        x1, y1 = pt1.ravel()
        x2, y2 = pt2.ravel()
        mask = cv2.line(mask, (x2, y2), (x1, y1), [0, 0, 200], 2)
        frame = cv2.circle(frame, (x2, y2), 5,  [0, 0, 200], -1)
    img = cv2.add(frame, mask)
    cv2.imshow('mask', img)
    gray1 = gray2.copy()
    ft1 = good2.reshape(-1, 1, 2)
    if cv2.waitKey(30) & 0xFF == ord('q'):
        break
  • cap.isOpened(): ビデオキャプチャーが開いているかを確認します。
  • cap.read(): 次のフレームを取得します。
  • cv2.cvtColor: フレームをグレースケールに変換します。
  • cv2.calcOpticalFlowPyrLK: Lucas-Kanade法を使用して、前のフレームと現在のフレーム間の特徴点のオプティカルフローを計算します。
  • status: 特徴点が追跡されたかどうかを示すステータス配列です。
  • good1good2: 追跡された特徴点の座標を取得します。
  • cv2.line: 特徴点の軌跡をマスクに描画します。
  • cv2.circle: 現在のフレームに特徴点を描画します。
  • cv2.add: フレームとマスクを合成します。
  • cv2.imshow: 合成画像をウィンドウに表示します。
  • cv2.waitKey(30): 30ミリ秒待機し、’q’キーが押されたらループを終了します。

9. 終了処理

cv2.destroyAllWindows()
cap.release()
  • cv2.destroyAllWindows: すべてのウィンドウを閉じます。
  • cap.release: ビデオキャプチャーを解放します。
【Python版OpenCV超入門】使い方とサンプルコードを解説
Python版OpenCVで画像処理プログラミングを行う方法を入門者向けにソースコード付きで解説するページです。

コメント