2

I am trying to do Frame subtraction in a video.Steps I am following

  1. Get a image , convert it into grayscale.
  2. Subtract it from previous frame grayscale.

All I see in diff2(and diff also) a complete black image.One observation I made is that pixel value of gray1 and gray2 become equal.

My code

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include <opencv2/video/background_segm.hpp>
#include <iostream>

using namespace cv;
using namespace std;
RNG rng(12345);

    int main( int argc, const char** argv )

{
   VideoCapture cap(0);

    if ( !cap.isOpened() ) 
    {
         cout << "Cannot open the web cam" << endl;
         return -1;
    }

    Mat img1,img2,diff,gray1,gray2,diff2;


        bool bSuccess = cap.read(img1); // read a new frame from video

         if (!bSuccess) //if not success, break loop
        {
             cout << "Cannot read a frame from video stream" << endl;
             return -1;
        }

        cvtColor( img1,gray1, CV_BGR2GRAY );

     while (true)
    {


        bSuccess = cap.read(img2); // read a new frame from video

         if (!bSuccess) //if not success, break loop
        {
             cout << "Cannot read a frame from video stream" << endl;
             break;
        }
        cvtColor( img2,gray2, CV_BGR2GRAY );

        absdiff(gray2,gray1,diff);
        threshold(diff, diff2, 150, 255, CV_THRESH_BINARY); 
        cout<<gray2.at<uchar>(100,200) <<endl;
        cout<<gray1.at<uchar>(100,200) <<endl;

        gray1=gray2;
        imshow("1",gray1);
        imshow("2",diff2);


    if (waitKey(1000) == 27) //wait for 'esc' key press for 30ms. If 'esc' key is pressed, break loop
       {
            cout << "esc key is pressed by user" << endl;
            break; 
       }
    }


     return -1;
}
jokeroor
  • 63
  • 1
  • 5
  • 1
    do you still get a black image if you don't threshold? Difference of 150 is quite a lot, typically for saying that there is a difference you choose a threshold of 20-30. Instead of thresholding can you try `diff2 = diff > 0` to test whether there is ANY difference in your images? `gray1=gray2;` is a problem, please use `gray1=gray2.clone();` instead, otherwise gray1 and gray2 will use the same memory after your first iteration. If you don't want to copy but just "swap the buffers" you should really swap the buffers and don't just overwrite one. – Micka Dec 09 '15 at 13:19
  • 1
    @Micka that should be an answer. `gray1=gray2;` is in fact the issue, and a lower threshold shows better results. – Miki Dec 09 '15 at 13:25

1 Answers1

2

please try this code. It looks like you're overwriting gray1 so that gray1 and gray2 use the very same data memory positions.

You could either use gray1=gray2.clone(); instead or use some real "swapping" of the buffers instead of overwriting. My code should perform a simple buffer swapping and has some comments about the problem.

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include <opencv2/video/background_segm.hpp>
#include <iostream>

using namespace cv;
using namespace std;
RNG rng(12345);

int main( int argc, const char** argv )

{
   VideoCapture cap(0);

    if ( !cap.isOpened() ) 
    {
         cout << "Cannot open the web cam" << endl;
         return -1;
    }

    Mat img1,img2,diff,gray1,gray2,diff2;

    Mat tmp; // used to swap the buffers


    bool bSuccess = cap.read(img1); // read a new frame from video

    if (!bSuccess) //if not success, break loop
    {
         cout << "Cannot read a frame from video stream" << endl;
         return -1;
    }

    // this will allocate memory of gray1 if not allocated yet
    cvtColor( img1,gray1, CV_BGR2GRAY );

    while (true)
    {


        bSuccess = cap.read(img2); // read a new frame from video

         if (!bSuccess) //if not success, break loop
        {
         cout << "Cannot read a frame from video stream" << endl;
         break;
        }

        // memory for gray2 won't be allocated if it is present already => if gray2 and gray1 use the same data memory, you'll overwrite gray1's pixels here and obviously gray1 and gray2 will have the same pixel values then
        cvtColor( img2,gray2, CV_BGR2GRAY );

        absdiff(gray2,gray1,diff);
        threshold(diff, diff2, 150, 255, CV_THRESH_BINARY); 
        cout<<gray2.at<uchar>(100,200) <<endl;
        cout<<gray1.at<uchar>(100,200) <<endl;

        // don't lose the memory of gray1
        tmp = gray1;

        // this means gray1 and gray2 will use the same data memory location
        gray1=gray2;

        // give gray2 a new data memory location. Since previous gray1 memory is still present but wont be used anymore, use it here.
        gray2=tmp;

        imshow("1",gray1);
        imshow("2",diff2);


    if (waitKey(1000) == 27) //wait for 'esc' key press for 30ms. If 'esc' key is pressed, break loop
       {
            cout << "esc key is pressed by user" << endl;
            break; 
       }
    }


     return -1;
}

in addition, a thres difference threshold of 150 might be very high for common tasks, but it might be ok for your special task. Typical difference values/thresholds in background subtraction for foreground extraction are around 20 to 30 from my experience, but at the end it depends on your task/problem/domain.

Micka
  • 19,585
  • 4
  • 56
  • 74
  • Thanks a lot!!. I think I need to spend some time Understanding data structures of opencv – jokeroor Dec 09 '15 at 17:04
  • 1
    Mat data structure is very comfortable to use but has some traps included. If you plan to work a lot with openCV it is really worth the effort to go deeper in that. For the beginning just think about cv::Mat as some kind of smart pointer to some data memory and that most openCV functions will allocate output memory for that pointer automatically if and only if the pointer's memory doesn't already fit the parameters for that output (size and type). – Micka Dec 09 '15 at 17:12