Skip to content

Commit

Permalink
Add new motion detection algorithm (DNE), refs #524
Browse files Browse the repository at this point in the history
The "Do No Engage" algorithm is simply a rectangle specified by the user in
which the algorithm will ignore motion. The feature is implemented by allowing
the user to pass a Rectangle into the algorithm, and then the algorithm
only processes pixels that are not contained in the Rectangle.

This commit is a squash of pull request #524 by Kevin Kanzelmeyer (@kkanzelmeyer).

It was produced by cherry picking all changes into the master, squasing,
removing all changes that relates to pom.xml files (these were unnecessary)
and the ones related to GStramer 1.x driver and then finally reworking to address
comments from review.
  • Loading branch information
kkanzelmeyer authored and sarxos committed Aug 18, 2017
1 parent 2fd33d1 commit 9ee9d94
Show file tree
Hide file tree
Showing 8 changed files with 453 additions and 223 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ README.md~
.idea/
*.ipr
*.iws
.DS_Store
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.TexturePaint;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Arrays;

import javax.swing.JFrame;

import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.WebcamMotionDetector;
import com.github.sarxos.webcam.WebcamMotionDetectorAlgorithm;
import com.github.sarxos.webcam.WebcamMotionDetectorDefaultAlgorithm;
import com.github.sarxos.webcam.WebcamPanel;
import com.github.sarxos.webcam.WebcamResolution;
import com.github.sarxos.webcam.util.ImageUtils;


/**
* This example demonstrates how to use build-in motion detector with do-not-engage zones. The
* do-not-engage zone is a rectangular area where motion is ignored and won't trigger motion
* detector.
*
* @author Bartosz Firyn (sarxos)
*/
public class DetectMotionDoNotEngageZoneExample extends JFrame implements WebcamPanel.Painter {

private static final long serialVersionUID = 1L;

private static final BufferedImage TEXTURE = ImageUtils.readFromResource("stripes.png");
private static final Paint PAINT = new TexturePaint(TEXTURE, new Rectangle(0, 0, 10, 10));

private static final Dimension RESOLUTION = WebcamResolution.VGA.getSize();
private static final Rectangle DO_NOT_ENGAGE_ZONE = new Rectangle(0, 0, 320, 480);

private final Webcam webcam;
private final WebcamPanel panel;
private final WebcamMotionDetector detector;

public DetectMotionDoNotEngageZoneExample() {

setTitle("Motion Detector Demo");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

webcam = Webcam.getDefault();
webcam.setViewSize(RESOLUTION);
webcam.open(true);

panel = new WebcamPanel(webcam, false);
panel.setPainter(this);
panel.start();

WebcamMotionDetectorAlgorithm algorithm = new WebcamMotionDetectorDefaultAlgorithm();
algorithm.setDoNotEngageZones(Arrays.asList(DO_NOT_ENGAGE_ZONE));

detector = new WebcamMotionDetector(webcam, algorithm, 500);
detector.setPixelThreshold(20);
detector.start();

add(panel);

pack();
setVisible(true);
}

public static void main(String[] args) throws IOException {
new DetectMotionDoNotEngageZoneExample();
}

@Override
public void paintPanel(WebcamPanel panel, Graphics2D g2) {
panel.getDefaultPainter().paintPanel(panel, g2);
}

@Override
public void paintImage(WebcamPanel panel, BufferedImage image, Graphics2D g2) {

final double s = detector.getMotionArea();
final Point cog = detector.getMotionCog();

final int x = DO_NOT_ENGAGE_ZONE.x;
final int y = DO_NOT_ENGAGE_ZONE.y;
final int w = DO_NOT_ENGAGE_ZONE.width;
final int h = DO_NOT_ENGAGE_ZONE.height;

Graphics2D g = image.createGraphics();
g.setPaint(PAINT);
g.fillRect(x, y, w, h);
g.setColor(Color.WHITE);
g.drawString(String.format("Area: %.2f%%", s), 10, 20);

if (detector.isMotion()) {
g.setStroke(new BasicStroke(2));
g.setColor(Color.RED);
g.drawOval(cog.x - 5, cog.y - 5, 10, 10);
} else {
g.setColor(Color.GREEN);
g.drawRect(cog.x - 5, cog.y - 5, 10, 10);
}

g.dispose();

panel.getDefaultPainter().paintImage(panel, image, g2);
}
}
Binary file added webcam-capture/src/example/resources/stripes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions webcam-capture/src/example/resources/stripes.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
/**
* Webcam motion detector.
*
* @author Bartosz Firyn (SarXos)
* @author Bartosz Firyn (sarxos)
*/
public class WebcamMotionDetector {

Expand Down Expand Up @@ -141,8 +141,8 @@ public void run() {
/**
* Previously captured image with blur and gray filters applied.
*/
private BufferedImage previousModified = null;
private BufferedImage previousFiltered = null;

/**
* Webcam to be used to detect motion.
*/
Expand All @@ -166,24 +166,24 @@ public void run() {
/**
* Implementation of motion detection algorithm.
*/
private final WebcamMotionDetectorAlgorithm detectorAlgorithm;
private final WebcamMotionDetectorAlgorithm algorithm;

/**
* Create motion detector. Will open webcam if it is closed.
* Create motion detector. Will open webcam if it is closed.
*
* @param webcam web camera instance
* @param motion detector algorithm implementation
* @param interval the check interval
* @param motion detector algorithm implementation
* @param interval the check interval (in milliseconds)
*/
public WebcamMotionDetector(Webcam webcam, WebcamMotionDetectorAlgorithm detectorAlgorithm, int interval) {
public WebcamMotionDetector(Webcam webcam, WebcamMotionDetectorAlgorithm algorithm, int interval) {
this.webcam = webcam;
this.detectorAlgorithm = detectorAlgorithm;
this.algorithm = algorithm;
setInterval(interval);
}

/**
* Create motion detector. Will open webcam if it is closed.
* Uses WebcamMotionDetectorDefaultAlgorithm for motion detection.
* Create motion detector. Will open webcam if it is closed. Uses
* WebcamMotionDetectorDefaultAlgorithm for motion detection.
*
* @param webcam web camera instance
* @param pixelThreshold intensity threshold (0 - 255)
Expand All @@ -195,21 +195,20 @@ public WebcamMotionDetector(Webcam webcam, int pixelThreshold, double areaThresh
}

/**
* Create motion detector with default parameter inertia = 0.
* Uses WebcamMotionDetectorDefaultAlgorithm for motion detection.
* Create motion detector with default parameter inertia = 0. Uses
* WebcamMotionDetectorDefaultAlgorithm for motion detection.
*
* @param webcam web camera instance
* @param pixelThreshold intensity threshold (0 - 255)
* @param areaThreshold percentage threshold of image covered by motion (0 -
* 100)
* @param areaThreshold percentage threshold of image covered by motion (0 - 100)
*/
public WebcamMotionDetector(Webcam webcam, int pixelThreshold, double areaThreshold) {
this(webcam, pixelThreshold, areaThreshold, DEFAULT_INTERVAL);
}

/**
* Create motion detector with default parameter inertia = 0.
* Uses WebcamMotionDetectorDefaultAlgorithm for motion detection.
* Create motion detector with default parameter inertia = 0. Uses
* WebcamMotionDetectorDefaultAlgorithm for motion detection.
*
* @param webcam web camera instance
* @param pixelThreshold intensity threshold (0 - 255)
Expand All @@ -219,8 +218,7 @@ public WebcamMotionDetector(Webcam webcam, int pixelThreshold) {
}

/**
* Create motion detector with default parameters - threshold = 25, inertia
* = 0.
* Create motion detector with default parameters - threshold = 25, inertia = 0.
*
* @param webcam web camera instance
*/
Expand Down Expand Up @@ -257,26 +255,26 @@ protected void detect() {
return;
}

BufferedImage currentModified = detectorAlgorithm.prepareImage(currentOriginal);

boolean movementDetected = detectorAlgorithm.detect(previousModified, currentModified);
final BufferedImage currentFiltered = algorithm.filter(currentOriginal);
final boolean motionDetected = algorithm.detect(previousFiltered, currentFiltered);

if (movementDetected) {
if (motionDetected) {
motion = true;
lastMotionTimestamp = System.currentTimeMillis();
notifyMotionListeners(currentOriginal);
}

previousOriginal = currentOriginal;
previousModified = currentModified;
previousFiltered = currentFiltered;
}

/**
* Will notify all attached motion listeners.
*
* @param image with the motion detected
*/
private void notifyMotionListeners(BufferedImage currentOriginal) {
WebcamMotionEvent wme = new WebcamMotionEvent(this, previousOriginal, currentOriginal, detectorAlgorithm.getArea(), detectorAlgorithm.getCog(), detectorAlgorithm.getPoints());
WebcamMotionEvent wme = new WebcamMotionEvent(this, previousOriginal, currentOriginal, algorithm.getArea(), algorithm.getCog(), algorithm.getPoints());
for (WebcamMotionListener l : listeners) {
try {
l.motionDetected(wme);
Expand Down Expand Up @@ -321,8 +319,8 @@ public int getInterval() {
}

/**
* Motion check interval in milliseconds. After motion is detected, it's
* valid for time which is equal to value of 2 * interval.
* Motion check interval in milliseconds. After motion is detected, it's valid for time which is
* equal to value of 2 * interval.
*
* @param interval the new motion check interval (ms)
* @see #DEFAULT_INTERVAL
Expand All @@ -337,37 +335,32 @@ public void setInterval(int interval) {
}

/**
* Sets pixelThreshold to the underlying detector algorithm, but only if the
* algorithm is (or extends) WebcamMotionDetectorDefaultAlgorithm
* Sets pixelThreshold to the underlying detector algorithm, but only if the algorithm is (or
* extends) WebcamMotionDetectorDefaultAlgorithm
*
* @see WebcamMotionDetectorDefaultAlgorithm#setPixelThreshold(int)
*
* @param threshold the pixel intensity difference threshold
*/
public void setPixelThreshold(int threshold) {
if (detectorAlgorithm instanceof WebcamMotionDetectorDefaultAlgorithm) {
((WebcamMotionDetectorDefaultAlgorithm)detectorAlgorithm).setPixelThreshold(threshold);
}
((WebcamMotionDetectorDefaultAlgorithm) algorithm).setPixelThreshold(threshold);
}

/**
* Sets areaThreshold to the underlying detector algorithm, but only if the
* algorithm is (or extends) WebcamMotionDetectorDefaultAlgorithm
* Sets areaThreshold to the underlying detector algorithm, but only if the algorithm is (or
* extends) WebcamMotionDetectorDefaultAlgorithm
*
* @see WebcamMotionDetectorDefaultAlgorithm#setAreaThreshold(double)
*
* @param threshold the percentage fraction of image area
*/
public void setAreaThreshold(double threshold) {
if (detectorAlgorithm instanceof WebcamMotionDetectorDefaultAlgorithm) {
((WebcamMotionDetectorDefaultAlgorithm)detectorAlgorithm).setAreaThreshold(threshold);
}
((WebcamMotionDetectorDefaultAlgorithm) algorithm).setAreaThreshold(threshold);
}

/**
* Set motion inertia (time when motion is valid). If no value specified
* this is set to 2 * interval. To reset to default value,
* {@link #clearInertia()} method must be used.
* Set motion inertia (time when motion is valid). If no value specified this is set to 2 *
* interval. To reset to default value, {@link #clearInertia()} method must be used.
*
* @param inertia the motion inertia time in milliseconds
* @see #clearInertia()
Expand All @@ -380,8 +373,8 @@ public void setInertia(int inertia) {
}

/**
* Reset inertia time to value calculated automatically on the base of
* interval. This value will be set to 2 * interval.
* Reset inertia time to value calculated automatically on the base of interval. This value will
* be set to 2 * interval.
*/
public void clearInertia() {
this.inertia = -1;
Expand All @@ -404,23 +397,23 @@ public boolean isMotion() {
}

/**
* Get percentage fraction of image covered by motion. 0 means no motion on
* image and 100 means full image covered by spontaneous motion.
* Get percentage fraction of image covered by motion. 0 means no motion on image and 100 means
* full image covered by spontaneous motion.
*
* @return Return percentage image fraction covered by motion
*/
public double getMotionArea() {
return detectorAlgorithm.getArea();
return algorithm.getArea();
}

/**
* Get motion center of gravity. When no motion is detected this value
* points to the image center.
* Get motion center of gravity. When no motion is detected this value points to the image
* center.
*
* @return Center of gravity point
*/
public Point getMotionCog() {
Point cog = detectorAlgorithm.getCog();
Point cog = algorithm.getCog();
if (cog == null) {
// detectorAlgorithm hasn't been called so far - get image center
int w = webcam.getViewSize().width;
Expand All @@ -434,25 +427,22 @@ public Point getMotionCog() {
* @return the detectorAlgorithm
*/
public WebcamMotionDetectorAlgorithm getDetectorAlgorithm() {
return detectorAlgorithm;
return algorithm;
}

public void setMaxMotionPoints(int i) {
algorithm.setMaxPoints(i);
}

public void setMaxMotionPoints(int i){
detectorAlgorithm.setMaxPoints(i);
}

public int getMaxMotionPoints(){
return detectorAlgorithm.getMaxPoints();
}


public void setPointRange(int i){
detectorAlgorithm.setPointRange(i);
}
public int getMaxMotionPoints() {
return algorithm.getMaxPoints();
}

public int getPointRange(){
return detectorAlgorithm.getPointRange();
}
public void setPointRange(int i) {
algorithm.setPointRange(i);
}

public int getPointRange() {
return algorithm.getPointRange();
}
}
Loading

0 comments on commit 9ee9d94

Please sign in to comment.