2013-08-07 50 views
10

我試圖讓移動的人們用C++中的OpenCV跟蹤工作,用攝像頭看着街道和人們移動它。對樣品的視頻我拍,我使用,在這裏看到:http://akos.maroy.hu/~akos/eszesp/MVI_0778.MOVC++ OpenCV:跟蹤街道上的移動人物

我在這個題目讀了,我嘗試了一些事情,包括:

  • 背景檢測和創建輪廓
  • 嘗試使用每個幀一人檢測器來檢測斑點(關鍵點的斑點)
  • 與HOGDescriptor

但這些都不提供一個很好的結果。對於我的示例代碼,請參見下文。對於基於上述視頻的代碼輸出,請參閱: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,嘗試關閉斑點中的洞並獲得更好的結果。但不要期待完美的結果。背景減法是一項困難的操作,您可以花費數小時對給定數據集的微調參數,然後在真實世界中嘗試您的代碼,並且......沒有任何工作。燈光,陰影,背景隨着不感興趣的物體而改變..只是爲了提到一些問題。

所以..不,沒有一種簡單和標準的技術來處理所謂的「blob碎片」或「拆分合並」問題(有時一個人被分割成更多的斑點,有時更多的人被合併成一個單個blob)。再次,它充滿了關於這個論點的科學論文。但有些技術可以處理不完整或雜亂觀測的跟蹤。使用卡爾曼濾波器進行一些不完整的觀察,最簡單的方法就是嘗試推斷系統的實際狀態。 Opencv在這方面有很好的實現。再次,如果您在「卡爾曼濾波器跟蹤」或「GNN數據關聯」上進行搜索,您會發現很多。

如果你想使用一些幾何信息,比如估計一個人的身高等,你可以這樣做,但是你需要攝像頭的校準參數。這意味着它們可用(標準iphone相機的microsoft kinect可用參數)或通過相機校準過程來計算它們。這意味着要下載棋盤圖像,將其打印在紙上,並拍攝一些照片。然後,OpenCV擁有所有校準方法。之後,您需要估計地平面,然後使用一些簡單的渲染項目/未投影方法從2d到3d座標前後移動,並估計3d標準人物的2d邊界框。

「行人跟蹤」的現代方法可以用一些檢測器提取觀察結果。背景減法可以給出一個映射在哪裏試圖檢測到不搜索孔圖像,但在這種情況下斑點檢測是無用的。在OpenCV中,在這種情況下使用得越多的是Haar Adaboost檢測器和HOG檢測器。在某些情況下,HOG檢測器似乎可以提供更好的結果。在OpenCV中已經實現了分類器,其中包括面向Haar的人臉檢測器和用於HOG的人員檢測。您將在OpenCV存儲庫中的cpp和python示例中找到示例。

如果標準檢測失敗(您的視頻尺寸不同或者您必須檢測到除行人之外的其他物體)..您必須訓練您自己的探測器。這意味着收集一些想要檢測的對象的圖像(正樣本)和一些其他圖像(負樣本),並用機器學習技術(如SVN)訓練自己的分類器。再次,谷歌是你的朋友:)

祝你好運!

3

我會創造一個人跟蹤這樣的:

  1. 首先,我們必須初始化的對象。怎麼樣?對象檢測。使用HOG或具有適當模型的級聯分類器(即haarcascade_fullbody.xml)(或將它們一起使用)。

  2. 然後,我們必須跟蹤邊界框內發現的像素。怎麼樣? Match past templates!點子:將一個以上積分爲vector<cv::Mat>並使用mean template進行關聯。

更多的想法:

  • 合併結果:使用探測器作爲最可靠的觀測模型,如果失敗切換到模板匹配。

  • 將背景建模用於濾波器誤報(FP與背景相關性非常好)。

另外,如果您想要基於輪廓的跟蹤,請嘗試在opencv示例文件夾中找到blobtrack_sample.cpp。

1

您缺少跟蹤的「運動模型」組件。卡爾曼/粒子過濾器應該有所幫助。我更喜歡卡爾曼。