LoginSignup
101

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-08-04

はじめに

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個呼ぶだけです。
なんて便利な世の中なんでしょう(^^;)

実行結果

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

result1.png

result2.png

result3.png

result4.png

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
101