2013-08-07 20 views
10

OpenCVでC++で移動する人を追跡するようにしています。私が撃たれ、私が使用しているサンプルビデオのために、ここを参照してください:http://akos.maroy.hu/~akos/eszesp/MVI_0778.MOVC++ OpenCV:通りに移動する人を追跡する

私はこのトピックをよく読んで、私を含む多くのこと、試してみました:

  • 背景検出と輪郭
  • を作成します
  • HOGDescriptor

でフレームごとに人々の検出器を使用して、ブロブ(BLOBのキーポイント)

  • を検出しようとするが、これらはいずれも優れた結果を提供しません。私のサンプルコードは、以下を参照してください。上記のビデオに基づくコードの出力については、http://akos.maroy.hu/~akos/eszesp/ize.aviを参照してください。背景に対して検出された輪郭は赤色であり、輪郭の境界の長方形は緑色であり、HOG人検出器の結果は青色である。私が持っている

    具体的な問題は、次のとおりです。いくつかの偽陽性があるが

    背景検出し、次に見つけ輪郭は、正常に動作するようです。主な欠点は、一人の人間が複数の輪郭に「切り取られて」いることです。これらを一緒に「結合」する簡単な方法がありますか?おそらく、想定される「理想」人のサイズ、または他の手段によってですか?

    私の場合、HOG人検出器に関しては、画像上の実際の人物を非常にめったに識別しません。私は何が間違っていますか?

    すべてのアイデア、歓迎!

    ので、私はあちこち見られる様々なサンプルのカストアンドペースト栄光である、これまで使っていたコード:

    #include<opencv2/opencv.hpp> 
    #include<iostream> 
    #include<vector> 
    
    int main(int argc, char *argv[]) 
    { 
        if (argc < 3) { 
         std::cerr << "Usage: " << argv[0] << " in.file out.file" << std::endl; 
         return -1; 
        } 
    
        cv::Mat frame; 
        cv::Mat back; 
        cv::Mat fore; 
        std::cerr << "opening " << argv[1] << std::endl; 
        cv::VideoCapture cap(argv[1]); 
        cv::BackgroundSubtractorMOG2 bg; 
        //bg.nmixtures = 3; 
        //bg.bShadowDetection = false; 
    
        cv::VideoWriter output; 
        //int ex = static_cast<int>(cap.get(CV_CAP_PROP_FOURCC)); 
        int ex = CV_FOURCC('P','I','M','1'); 
        cv::Size size = cv::Size((int) cap.get(CV_CAP_PROP_FRAME_WIDTH), 
              (int) cap.get(CV_CAP_PROP_FRAME_HEIGHT)); 
        std::cerr << "saving to " << argv[2] << std::endl; 
        output.open(argv[2], ex, cap.get(CV_CAP_PROP_FPS), size, true); 
    
        std::vector<std::vector<cv::Point> > contours; 
    
        cv::namedWindow("Frame"); 
        cv::namedWindow("Fore"); 
        cv::namedWindow("Background"); 
    
    
        cv::SimpleBlobDetector::Params params; 
        params.minThreshold = 40; 
        params.maxThreshold = 60; 
        params.thresholdStep = 5; 
        params.minArea = 100; 
        params.minConvexity = 0.3; 
        params.minInertiaRatio = 0.01; 
        params.maxArea = 8000; 
        params.maxConvexity = 10; 
        params.filterByColor = false; 
        params.filterByCircularity = false; 
    
    
        cv::SimpleBlobDetector blobDtor(params); 
        blobDtor.create("SimpleBlob"); 
    
        std::vector<std::vector<cv::Point> > blobContours; 
        std::vector<cv::KeyPoint>    keyPoints; 
        cv::Mat         out; 
    
        cv::HOGDescriptor hog; 
        hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector()); 
    
    
        for(;;) 
        { 
         cap >> frame; 
    
         bg.operator()(frame, fore); 
    
         bg.getBackgroundImage(back); 
         cv::erode(fore, fore, cv::Mat()); 
         cv::dilate(fore, fore, cv::Mat()); 
    
         blobDtor.detect(fore, keyPoints, cv::Mat()); 
    
         //cv::imshow("Fore", fore); 
    
         cv::findContours(fore, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); 
         cv::drawContours(frame, contours, -1, cv::Scalar(0,0,255), 2); 
    
         std::vector<std::vector<cv::Point> >::const_iterator it = contours.begin(); 
         std::vector<std::vector<cv::Point> >::const_iterator end = contours.end(); 
         while (it != end) { 
          cv::Rect bounds = cv::boundingRect(*it); 
          cv::rectangle(frame, bounds, cv::Scalar(0,255,0), 2); 
    
          ++it; 
         } 
    
         cv::drawKeypoints(fore, keyPoints, out, CV_RGB(0,255,0), cv::DrawMatchesFlags::DEFAULT); 
         cv::imshow("Fore", out); 
    
    
         std::vector<cv::Rect> found, found_filtered; 
         hog.detectMultiScale(frame, found, 0, cv::Size(8,8), cv::Size(32,32), 1.05, 2); 
         for (int i = 0; i < found.size(); ++i) { 
          cv::Rect r = found[i]; 
          int j = 0; 
          for (; j < found.size(); ++j) { 
           if (j != i && (r & found[j]) == r) { 
            break; 
           } 
          } 
          if (j == found.size()) { 
           found_filtered.push_back(r); 
          } 
         } 
    
         for (int i = 0; i < found_filtered.size(); ++i) { 
          cv::Rect r = found_filtered[i]; 
          cv::rectangle(frame, r.tl(), r.br(), cv::Scalar(255,0,0), 3); 
         } 
    
    
         output << frame; 
    
         cv::resize(frame, frame, cv::Size(1280, 720)); 
         cv::imshow("Frame", frame); 
    
         cv::resize(back, back, cv::Size(1280, 720)); 
         cv::imshow("Background", back); 
    
    
    
         if(cv::waitKey(30) >= 0) break; 
        } 
        return 0; 
    } 
    
  • 答えて

    3

    あなたが読む人のトラッカーを見たことがあります。これは研究プロジェクトでしたが、オープンソースであり、非常に効果的です。 here

    これはおそらく最先端ではないかもしれませんが、ソースは入手可能であり、非常にうまく構成されています。

    10

    実際は、非常に広い話題です。この問題を攻撃しようとする科学論文はたくさんあります。あなたは前に何かを読むべきです。

    簡単に: 背景検出と輪郭が最も簡単な手法です。 OpenCVはgpu用に最適化された非常に素晴らしい実装を持っています。フォアグラウンド/バックグラウンドブロブを改良するには、morphological operation,ブロブの穴を閉じてより良い結果を得るようにしてください。しかし、完璧な結果を期待しないでください。バックグラウンドの減算は難しい操作です。与えられたデータセットのパラメータを微調整するのに何時間も費やすことができますし、実世界でコードを試してみてください。ライト、シャドウ、無関係なオブジェクトによる背景の変更..何らかの問題を言及するだけです。

    いわゆる「ブロブフラグメンテーション」や「スプリットマージ」問題を処理するための単純で標準的な手法はありません(ある人はより多くのブロブに分割されることがあります。単一ブロブ)。再び、この議論に関する科学的論文がいっぱいです。しかし、不完全またはクラッタ観測の追跡を扱う技術があります。最も簡単な方法の1つは、カルマンフィルタによる不完全な観測を考慮して、システムの実際の状態を推測することです。 Opencvはその上で素晴らしい実装をしています。もう一度、 "Kalman filter tracking"や "GNN data association"の検索をすると、たくさん見つかるでしょう。

    人物の高さなどを推定するなどの幾何学的情報を使用したい場合は、カメラの較正パラメータが必要です。それは、それらが利用可能であることを意味する(標準的なiphoneカメラのマイクロソフトキネクトは利用可能なパラメータを持っている)か、カメラ較正プロセスを通してそれらを計算することを意味する。これは、チェス盤画像をダウンロードして紙に印刷し、写真を撮ることを意味します。 OpenCVには、校正を行うためのすべての方法があります。その後、地面を見積もり、2次元から3次元への座標変換を行うための単純なレンダープロジェクト/アンプロジェクトメソッドを使用して、3次元標準人物の2次元境界ボックスを推定する必要があります。

    「歩行者追跡」に関する現代のアプローチは、ある検出器での観測を抽出します。バックグラウンド減算は、穴の画像を検索しないように検出しようとする場所にマップを与えることができるが、この場合、ブロブの検出は役に立たない。 OpenCVでは、Haar Adaboost検出器とHOG検出器が使用されています.HOG検出器は、場合によってはより良い結果をもたらすようです。すでにOpenCVのクラシファイアには、Haarの顔検出機能とHOG検出機能があります。 OpenCVリポジトリのcppサンプルとpythonサンプルの両方にサンプルがあります。

    標準の検出に失敗した場合(ビデオのサイズが違う、または歩行者以外の物体を検出する必要がある場合)、自分の検出器を訓練する必要があります。つまり、検出したいオブジェクトの画像(ポジティブサンプル)と何か他の画像(ネガティブサンプル)を収集し、SVNのような機械学習技術で独自の分類子を訓練することを意味します。もう一度、Googleはあなたの友人です:)

    幸運!

    3

    私はこのような人間トラッカー作成します。

    1. まず、我々は、オブジェクトを初期化する必要があります。どうやって?オブジェクト検出。適切なモデル(つまり、haarcascade_fullbody.xml)とともにHOGまたはカスケード分類子を使用します(またはそれらをすべて一緒に使用します)。

    2. 次に、バウンディングボックス内にあるピクセルをTRACKする必要があります。どうやって? Match past templates!考え:vector<cv::Mat>に1つ以上を累積し、相関のためにmean templateを使用してください。

    その他のアイデア:

    • 結果を組み合わせる:最も信頼性の高い観測モデルとして検出器を使用し、それが失敗した場合、テンプレートマッチングに切り替えます。

    • バックグラウンドモデリングを使用して、偽陽性(FPsはバックグラウンドと優れた相関性があります)をファイリングします。

    また、輪郭に基づくトラッキングが必要な場合は、opencvサンプルフォルダにあるblobtrack_sample.cppを試してみてください。

    1

    トラッキングの「モーションモデル」コンポーネントがありません。カルマン/粒子フィルターが役立つはずです。私はカルマンを好む。

    関連する問題