Search code examples
c++opencvobject-detectionopencv3.0

how to track foreground in video and draw rectangle on it


I'm working in a motion detection script that tracking people. I used foreground function MOG2 and it does what I want to do. In the next step, I want to draw a rectangle around moving people but I get an error when I run it.

Are there any ideas on how to fix it?

The error:

OpenCV Error: Bad flag (parameter or structure field) (Unrecognized or unsupported array type) in cvGetMat, file /home/shar/opencv/modules/core/src/array.cpp, line 2494
terminate called after throwing an instance of 'cv::Exception'
  what():  /home/shar/opencv/modules/core/src/array.cpp:2494: error: (-206) Unrecognized or unsupported array type in function cvGetMat

Aborted

This is my code:

    #include <opencv2/opencv.hpp>
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <vector>
    #include <iostream>
    #include <sstream>
    #include <opencv2/video/background_segm.hpp>  
    #include <opencv2/video/background_segm.hpp>
    using namespace std;
    using namespace cv;
    
    
    int main()
    {
       //Openthevideofile
       cv::VideoCapture capture(0);
       cv::Mat frame;
       Mat colored;  
       //foregroundbinaryimage
       cv::Mat foreground;
       int largest_area=0;
       int largest_contour_index=0;
       Rect bounding_rect;
       cv::namedWindow("ExtractedForeground");
       vector<vector<Point> > contours; // Vector for storing contour
       vector<Vec4i> hierarchy;
       findContours( frame, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
       //checkifvideosuccessfullyopened
       if (!capture.isOpened())
         return 0;
       //currentvideoframe
    
       //TheMixtureofGaussianobject
       //used with all default parameters
       cv::Ptr<cv::BackgroundSubtractorMOG2> pMOG2 = cv::createBackgroundSubtractorMOG2();
      
       bool stop(false);
            //  testing the bounding    box 
    
       //forallframesinvideo
       while(!stop){
      //readnextframeifany
        if(!capture.read(frame))
          break;
       //updatethebackground
       //andreturntheforeground
        float learningRate = 0.01; // or whatever
        cv::Mat foreground; 
        pMOG2->apply(frame, foreground, learningRate);
      //learningrate
      //Complementtheimage
        cv::threshold(foreground,foreground,128,255,cv::THRESH_BINARY_INV);
      //showforeground
        for( int i = 0; i< contours.size(); i++ )
        {
            //  Find the area of contour
            double a=contourArea( contours[i],false); 
            if(a>largest_area){
                largest_area=a;cout<<i<<" area  "<<a<<endl;
                // Store the index of largest contour
                largest_contour_index=i;               
                // Find the bounding rectangle for biggest contour
                bounding_rect=boundingRect(contours[i]);
            }
         }
    
        Scalar color( 255,255,255);  // color of the contour in the
        //Draw the contour and rectangle
        drawContours( frame, contours,largest_contour_index, color, CV_FILLED,8,hierarchy);
        rectangle(frame, bounding_rect,  Scalar(0,255,0),2, 8,0);
    
    
        cv::imshow("ExtractedForeground",foreground);
        cv::imshow("colord",colored);
    
      //introduceadelay
      //orpresskeytostop
        if(cv::waitKey(10)>=0)
        stop=true;
      }
     
    
    }

Solution

  • Your code fails because you are calling findContours on frame, which is not initialized until the while loop.

    You have also issues in finding the largest contour, since you don't reset largest_area and largest_contour_index at each iteration, so it will fail in case you don't find a contour in the current frame.

    This code should be what you meant to do. You can find a related answer here. The code here is the port to OpenCV 3.0.0, plus noise removal using morphological open.

    #include <opencv2\opencv.hpp>
    #include <vector>
    
    using namespace cv;
    using namespace std;
    
    int main(int argc, char *argv[])
    {
        Ptr<BackgroundSubtractorMOG2> bg = createBackgroundSubtractorMOG2(500, 16, false);
        VideoCapture cap(0);
        Mat3b frame;
        Mat1b fmask;
        Mat kernel = getStructuringElement(MORPH_RECT, Size(3,3));
    
        for (;;)
        {
            // Capture frame
            cap >> frame;
    
            // Background subtraction
            bg->apply(frame, fmask, -1);
    
            // Clean foreground from noise
            morphologyEx(fmask, fmask, MORPH_OPEN, kernel);
    
            // Find contours
            vector<vector<Point>> contours;
            findContours(fmask.clone(), contours, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
    
            if (!contours.empty())
            {
                // Get largest contour
                int idx_largest_contour = -1;
                double area_largest_contour = 0.0;
    
                for (int i = 0; i < contours.size(); ++i)
                {
                    double area = contourArea(contours[i]);
                    if (area_largest_contour < area)
                    {
                        area_largest_contour = area;
                        idx_largest_contour = i;
                    }
                }
    
                if (area_largest_contour > 200)
                {
                    // Draw
                    Rect roi = boundingRect(contours[idx_largest_contour]);
                    drawContours(frame, contours, idx_largest_contour, Scalar(0, 0, 255));
                    rectangle(frame, roi, Scalar(0, 255, 0));
                }
            }
    
            imshow("frame", frame);
            imshow("mask", fmask);
            if (cv::waitKey(30) >= 0) break;
        }
        return 0;
    }