title: C++ OpenCV: tracking moving people on the street
body: <p>I'm trying to make moving people tracking work with OpenCV in C++, with a camera looking at a street and people moving about it. for a sample video I shot and I'm using, see here: <a href="http://akos.maroy.hu/~akos/eszesp/MVI_0778.MOV">http://akos.maroy.hu/~akos/eszesp/MVI_0778.MOV</a></p>
  
  <p>I read up on this topic, and I tried a number of things, including:</p>
  
  <ul>
  <li>background detection and creating contours</li>
  <li>try to detect blobs (keypoints for blobs)</li>
  <li>using a people detector for each frame with a HOGDescriptor</li>
  </ul>
  
  <p>but none of these provide a good result. for my sample code, see below. for the output of the code based on the above video, see: <a href="http://akos.maroy.hu/~akos/eszesp/ize.avi">http://akos.maroy.hu/~akos/eszesp/ize.avi</a> . the contours detected against the background are in red, the bounding rectangles of the contours are in green, and the HOG people detector results are in blue.</p>
  
  <p>the specific issues I have are:</p>
  
  <p>background detection and then finding contours seems to work fine, although there are some false positives. but the main drawback is that a lot of times a single person is 'cut up' into multiple contours. is there a simple way to 'join' these together, maybe by an assumed 'ideal' person size, or some other means?</p>
  
  <p>as for the HOG people detector, in my case it very seldomly identifies the real people on the image. what could I be doing wrong there?</p>
  
  <p>all pointers, ideas welcome!</p>
  
  <p>and thus, the code I'm using so far, which is a cust-and-paste glory of various samples I found here and there:</p>
  
  <pre><code>#include&lt;opencv2/opencv.hpp&gt;
  #include&lt;iostream&gt;
  #include&lt;vector&gt;
  
  int main(int argc, char *argv[])
  {
      if (argc &lt; 3) {
          std::cerr &lt;&lt; "Usage: " &lt;&lt; argv[0] &lt;&lt; " in.file out.file" &lt;&lt; std::endl;
          return -1;
      }
  
      cv::Mat frame;
      cv::Mat back;
      cv::Mat fore;
      std::cerr &lt;&lt; "opening " &lt;&lt; argv[1] &lt;&lt; std::endl;
      cv::VideoCapture cap(argv[1]);
      cv::BackgroundSubtractorMOG2 bg;
      //bg.nmixtures = 3;
      //bg.bShadowDetection = false;
  
      cv::VideoWriter output;
      //int ex = static_cast&lt;int&gt;(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 &lt;&lt; "saving to " &lt;&lt; argv[2] &lt;&lt; std::endl;
      output.open(argv[2], ex, cap.get(CV_CAP_PROP_FPS), size, true);
  
      std::vector&lt;std::vector&lt;cv::Point&gt; &gt; 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&lt;std::vector&lt;cv::Point&gt; &gt;    blobContours;
      std::vector&lt;cv::KeyPoint&gt;               keyPoints;
      cv::Mat                                 out;
  
      cv::HOGDescriptor hog;
      hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector());
  
  
      for(;;)
      {
          cap &gt;&gt; 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&lt;std::vector&lt;cv::Point&gt; &gt;::const_iterator it = contours.begin();
          std::vector&lt;std::vector&lt;cv::Point&gt; &gt;::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&lt;cv::Rect&gt; found, found_filtered;
          hog.detectMultiScale(frame, found, 0, cv::Size(8,8), cv::Size(32,32), 1.05, 2);
          for (int i = 0; i &lt; found.size(); ++i) {
              cv::Rect r = found[i];
              int j = 0;
              for (; j &lt; found.size(); ++j) {
                  if (j != i &amp;&amp; (r &amp; found[j]) == r) {
                      break;
                  }
              }
              if (j == found.size()) {
                  found_filtered.push_back(r);
              }
          }
  
          for (int i = 0; i &lt; found_filtered.size(); ++i) {
              cv::Rect r = found_filtered[i];
              cv::rectangle(frame, r.tl(), r.br(), cv::Scalar(255,0,0), 3);
          }
  
  
          output &lt;&lt; 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) &gt;= 0) break;
      }
      return 0;
  }
  </code></pre>