Detect Basic Change in Video using OpenCV

Trying to recreate a basic change detection program I got from a great blog done by Adrian Rosebrock (if looking to get into python and OpenCV go here). The code was designed in python and I am trying to convert it to C++. You can find the blog post here. My struggle is with the absdiff(firsFrame, gray, imageDifference) as every iteration of the loop has firstFrame and gray being equal. I think the problem is either where I initialize firstFrame = gray but I did a cout check to see how many times it is hit so not sure. Here is code:

int min_area = 500; //min area of motion detectable

//get camera operational and make sure working correctly
VideoCapture camera(0);
if(!camera.isOpened()){
    cout << "cannot open camera" << endl;
    return(1);
}

Mat firstFrame, gray, imageDifference, thresh;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;


while(true){
    Mat frame;
    camera.read(frame);
    if(frame.empty()){
        cout << "frame was not captured" << endl;
        return(2);
    }
    //pre processing
    //resize(frame, frame, Size (1200,900));
    cvtColor(frame, gray, COLOR_BGR2GRAY);
    GaussianBlur(gray, gray, Size( 21, 21 ), 0, 0 );

    //initrialize first frame if necessary
    if(firstFrame.empty()){
        cout << "hit" << endl;
        firstFrame = gray;
        continue;
    }

    //get difference
    absdiff(firstFrame, gray, imageDifference);
    threshold(imageDifference, thresh, 25, 255, THRESH_BINARY);
    //fill in holes
    dilate(thresh, thresh, Mat(), Point(-1, -1), 2, 1, 1);
    findContours(thresh, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

    //loop over contours
    for(int i = 0; i < contours.size(); i++){
        //get the boundboxes and save the ROI as an Image
        if (contourArea(contours[i]) < min_area){
            continue;
        }
        Rect boundRect = boundingRect( Mat(contours[i]));
        rectangle( frame, boundRect.tl(), boundRect.br(), (0,255,0), 1, 8, 0 );

    }
    //draw everything
    imshow("Security feed", frame);
    imshow("Thresh", thresh);
    imshow("Difference", imageDifference);
    if (waitKey(30) >= 0)
        break;
}

camera.release();
destroyAllWindows();
return(0);

1 answer

  • answered 2018-01-10 15:29 Silencer

    Some to be improved:

    1. firstFrame = gray => gray.copyTo(firstFrame)

      you define firstFrame and gray at the same line, then after do firstFrame = gray, they share same data memory. So every time they are the same.

    2. Skip some frames.

      As the camera just starts, so the first frame is not that stable, you should skip some frames(like 10 frames).

    3. cv::Scalar <==> tuple

      In C++:

      cv::Scalar(b,g,r) <==> tuple(b,g,r)

      (b,g,r) ==> r


    Modified code:

    int cnt = 0;
    
    while(true) {
    
        Mat frame;
        camera.read(frame);
        if(frame.empty()) {
            cout << "frame was not captured" << endl;
            return(2);
        }
        //pre processing
        //resize(frame, frame, Size (1200,900));
        cvtColor(frame, gray, COLOR_BGR2GRAY);
        GaussianBlur(gray, gray, Size( 21, 21 ), 0, 0 );
    
        //initrialize first frame if necessary
        if(firstFrame.empty()) {
            if(cnt<10){
                ++cnt;
            }else{
                cout << "hit" << endl;
                gray.copyTo(firstFrame);
            }
            continue;
        }
    
        // ...
    
        ///  cv::Scalar(b,g,r) <==> tuple(b,g,r)
        ///  (b,g,r) ==> r
        rectangle( frame, boundRect.tl(), boundRect.br(), Scalar(0,255,0), 1, 8, 0 );
    
        // ...
    
    
    }
    

    enter image description here