EnsekiTT Blog

EnsekiTTが書くブログです。

Python+OpenCVでWebカメラの画像中のものをトラッキングする話

こんにちは、えんせきです。
何か処理するって記事を書いたけど、何も処理してなかったので画像の中のものをトラッキングすることにした。

つまりなにしたの?

Python+OpenCVのTracking手法のうちBoosting、MIL、KCF、TLD、MedianFlowの5つを実行してみた。
GOTURNもあるけどこっちはうまく動いていない。単純に学習済のモデルのダウンロードが終わっていない。
f:id:ensekitt:20171222001112g:plain

Trackingとは?

簡単に言うと、目で追い続けるのをコンピュータにやらせようって話。ただ、コンピュータは、画像のどの領域が何であるかとかものは落ちる時下に行くとか慣性の法則とかを知らないので人間が思うよりも難しい。
それを実現する画像処理の方法がOpenCVに6つ実装されている。

OpenCVで使えるTracking

Boosting

AdaBoostで動いている。分類器ベースで実行されていて、新しいフレームが来ると前の写っていた場所の近傍のすべてのピクセル上で分類を実行して、分類器のスコアから新しい場所を検出する
伝統的な手法だけど、今これを採用する理由はあんまりない。

MIL(Multiple Instance Learning)

考え方としてはBoostingにとても近いけど、分類対象の場所の近傍のサンプルについてもいくつか正の場所として扱うことが特徴。外堀が埋まってたら真ん中はトラッキング対象でしょうって感じで扱われているみたい。
ただ今更これを採用する理由もない。

KCF(Kernelized Correlation Filters)

カーネルだって!おらわくわくしてきたぞ!MILの近傍サンプルにはそれぞれ同士でオーバーラップする部分があって、その領域を加味することで性能を上げたらしい。
OpenCV3.1以降であればこれがおすすめ。

TLD(Tracking, learning and detection)

学習と検出によってトラッキングする。これまでに検出した範囲を学習してまた検出するみたい。性質上、似たような他のものとの入れ替わりには引っ張られたりすることがある。ただ、長い間遮られたりするものやスケールが大幅に変わるものには適しているっぽい。

MedianFlow

オブジェクトを時間的に順方向および逆方向の両方で追跡して、これらの軌跡間の差異を測定する。動きが小さくて、遮りがなくて、予測しやすい時(たとえばすごく引きで撮ってる時の車とか。。。)にはすごく向いている。

GOTURN

CNNを使ったトラッキング手法なため、向いているハードウェアに搭載すればとても早いらしい。明るさやスケール
・回転の変化とかにも強い。最強に思えるけど、遮りには弱いらしい。

スペックが許せばTLDとGOTURNの組み合わせが最強なんじゃないかな!って思いました。

実行してみた結果

f:id:ensekitt:20171222000908p:plain
Webカメラがよしなに明るさを変更すると結構外れやすかったりする。
領域は広い方がトラッキングし続けてくれるけど、計算に時間がかかってFPSは落ちがち。
当たり前といえば当たり前だけど、検出するものの選択を自分でやらなければならない。
Yolo v2とかで矩形にしてからターゲットを選んでトラッキングするとかやりたくなる。

実装例

import cv2

def frame_resize(frame, n=2):
    """
    スクリーンショットを撮りたい関係で1/4サイズに縮小
    """
    return cv2.resize(frame, (int(frame.shape[1]/2), int(frame.shape[0]/2)))

if __name__ == '__main__':
    """
    Tracking手法を選ぶ。適当にコメントアウトして実行する。
    """
    # Boosting
    # tracker = cv2.TrackerBoosting_create()

    # MIL
    # tracker = cv2.TrackerMIL_create()

    # KCF
    tracker = cv2.TrackerKCF_create()

    # TLD #GPUコンパイラのエラーが出ているっぽい
    # tracker = cv2.TrackerTLD_create()

    # MedianFlow
    # tracker = cv2.TrackerMedianFlow_create()

    # GOTURN # モデルが無いよって怒られた
    # https://github.com/opencv/opencv_contrib/issues/941#issuecomment-343384500
    # https://github.com/Auron-X/GOTURN-Example
    # http://cs.stanford.edu/people/davheld/public/GOTURN/trained_model/tracker.caffemodel
    # tracker = cv2.TrackerGOTURN_create()

    cap = cv2.VideoCapture(1)

    while True:
        ret, frame = cap.read()
        if not ret:
            continue
        frame = frame_resize(frame)
        bbox = (0,0,10,10)
        bbox = cv2.selectROI(frame, False)
        ok = tracker.init(frame, bbox)
        cv2.destroyAllWindows()
        break

    while True:
        # VideoCaptureから1フレーム読み込む
        ret, frame = cap.read()
        frame = frame_resize(frame)
        if not ret:
            k = cv2.waitKey(1)
            if k == 27 :
                break
            continue

        # Start timer
        timer = cv2.getTickCount()

        # トラッカーをアップデートする
        track, bbox = tracker.update(frame)

        # FPSを計算する
        fps = cv2.getTickFrequency() / (cv2.getTickCount() - timer);

        # 検出した場所に四角を書く
        if track:
            # Tracking success
            p1 = (int(bbox[0]), int(bbox[1]))
            p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
            cv2.rectangle(frame, p1, p2, (0,255,0), 2, 1)
        else :
            # トラッキングが外れたら警告を表示する
            cv2.putText(frame, "Failure", (10,50), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 1, cv2.LINE_AA);

        # FPSを表示する
        cv2.putText(frame, "FPS : " + str(int(fps)), (10,20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 1, cv2.LINE_AA);

        # 加工済の画像を表示する
        cv2.imshow("Tracking", frame)

        # キー入力を1ms待って、k が27(ESC)だったらBreakする
        k = cv2.waitKey(1)
        if k == 27 :
            break

# キャプチャをリリースして、ウィンドウをすべて閉じる
cap.release()
cv2.destroyAllWindows()
クリエイティブ・コモンズ・ライセンス
この 作品 は クリエイティブ・コモンズ 表示 4.0 国際 ライセンスの下に提供されています。