Sosogu LLC. Blog

Sosogu LLC. のブログ https://sosogu.net

Neural Networkベースのトラッキング手法GOTURNを使ってみる

はじめに

ラッキングとは簡単に言うと、カメラに写っている対象のオブジェクトを追跡して行くことです。マシンビジョンの世界では人間の行動解析や交通システム等で使用されている技術です。
実は昔、GOTURNはOpenCV3.2で試してみたのですが、その時はバグがあってうまく動きませんでした。
先日、既存のトラッキング手法プレビューしていて、ふとGOTURN思い出したので、今度はOpenCV3.4で試してみます。

実行環境

実行環境は以下の通りです。
C++
OpenCV: 3.4 + OpenCV_Contrib 3.4
OS: Ubuntu16.04
CPU: corei7-7700K
OpenCVは各自の環境に合わせてインストールしてください。

Pre-Trained モデルの入手

これはOpenCV-extraと言うモジュールの中にあります。
https://github.com/opencv/opencv_extra/tree/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking

4つのZipファイルとファイルをgoturn.prototxtダウンロードします。
その後、以下のコマンドでZipファイルを1つに統合します。

cat goturn.caffemodel.zip* > goturn.caffemodel.zip

そして、ZIPファイルを以下のコマンドで解凍します。

unzip goturn.caffemodel.zip

goturn.caffemodelとgoturn.prototxtは実行フォルダに移動してください。

実行

顔をトラッキングした結果です。


うまく、トラッキングしていますね。

GOTURNの問題として、複数のトラッキングが出来ません。また、オクルージョンに対応していないので、木や建物でオブジェクトが遮られるとうまくトラッキング出来ないことがあります。
しかし、それ以外の場合は非常にロバストなトラッキングが行えます。

ソースコード
今回のデモのソースコードです。

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/tracking.hpp>
#include <opencv2/core/ocl.hpp>
 
using namespace cv;
using namespace std;
 
// Convert to string
#define SSTR( x ) static_cast< std::ostringstream & >( \
( std::ostringstream() << std::dec << x ) ).str()
 
int main()
{
 
    // Create a tracker
    Ptr<Tracker> tracker = TrackerGOTURN::create();
 
    // Read video
    VideoCapture video("/path/to/video");
 
    // Exit if video is not opened
    if(!video.isOpened()){
        cout << "Could not read video file" << endl;
        return 1;
 
    }
 
    // Read first frame
    Mat frame;
    bool ok = video.read(frame);
 
    // Define initial boundibg box
    Rect2d bbox(287, 23, 86, 320);
 
    // Uncomment the line below to select a different bounding box
    bbox = selectROI(frame, false);
 
    // Display bounding box.
    rectangle(frame, bbox, Scalar( 255, 0, 0 ), 2, 1 );
    imshow("Tracking", frame);
 
 
    tracker->init(frame, bbox);
 
    while(video.read(frame)){
        // Start timer
        double timer = (double)getTickCount();
 
        // Update the tracking result
        bool ok = tracker->update(frame, bbox);
 
        // Calculate Frames per second (FPS)
        float fps = getTickFrequency() / ((double)getTickCount() - timer);
 
        if (ok){
            // Tracking success : Draw the tracked object
            rectangle(frame, bbox, Scalar( 255, 0, 0 ), 2, 1 );
        }else{
            // Tracking failure detected.
            putText(frame, "Tracking failure detected", Point(100,80), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0,0,255),2);
        }
 
        // Display tracker type on frame
        putText(frame, trackerType + " Tracker", Point(100,20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(50,170,50),2);
 
        // Display FPS on frame
        putText(frame, "FPS : " + SSTR(int(fps)), Point(100,50), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(50,170,50), 2);
 
        // Display frame.
        imshow("Tracking", frame);
        
        // Exit if ESC pressed.
        int k = waitKey(1);
        if(k == 27){
            break;
        }
    }
}

まとめ
正直、実際の現場でトラッキングを行う場合にはGOTURNでは十分ではありません。
と言うのも、人間や車のトラッキングは複雑な環境(木や建物によってオブジェクトが見えなくなる箇所がある)で行うことが多く、対象も複数になる場合がほとんどだからです。
弊社でも、YOLOやSSDで物体認識した後に独自のトラッキング手法を組み合わせて実際の現場で使用しています。
しかし、手軽にNNベースのトラッキングを試したい場合には良い選択ではないでしょうか。