Ask Your Question
1

frame difference correct method

asked 2015-11-15 13:06:00 -0600

elp14sma gravatar image

updated 2020-10-24 14:09:25 -0600

I want to do basic frame difference like this :

diff = current frame - previous frame

is this correct way to so this ? I"m not sure how to get current and next frame

#include <highgui.h>
#include <iostream>
using namespace cv;

int main()
{

VideoCapture cap("Camouflage/b%05d.bmp");
if(!cap.isOpened())
{
    std::cout<<"failed to open image sequence";
    return 1;
}
char c;
Mat frame1, frame2, frame3;
namedWindow("Original Frames",1);   
namedWindow("Frame Difference",1);
while(1)
{
    cap>>frame1;
    if(frame1.empty())
    {
        std::cout<<"Frame1Message->End of sequence"<<std::endl;
        break;
    }
    cap>>frame2;
    if(frame2.empty())
    {
        std::cout<<"Frame2Message->End of sequence"<<std::endl;
        break;
    }

    frame3=frame1.clone();
    frame3=frame3-frame2;

    imshow("Frame Difference",frame3);
    c=waitKey(90);
    if(c==27)
        break;

    imshow("Original Frames",frame1);
    c=waitKey(90);
    if(c==27)           
         break;
    }

  }
edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
2

answered 2015-11-15 13:29:17 -0600

pklab gravatar image

updated 2015-11-18 08:45:49 -0600

Be careful because if your mats are unsigned type like CV_8UC3, pixel difference can gives negative values that will be saturated to 0... so that 250-230=20 but 230-250=0!!

  • If you don't have need of sign you can use cv::absdiff
  • if you have need of sign you have to prepare a signed Mat to store the result and use cv::subtract
  • at the end if you want just to know which pixels had changed, you can use compare or checkRange

Here is the code on how to get different types of difference available in opencv and how you can take them between 2 consecutive frames, let me change your var name...

//declare mats
cv::Mat frameCurrent, framePrev;
cv::Mat badDiff,frameAbsDiff, frameDif, frameChangeMask;
//prepare Mats
cap >> frameCurrent;
framePrev = cv::Mat::zeros(frameCurrent.size(), frameCurrent.type()); // prev frame as black
//signed 16bit mat to receive signed difference
if (frameCurrent.channels() == 1)
    frameDif = cv::Mat(frameCurrent.size(), CV_16SC1);
if (frameCurrent.channels() == 3)
    frameDif = cv::Mat(frameCurrent.size(), CV_16SC3);
if (frameCurrent.channels() == 4)
    frameDif = cv::Mat(frameCurrent.size(), CV_16SC4);
while (1)
{
    if (frameCurrent.empty()) {
        std::cout << "Frame1Message->End of sequence" << std::endl;
        break;
    }
    // WARNING!!! here 250-230=20 but 230-250=0
    badDiff = frameCurrent - framePrev;
    //here 230-250=20 and 250-230=20
    cv::absdiff(frameCurrent, framePrev, frameAbsDiff);
    //here 230-250=-20 and 250-230=+20
    cv::subtract(frameCurrent, framePrev, frameDif, cv::Mat(), frameDif.type());
    // this is a changing mask that is same as frame1(x,y) != frame2(x,y)
    cv::compare(frameCurrent, framePrev, theDiff, cv::CMP_NE);

    imshow("frameCurrent", frameCurrent);
    imshow("frameAbsDiff", frameAbsDiff);
    //To show 16 signed Mat, scale it and shift in 8bit unsigned
    //-255..-1 => 0..127 and 0..255 => 128..255;
    cv::Mat frameDiff8UC;
    frameDif.convertTo(frameDiff8UC, CV_8UC3, 0.5, 128);
    imshow("frameDif", frameDiff8UC);
    imshow("frameChangeMask", frameChangeMask);

    if (waitKey(90) == 27)
        break;

    frameCurrent.copyTo(framePrev);
    cap >> frameCurrent;
}
edit flag offensive delete link more

Comments

thanks for answer ,

Is the way that I'm getting current frame and previous frame is correct ?

how can I get current frame and previous frame

elp14sma gravatar imageelp14sma ( 2015-11-15 13:52:40 -0600 )edit

@elp14sma: not exactly. Right now you're getting difference of frame 1 and 2, then 3 and 4, then 5 and 6 and so on. If you want to get the difference between frame 1 and 2, and then between 2 and 3, you need to have a buffer Mat to store your previous frame, and just read one frame in each step of the loop.

LorenaGdL gravatar imageLorenaGdL ( 2015-11-15 14:28:27 -0600 )edit
2

I edited my answer with more explanation

pklab gravatar imagepklab ( 2015-11-16 03:55:34 -0600 )edit

@pklab i suggest tagging questions by Noteworthy_Content when it has a good answer

sturkmen gravatar imagesturkmen ( 2015-11-16 05:16:42 -0600 )edit

@pklab ,If I convert the the the video frames to grayscale and I want to calculate the difference as : current_frame - previous_frame . 1. which one I need to use absdiff or subtract , I know the difference between them but which one should be used .

  1. in framePrev = cv::Mat::zeros(frameCurrent.size(), frameCurrent.type());
    here you are creating empty Mat filled with zeros that equals to (frame current rows , columns and data type ) right ?
elp14sma gravatar imageelp14sma ( 2015-11-18 07:54:15 -0600 )edit

@pklab ,If I convert the the the video frames to grayscale and I want to calculate the difference as : current_frame - previous_frame .

  1. which one I need to use absdiff or subtract , I know the difference between them but which one should be used .

  2. in framePrev = cv::Mat::zeros(frameCurrent.size(), frameCurrent.type());
    here you are creating empty Mat filled with zeros that equals to (frame current rows , columns and data type ) right ?

elp14sma gravatar imageelp14sma ( 2015-11-18 07:54:35 -0600 )edit

@elp14asma

  1. you should use the difference you need
  2. yes framePrev must be initialized to calculate 1st difference. My opinion is that initial state of framePrev should be zero (black frame) so 1st difference will comes from black. You can initialize it to something else like framePrev=frameCurrent and have 1st difference = 0... it's just to define a starting state.
pklab gravatar imagepklab ( 2015-11-18 08:56:02 -0600 )edit

Sorry about that , I wanted to show you the code . how can I have ( current frame and previous frame ) to be grayscale and then calculate the difference

elp14sma gravatar imageelp14sma ( 2015-11-18 17:02:34 -0600 )edit

please read the doc: "the first array ... has as many elements as the number of channels in src2" means that both frameCurrent and framePrev should be GRAY or BGR and have same rows and cols. In your case, you can convert frameCurrent to gray and all should work.

cap >> frameCurrent;
cvtColor(frameCurrent,frameCurrent,BGR2GRAY);
frameCurrent.copyTo(framePrev); // 1st difference will be 0
...
while(1)
{
    ...
    cv::absdiff(frameCurrent, framePrev, frameAbsDiff);    
    ...
    frameCurrent.copyTo(framePrev);
    cap >> frameCurrent;
    cvtColor(frameCurrent,frameCurrent,BGR2GRAY);
}
pklab gravatar imagepklab ( 2015-11-19 01:52:55 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2015-11-15 13:06:00 -0600

Seen: 7,938 times

Last updated: Nov 18 '15