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

この記事では、Python版OpenCVでパーティクルフィルタを実装し、カラートラッキング(色追跡)する方法をソースコード付きで解説します。

パーティクルフィルタでカラートラッキング

オプティカルフローとは、デジタル画像中の物体の動きを「ベクトル」で表したものです。
主に移動物体の検出や、その動作の解析などによく用いられています。
しかしオプティカルフロー(=物体の移動ベクトル)を一意的に求めることは困難です。
一般的には推定によって動き(ベクトル)を求めます。
オプティカルフローを推定する手法は代表的なモノに「LucasKanade法」や「Horn-Schunk法」があります。
今回は、「LucasKanade法」を使って物体追跡を行いました。

尚、追跡する対象は、Shi-Tomasi法で求めた特徴点です。

関連記事
原理の詳細 オプティカルフロー推定の原理・特徴・計算式
OpenCVの導入方法 【Python3】OpenCV3をインストール
Python版OpenCV入門 Python版OpenCV入門 サンプル集
画像処理の原理 【画像処理入門】アルゴリズム&プログラミング

大まかな処理手順は以下の通りです。

説明
cv2.goodFeaturesToTrackメソッドで前フレームから特徴点を抽出します。(Shi-Tomashiの方法)
cv2.calcOpticalFlowPyrLKメソッドで特徴点のオプティカルフローを計算します。(前フレームと現フレームからLucas-Kanade法で算出)
現フレームにオプティカルフローを描画します。
②~③を繰り返します。

ソースコード(Python3+OpenCV3)

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

# -*- coding: utf-8 -*-
import cv2
import numpy as np

def main():
    # ビデオキャプチャー
    cap = cv2.VideoCapture('input.mp4')
    # Shi-Tomasi法のパラメータ(コーナー検出用)
    ft_params = dict(maxCorners=100, qualityLevel=0.3, minDistance=7, blockSize=7)

    # Lucas-Kanade法のパラメータ(追跡用)
    lk_params = dict(winSize=(15,15), maxLevel=2, criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))

    # 最初のフレームを取得
    ret, frame = cap.read()
    gray1 = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # グレースケール変換
    ft1 = cv2.goodFeaturesToTrack(gray1, mask = None, **ft_params) # Shi-Tomasi法で特徴点の検出
    mask = np.zeros_like(frame) # mask用の配列を生成

    while cv2.waitKey(30) < 0 & 0xff != 27: 
        # グレースケールに変換
        gray2 = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        # Lucas-Kanade法でオプティカルフローの検出
        ft2, status, err = cv2.calcOpticalFlowPyrLK(gray1, gray2, ft1, None, **lk_params)

        # オプティカルフローを検出した特徴点を取得(1なら検出)
        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)
        ret, frame = cap.read()

    # 終了処理
    cv2.destroyAllWindows()
    cap.release()


if __name__ == "__main__":
    main()

実行結果

サンプルプログラムの実行結果です。

- 関連記事
1 PythonでOpenCV入門 サンプル集
2 【Python】画像処理プログラミング入門
3 【画像処理入門】アルゴリズム&プログラミング
関連記事