Edited at

OpenCVでオプティカルフローをリアルタイムに描画する(Shi-Tomasi法、Lucas-Kanade法)

More than 3 years have passed since last update.


はじめに

OpenCV(Open Source Computer Vision Library)はBSDライセンスの映像/画像処理ライブラリ集です。画像のフィルタ処理、テンプレートマッチング、物体認識、映像解析、機械学習などのアルゴリズムが多数用意されています。

OpenCVを使った動体追跡の例 (OpenCV Google Summer of Code 2015)

https://www.youtube.com/watch?v=OUbUFn71S4s

インストールと簡単な使い方はこちら

OpenCV 3(core + contrib)をPython 3の環境にインストール&OpenCV 2とOpenCV 3の違い&簡単な動作チェック

静止画像のフィルター処理についてはこちら

OpenCVでエッジ検出してみる

OpenCVで各種フィルター処理をする(グラディエント、ハイパス、ラプラシアン、ガウシアン)

OpenCVで特徴点を抽出する(AgastFeature, FAST, GFTT, MSER, AKAZE, BRISK, KAZE, ORB, SimpleBlob)

動画ファイルの処理についてはこちら

OpenCVで動画をリアルタイムに変換してみる

OpenCVでWebカメラ/ビデオカメラの動画をリアルタイムに変換してみる

今回は、OpenCVを使ってオプティカルフローをリアルタイムに描画してみます。


オプティカルフロー

オプティカルフローとは、動画において、特徴点のフレームとフレームの差分(ベクトル)を表現する方法です。フレームレートは、通常一定なので、特徴点の速度を表現しているとも言えます。

計算方法は、テンプレートマッチングを用いる方法や特徴点/特徴量を用いる方法があります。

今回は、特徴点を用いてオプティカルフローを描画してみます。流れは以下のようになります。


  1. 前のフレームに対して特徴点を検出します。今回は、Shi-Tomashiの方法を用いて特徴点を検出します。

    cv2.goodFeaturesToTrack() を利用します。

  2. 前フレーム内の特徴点のオプティカルフローを、前フレーム、次フレームの情報を用いて、画像ピラミッド型Lucas-Kanade法で計算します。

    cv2.calcOpticalFlowPyrLK() を利用します。

  3. フレームにオプティカルフローを描画します。

  4. 2と3を繰り返します。


プログラム



  • 動作環境


    • python: 3.5.1

    • OpenCV: 3.1.0



  • 動画データ

    OpenCVに付属しているサンプル動画を利用しました。

      OpenCV\opencv\sources\samples\data\768x576.avi



LucasKande.py

import numpy as np

import cv2

cap = cv2.VideoCapture('768x576.avi')

# Shi-Tomasiのコーナー検出パラメータ
feature_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))

# ランダムに色を100個生成(値0~255の範囲で100行3列のランダムなndarrayを生成)
color = np.random.randint(0, 255, (100, 3))

# 最初のフレームの処理
end_flag, frame = cap.read()
gray_prev = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
feature_prev = cv2.goodFeaturesToTrack(gray_prev, mask = None, **feature_params)
mask = np.zeros_like(frame)

while(end_flag):
# グレースケールに変換
gray_next = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# オプティカルフロー検出
feature_next, status, err = cv2.calcOpticalFlowPyrLK(gray_prev, gray_next, feature_prev, None, **lk_params)

# オプティカルフローを検出した特徴点を選別(0:検出せず、1:検出した)
good_prev = feature_prev[status == 1]
good_next = feature_next[status == 1]

# オプティカルフローを描画
for i, (next_point, prev_point) in enumerate(zip(good_next, good_prev)):
prev_x, prev_y = prev_point.ravel()
next_x, next_y = next_point.ravel()
mask = cv2.line(mask, (next_x, next_y), (prev_x, prev_y), color[i].tolist(), 2)
frame = cv2.circle(frame, (next_x, next_y), 5, color[i].tolist(), -1)
img = cv2.add(frame, mask)

# ウィンドウに表示
cv2.imshow('window', img)

# ESCキー押下で終了
if cv2.waitKey(30) & 0xff == 27:
break

# 次のフレーム、ポイントの準備
gray_prev = gray_next.copy()
feature_prev = good_next.reshape(-1, 1, 2)
end_flag, frame = cap.read()

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


OpenCVなら、特徴点の抽出、オプティカルフローの計算ともに、メソッドを1個呼ぶだけです。

なんて便利な世の中なんでしょう(^^;)


実行結果

実行すると、リアルタイムにオプティカルフローが描画されます。