Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Based on the info and the images that you added (they're not the best ones...), my first approach would be the following:

  1. For a 1-lane road, define two windows (entry and exit areas)
  2. Capture a frame, apply background subtraction and get the foreground mask (moving objects)
  3. Monitor moving objects over the previous windows: first, consider there's a moving object in the window if there a more than certain number of white pixels in the window (any other criteria may be valid); second, consider that a car entered/exited the road if it is detected over certain consecutive number of frames (it is required to know the mean speed of the vehicles to approximate the mean number of frames the car will be in the window).
  4. Update corresponding counters: total number of cars = cars that entered - cars that exited

Additional features/steps may be implemented:

  • Morphology operations (erode, dilate) on the foreground mask
  • "Timers": define a minimum and/or maximum time to cross the road (to pass between the entry and the exit window). This will prevent false detections (for example, you detect a car at frame 14. If 50 frames later (maximum time to cross) you haven't detected a car exiting, automatically decrease by 1 the number of cars)

Limitations - this approach won't work properly or won't work at all if:

  • There is not enough movement (traffic jams, traffic lights in the path, possibility to park in that road)
  • Longer vehicles than expected enter the road. For example, a truck is likely to be counted as 2 different cars

Some very basic code to start from might be the following (haven't tested it). Of course you will need to tweak parameters and see what works and what does not.

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/video/video.hpp>
#include <iostream>

using namespace cv;
using namespace std;

void main(){
    VideoCapture cap(0);
    BackgroundSubtractorMOG2 mog;
    Mat frame, foreground;

    //Define counting windows
    Rect in_window = Rect(x1, y1, width1, height1);       //fill with coordinates of entry window
    Rect out_window = Rect(x2, y2, width2, height2);     //fill with coordinates of exit window

    //Initialize counters
    int numberCars = 0;         //total number of cars in a frame
    int numberFramesIn = 0;     //number of consecutive frames a car is detected in the entry window 
    int numberFramesOut = 0;    //number of consecutive frames a car is detected in the exit window 

    while (true){
        cap >> frame;               //capture frame
        mog(frame, foreground);     //get and store foreground mask (moving objects)

        //--For entry window--
        int whitePixels = countNonZero(foreground(in_window));  //Count white pixels in window
        //If number is higher than a threshold, a car is in the window (here a car is detected 
        //if more than the 80% of the window is white. You can play around/choose any other criteria)
        if (whitePixels > (0.8 * in_window.width * in_window.height)){
            numberFramesIn++;           //update counter
            //If a car is detected over 3 (or whatever) consecutive frames, then it entered the road
            if (numberFramesIn > 3){    
                numberCars++;
            }
        }
        else {                      //If a car is not detected in the window, reset counter
            numberFramesIn = 0;
        }

        //--For exit window - similar behavior--
        whitePixels = countNonZero(foreground(out_window));
        if (whitePixels > (0.8 * out_window.width * out_window.height)){
            numberFramesOut++;
            if (numberFramesOut > 3 && numberCars > 0){     //careful: never less than 0 cars
                numberCars--;
            }
        }
        else {
            numberFramesOut = 0;
        }

        cout << "Total number of cars in frame: " << numberCars << endl;
    }
}