title: Multiple Object Tracking with Kalman Filter
body: <p>I am new on OpenCV. I am always wish to learn new image processing technologies / Programming. I have seen few tutorial on Object detection, tracking, counting etc. 
  I wish to learn the same and try to make my own similar project. </p>
  
  <p>With lot of searching on internet and papers. Finally i came to know about Kalman Filter for object tracking. I have used following codes as per following:</p>
  
  <ol>
  <li>Background Subtract</li>
  <li>Smoothing , Blur  etc. filters. </li>
  <li>Find Contours </li>
  <li>Draw Rectangle and find Centroid. </li>
  <li>Apply Kalman Filter </li>
  </ol>
  
  <p>Now, i can track ONE Object with my codes. I want to track multiple objects.(i.e. people running on the roads, vehicle running etc.) </p>
  
  <p>I would be pleased and appreciate if someone can guide me or give me example codes to try with. </p>
  
  <p>Looking forward your positive reply. 
  Shan</p>
  
  <pre><code>using namespace std;
  using namespace cv;
  
  #define drawCross( img, center, color, d )\
  line(img, Point(center.x - d, center.y - d), Point(center.x + d, center.y + d), color, 2, CV_AA, 0);\
  line(img, Point(center.x + d, center.y - d), Point(center.x - d, center.y + d), color, 2, CV_AA, 0 )\
  
  vector&lt;Point&gt; mousev,kalmanv;
  
  
  cv::KalmanFilter KF;
  cv::Mat_&lt;float&gt; measurement(2,1); 
  Mat_&lt;float&gt; state(4, 1); // (x, y, Vx, Vy)
  int incr=0;
  
  
  void initKalman(float x, float y)
  {
      // Instantate Kalman Filter with
      // 4 dynamic parameters and 2 measurement parameters,
      // where my measurement is: 2D location of object,
      // and dynamic is: 2D location and 2D velocity.
      KF.init(4, 2, 0);
  
      measurement = Mat_&lt;float&gt;::zeros(2,1);
      measurement.at&lt;float&gt;(0, 0) = x;
      measurement.at&lt;float&gt;(0, 0) = y;
  
  
      KF.statePre.setTo(0);
      KF.statePre.at&lt;float&gt;(0, 0) = x;
      KF.statePre.at&lt;float&gt;(1, 0) = y;
  
      KF.statePost.setTo(0);
      KF.statePost.at&lt;float&gt;(0, 0) = x;
      KF.statePost.at&lt;float&gt;(1, 0) = y; 
  
      setIdentity(KF.transitionMatrix);
      setIdentity(KF.measurementMatrix);
      setIdentity(KF.processNoiseCov, Scalar::all(.005)); //adjust this for faster convergence - but higher noise
      setIdentity(KF.measurementNoiseCov, Scalar::all(1e-1));
      setIdentity(KF.errorCovPost, Scalar::all(.1));
  }
  
  Point kalmanPredict() 
  {
      Mat prediction = KF.predict();
      Point predictPt(prediction.at&lt;float&gt;(0),prediction.at&lt;float&gt;(1));
  
      KF.statePre.copyTo(KF.statePost);
      KF.errorCovPre.copyTo(KF.errorCovPost);
  
      return predictPt;
  }
  
  Point kalmanCorrect(float x, float y)
  {
      measurement(0) = x;
      measurement(1) = y;
      Mat estimated = KF.correct(measurement);
      Point statePt(estimated.at&lt;float&gt;(0),estimated.at&lt;float&gt;(1));
      return statePt;
  }
  
  int main()
  {
    Mat frame, thresh_frame;
    vector&lt;Mat&gt; channels;
    VideoCapture capture;
    vector&lt;Vec4i&gt; hierarchy;
    vector&lt;vector&lt;Point&gt; &gt; contours;
  
     // cv::Mat frame;
      cv::Mat back;
      cv::Mat fore;
      cv::BackgroundSubtractorMOG2 bg;
  
      bg.nmixtures = 3;
      bg.bShadowDetection = false;
      int incr=0;
      int track=0;
  
      capture.open("E:/demo1.avi");
  
    if(!capture.isOpened())
      cerr &lt;&lt; "Problem opening video source" &lt;&lt; endl;
  
  
    mousev.clear();
    kalmanv.clear();
  
  initKalman(0, 0);
  
    while((char)waitKey(1) != 'q' &amp;&amp; capture.grab())
      {
  
     Point s, p;
  
    capture.retrieve(frame);
  
          bg.operator ()(frame,fore);
          bg.getBackgroundImage(back);
          erode(fore,fore,Mat());
          erode(fore,fore,Mat());
          dilate(fore,fore,Mat());
          dilate(fore,fore,Mat());
          dilate(fore,fore,Mat());
          dilate(fore,fore,Mat());
          dilate(fore,fore,Mat());
          dilate(fore,fore,Mat());
          dilate(fore,fore,Mat());
  
          cv::normalize(fore, fore, 0, 1., cv::NORM_MINMAX);
          cv::threshold(fore, fore, .5, 1., CV_THRESH_BINARY);
  
  
        split(frame, channels);
        add(channels[0], channels[1], channels[1]);
        subtract(channels[2], channels[1], channels[2]);
        threshold(channels[2], thresh_frame, 50, 255, CV_THRESH_BINARY);
        medianBlur(thresh_frame, thresh_frame, 5);
  
  //       imshow("Red", channels[1]);
        findContours(fore, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
        vector&lt;vector&lt;Point&gt; &gt; contours_poly( contours.size() );
        vector&lt;Rect&gt; boundRect( contours.size() );
  
        Mat drawing = Mat::zeros(thresh_frame.size(), CV_8UC1);
        for(size_t i = 0; i &lt; contours.size(); i++)
          {
  //          cout &lt;&lt; contourArea(contours[i]) &lt;&lt; endl;
            if(contourArea(contours[i]) &gt; 500)
              drawContours(drawing, contours, i, Scalar::all(255), CV_FILLED, 8, vector&lt;Vec4i&gt;(), 0, Point());
          }
        thresh_frame = drawing;
  
        findContours(fore, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
  
        drawing = Mat::zeros(thresh_frame.size(), CV_8UC1);
        for(size_t i = 0; i &lt; contours.size(); i++)
          {
  //          cout &lt;&lt; contourArea(contours[i]) &lt;&lt; endl;
            if(contourArea(contours[i]) &gt; 3000)
              drawContours(drawing, contours, i, Scalar::all(255), CV_FILLED, 8, vector&lt;Vec4i&gt;(), 0, Point());
        }
        thresh_frame = drawing;
  
  // Get the moments
        vector&lt;Moments&gt; mu(contours.size() );
        for( size_t i = 0; i &lt; contours.size(); i++ )
        { 
            mu[i] = moments( contours[i], false ); }
  
  //  Get the mass centers:
        vector&lt;Point2f&gt; mc( contours.size() );
        for( size_t i = 0; i &lt; contours.size(); i++ ) 
  
        { 
            mc[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); 
  
  
       /*  
        for(size_t i = 0; i &lt; mc.size(); i++)
          {
  
       //       drawCross(frame, mc[i], Scalar(255, 0, 0), 5);
            //measurement(0) = mc[i].x;
            //measurement(1) = mc[i].y;
  
  
  //        line(frame, p, s, Scalar(255,255,0), 1);
  
  //          if (measurement(1) &lt;= 130 &amp;&amp; measurement(1) &gt;= 120) {
    //            incr++;          
      //         cout &lt;&lt; "Conter " &lt;&lt; incr &lt;&lt; " Loation " &lt;&lt; measurement(1) &lt;&lt; endl;
        //   }
        }*/
        }
  
  
          for( size_t i = 0; i &lt; contours.size(); i++ )
         { approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
           boundRect[i] = boundingRect( Mat(contours_poly[i]) );
  
       }
  
                p = kalmanPredict();
  //        cout &lt;&lt; "kalman prediction: " &lt;&lt; p.x &lt;&lt; " " &lt;&lt; p.y &lt;&lt; endl;
            mousev.push_back(p);
  
        for( size_t i = 0; i &lt; contours.size(); i++ )
         {
             if(contourArea(contours[i]) &gt; 1000){
           rectangle( frame, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 2, 8, 0 );
          Point center = Point(boundRect[i].x + (boundRect[i].width /2), boundRect[i].y + (boundRect[i].height/2));
          cv::circle(frame,center, 8, Scalar(0, 0, 255), -1, 1,0);
  
  
  
           s = kalmanCorrect(center.x, center.y);
          drawCross(frame, s, Scalar(255, 255, 255), 5);
  
          if (s.y &lt;= 130 &amp;&amp; p.y &gt; 130 &amp;&amp; s.x &gt; 15) {
              incr++;
               cout &lt;&lt; "Counter " &lt;&lt; incr &lt;&lt; endl;
             }
  
  
               for (int i = mousev.size()-20; i &lt; mousev.size()-1; i++) {
                   line(frame, mousev[i], mousev[i+1], Scalar(0,255,0), 1);
                   }
  
                }
         }
  
  
        imshow("Video", frame);
        imshow("Red", channels[2]);
        imshow("Binary", thresh_frame);
      }
    return 0;
  }
  </code></pre>