import java.awt.Color;
import java.awt.image.BufferedImage;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
/**
* @author Josh Carolan
* SID:311181058
*/
public class MotionDetect {
private IplImage background;
private IplImage diffImg;
int i;
public MotionDetect(IplImage firstFrame) {
background = preProcess(firstFrame);
diffImg = background;
i = 0;
}
public void setBackground(IplImage newBackground)
{
background = preProcess(newBackground);
}
/**
* Pre-processes an image to be used in the motion detection. it first
* smoothes/ blurs the image to reduce noise and then turns it into a
* greyscale image for easier detection of differences between frames
*
* @param img
* the image to be processed
* @return the processed image
*/
public IplImage preProcess(IplImage img) {
BufferedImage bufimg = img.getBufferedImage();
Filter f = new Filter();
bufimg = f.smooth(bufimg);
bufimg = f.greyscale(bufimg);
// bufimg= f.histogramEqualize(bufimg); <-- removed as unnecessary and
// adds to time taken to detect movement
return IplImage.createFrom(bufimg);
}
/**
* Detects any difference between the current frame taken in as a parameter
* and the saved background image.
*
* @param currFrame
* the current frame to be looked at by the system to determine
* if movement has happened
* @return true if there is a difference between the two frames, otherwise
* false.
*/
public boolean Detect(IplImage currFrame) {
int h = currFrame.height();
int w = currFrame.width();
IplImage preProcessed = preProcess(currFrame);
// diffImg = grayDiff(preProcessed, background); <-- no longer needed as
// it has been consolidated into another method for optimization
// threshold is 10 % of the total pixels
int threshold = (int) (h * w * 0.1);
// if(motionDetected(threshold, diffImg){ //<-- no longer needed as the
// below method has been included for optimization
if (motionDetectDiffImg(threshold, preProcessed, background)) {
System.out.println("Motion detected!");
return true;
}
/*
* every 10th frame change the background this is so if someone comes in
* and moves something if we keep just one background image from the
* start the system will think there is always something different
* between the two images in the spot where the object is now missing.
*/
i++;
if (i == 10) {
background = preProcessed;
i = 0;
}
return false;
}
/**
* This method and the motionDetected() method have been consolidated into
* one method motionDetectDiffImg() below for optimzation. the code has been
* left in for both methods for debugging and interests sake. This method
* gets the difference between two grayscale images and thresholds the value
* of the pixel to either black(no change) or white(change).
*
* @param img1
* one of the frames to get the difference between
* @param img2
* the second frame to get the difference between
* @return
*/
public IplImage grayDiff(IplImage img1, IplImage img2) {
BufferedImage bufImg1 = img1.getBufferedImage();
BufferedImage bufImg2 = img2.getBufferedImage();
int dif;
int i = 0;
for (int row = 0; row < img1.height(); row++) {
for (int col = 0; col < img1.width(); col++) {
Color c1 = new Color(bufImg1.getRGB(col, row));
Color c2 = new Color(bufImg2.getRGB(col, row));
dif = Math.abs(c1.getRed() - c2.getRed());
if (dif > 64) {
i++;
dif = 255;
} else {
dif = 0;
}
bufImg1.setRGB(col, row, dif << 16 | dif << 8 | dif);
}
}
return IplImage.createFrom(bufImg1);
}
/**
* This method and the grayDiff method have been consolidated into one
* method motionDetectDiffImg() below for optimzation. the code has been
* left in for both methods for debugging and interests sake
*
* @param threshold
* : The decided threshold of allowed change between frames to
* account for noise in the images and small changes such as wind
* blowing curtains or other small such changes that shouldn't be
* picked up by the detector
* @param img
* : the difference image between the current frame and the
* background. if there has been no change between the two frames
* then all of the pixels if this image should be 0 (black) since
* the difference image is the current image - the background.
* @return true if there has been motion between the frames above the given
* threshold
*/
public boolean motionDetected(int threshold, IplImage img) {
int width = img.width();
int height = img.height();
int count = 0;
BufferedImage bufImg = img.getBufferedImage();
Color c;
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
c = new Color(bufImg.getRGB(col, row));
/*
* divide by 255 because the value is either 0 or 255 so we
* increase the count by 1 ifthe pixel value is 255
*/
count += c.getBlue() / 255;
if (count > threshold) {
return true;
}
}
}
return false;
}
/**
* This method combines the two above methods into one method for more
* performance. The program no longer has to o through the entire two images
* twice, instead it just gets the difference between the two images until
* it determines that t has passed the threshold and then it returns true.
* This method was added after the previous two to better optimize the code.
*
* @param threshold
* the acceptable change between the two pictures. (number of
* pixels that are allowed to differ by more than 64 in one of
* the RGB colours) (greyscale images only since R = G = B in a
* grey image).
* @param img1
* one of the frames to get the difference between
* @param img2
* the second frame to get the difference between
* @return
*/
public boolean motionDetectDiffImg(int threshold, IplImage img1,
IplImage img2) {
int width = img1.width();
int height = img1.height();
BufferedImage bufImg1 = img1.getBufferedImage();
BufferedImage bufImg2 = img2.getBufferedImage();
Color c1;
Color c2;
int dif = 0;
int count = 0;
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
c1 = new Color(bufImg1.getRGB(col, row));
c2 = new Color(bufImg2.getRGB(col, row));
dif = Math.abs(c1.getRed() - c2.getRed());
if (dif > 64) {
count++;
}
if (count > threshold) {
return true;
}
}
}
return false;
}
}