1

I'm attempting to detect motion using frame difference. If there is a motion, I will enter another method, if not, I will not enter that method. The problem is when I make frame difference by using either absdiff(), or bitwise_xor(), I get a noisy frame, that is always detected as a motion.

I tried to remove that noise by using erode() and dilate() methods, it decreases the effect of the noise, but still there is noise. How can I remove this noise ?

Part of my current code:

capture >> Frame; // get a new frame from camera

cvtColor(Frame,Frame1,CV_RGB2GRAY);
threshold(Frame1,Frame1,50,255,CV_THRESH_BINARY);

waitKey(500);
capture >> PreFrame;

cvtColor(PreFrame,PreFrame,CV_RGB2GRAY);
threshold(PreFrame,PreFrame,50,255,CV_THRESH_BINARY);

//Result = Frame1 - PreFrame1;
//absdiff(Frame1,PreFrame1,Result);

bitwise_xor(Frame1,PreFrame,Result);
erode(Result,Result,Mat());
dilate(Result,Result,Mat());

imshow("Result",Result);

if (norm(Result,NORM_L1)==0){
    printf(" no change \n")
}
else
{
    // motion detected
}
Chris
  • 8,030
  • 4
  • 37
  • 56
Amr
  • 13
  • 4
  • possible duplicate of [What algorithm to compare two images](http://stackoverflow.com/questions/23931/what-algorithm-to-compare-two-images) – karlphillip May 24 '12 at 13:53
  • there is no way to *completely remove the noise* You should try and adopt your methods work with *"very low change"* -- e.g. see what the average of the noise is, and then all the frame differences below the average you treat as if they happened due to noise. All above the average, call it *"high change"* if you will, you presume there was other-than-noise influences in the image and go calculate the desired stuff. – penelope May 24 '12 at 14:42

3 Answers3

3

You can reduce noise a few different ways just applying one of the following techniques right after capturing the frame:

Blurring (averaging within the frame)

Have a look at a few different blur operators like:

  1. blur (fast, but less smooth)
  2. GaussianBlur (slower, but smoother)
  3. medianBlur (reduces impulse noise)

medianBlur is good for controlling impulse noise while preserving edges in the image.

Frame averaging (average different frames)

  1. accumulate
  2. accumulateWeighted

With frame averaging just divide the accumulated result by the number of frames accumulated to get the averaged frame. You probably want a rolling average window of say 5-10 frames to reduce the noise significantly. However, higher window sizes means more motion blurring when objects move in and out of the field of view. This will work best if your camera is motionless.

Hope that helps!

mevatron
  • 13,911
  • 4
  • 55
  • 72
  • 2
    Frame averaging will cancel readout noise (frame-to-frame differences). Blurring will cancel pixel differences such as FPN and PRNU. – Wouter Lievens May 24 '12 at 13:36
1

What happens if take the absolute difference of your grayscale images, and then threshold the result to remove small intensity changes? This would allow small variations in pixel intensity frame-to-frame, while still triggering your motion detector if there were any significant changes.

For example:

// Obtain image two images in grayscale
cvtColor(Frame,Frame1,CV_RGB2GRAY);
cvtColor(PreFrame,PreFrame,CV_RGB2GRAY);

// Take the absolute difference, this will be zero for identical
// pixels, and larger for greater differences
absdiff(Frame, PreFrame, Result)

// Threshold to remove small differences
threshold(Result,Result,20,255,CV_THRESH_BINARY);

// Prepare output, using Result as a mask
Mat output = Mat::zeros(Frame.size(), Frame.type());
add(
    Frame,   // Add frame
    0,       // and zero
    output,  // to output
    Result   // Only if result is non-zero
);

Do you have any example input/output images you are able to share?

Chris
  • 8,030
  • 4
  • 37
  • 56
  • @Mark Ransom Thanks for your help, this method minimized the noise but the frame colors appeared in a strange way, i don't know why?! – Amr May 24 '12 at 20:00
  • What do you mean by frame colours? You have converted to grayscale, performed image subtraction and then thresholded the result, so `Result` is a binary image corresponding to any significant intensity changes in the image. – Chris May 25 '12 at 07:54
  • after that i have to return back the frame ,into RGB ,so i used cvtColor(Result,Result1,CV_GRAY2RGB); bitwise_and(Result1,Frame,SResult1); – Amr May 25 '12 at 09:56
  • @Amr I have updated my answer with a possible solution. If I understand correctly, you basically want to use Result as a mask to select specific pixels from your input image. In the example I have used [cv::add](http://opencv.itseez.com/modules/core/doc/operations_on_arrays.html#add) as a dummy function to accomplish this, though there may be more elegant ways. – Chris May 25 '12 at 10:21
  • yes that's exactly what i want, and now it works well,thank you very much – Amr May 25 '12 at 11:14
0

By thresholding your images before you take the difference, you're multiplying the effect of the noise greatly. Do the subtraction on the grayscale images directly with absdiff instead of bitwise_xor.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622