Surinder ツ
Surinder ツ

Reputation: 1788

How to measure moving vehicle speed using Background Subtraction in OpenCv

I am using background subtraction for detecting moving vehicles in OpenCV.
The moving object is detected and a rectangle is created around the detected object. I input the video having moving objects in it.

The issue is :
I don't know how to calculate the moving object speed. I tried searching over forums, Google, StackOverflow but didn't got any idea on how to calculate the speed.

I want to implement the same as it is implemented in this YouTube video

Here is my code:

BgDetection.cpp

#include "BgDetection.h"
int BgDetection1();
using namespace cv;

int BgDetection1()
{
    cv::Mat frame;
    cv::Mat back;
    cv::Mat fore;
    CvSeq* seq;
    cv::VideoCapture cap("D:/Eclipse/bglib/video2.avi");
    cap >> frame;
    cv::initModule_video();
    cv::BackgroundSubtractorMOG2 bg(100, 16, true); // history is an int, distance_threshold is an int (usually set to 16), shadow_detection is a bool
    bg.set("nmixtures", 3);
    bg(frame, fore, -1); //learning_rate = -1 here
    std::vector<std::vector<cv::Point> > contours;
    cv::namedWindow("Frame");
    cv::namedWindow("Background");

    for(;;)
    {
        cap >> frame;
        bg.operator ()(frame,fore);
        bg.getBackgroundImage(back);
        cv::erode(fore,fore,cv::Mat());
        cv::dilate(fore,fore,cv::Mat());
        std::vector<cv::Vec4i> hierarchy;

        cv::findContours( fore, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, cvPoint(600,200));

        for ( size_t i=0; i<contours.size(); ++i )
        {
            cv::drawContours( frame, contours, i, Scalar(200,0,0), 1, 8, hierarchy, 0, Point() );
            cv::Rect brect = cv::boundingRect(contours[i]);
            cv::rectangle(frame, brect, Scalar(255,0,0));
        }
        //cv::drawContours(frame,contours,-1,cv::Scalar(0,0,255),2);
        cv::imshow("Frame",frame);
        cv::imshow("Background",back);
        if(cv::waitKey(30) >= 0) break;
    }
    return 0;
}

BgDetection.h

#ifndef BGDETECTION_H_INCLUDED
#define BGDETECTION_H_INCLUDED

#include <iostream>
#include <sys/stat.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include <opencv/cv.h>
#include "opencv2/features2d/features2d.hpp"
#include <opencv/highgui.h>
#include "opencv2/opencv.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/nonfree/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include  <vector>
#pragma comment (lib , "opencv_core244d.lib")
#pragma comment (lib ,"opencv_highgui244d.lib")
#pragma comment(lib , "opencv_imgproc244d.lib")
#pragma comment(lib ,"opencv_video244.lib")

int BgDetection1();

#endif // BGDETECTION_H_INCLUDED

main.cpp

#include <iostream>
#include "BgDetection.h"

using namespace std;

int main()
{
    cout << BgDetection1() << endl;
    return 0;
}

Any help appreciated.

Upvotes: 1

Views: 6499

Answers (1)

jmetz
jmetz

Reputation: 12773

Single object

If you are tracking a single rectangle around your moving object, the rectangle has a unique centre in each frame.

The difference between the centre positions could potentially be used to generate instantaneous velocity vectors.

My memory of opencv syntax in c++ is a bit rusty, but something along the lines of

// outside t-loop
cap >> frame;
bg.operator ()(frame,fore);
bg.getBackgroundImage(back);
cv::erode(fore,fore,cv::Mat());
cv::dilate(fore,fore,cv::Mat());
std::vector<cv::Vec4i> hierarchy;
cv::findContours( fore, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
int i =0;
cv::drawContours( frame, contours, i, Scalar(200,0,0), 1, 8, hierarchy, 0, Point() );
cv::Rect rectold = cv::boundingRect(contours[i]);
cv::rectangle(frame, rectold, Scalar(255,0,0));

//cv::drawContours(frame,contours,-1,cv::Scalar(0,0,255),2);
cv::imshow("Frame",frame);
cv::imshow("Background",back);
if(cv::waitKey(30) >= 0) break;


    // Within t-loop
    cv::Rect newrect = cv::boundingRect(contours[i]);
    double vx = newrect.x - oldrect.x;
    double vy = newrect.y - oldrect.y;
    oldrect = newrect;

Multiple object

If you have multiple objects, you could generate a point list for the objects in frame t and t+1 and then do point set matching on the two point sets.

Depending on the tracking complexity I'd suggest

  • a simple nearest neighbour matching if the assignment is essentially trivial
  • Global nearest neighbours (e.g. Jonkers-Volgenant http://www.assignmentproblems.com/LAPJV.htm) for something more difficult
  • If that still doesn't work you'll probably have to delve into state estimation (see the Kalman filter for a basic example) and devise a cost function before calling LAPJV.

Upvotes: 1

Related Questions