diff --git a/webcam-capture/src/example/java/MultipointMotionDetectionExample.java b/webcam-capture/src/example/java/MultipointMotionDetectionExample.java new file mode 100644 index 00000000..88512e94 --- /dev/null +++ b/webcam-capture/src/example/java/MultipointMotionDetectionExample.java @@ -0,0 +1,142 @@ +package com.github.sarxos.webcam; + +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +public class MultipointMotionDetectionExample implements WebcamMotionListener, WebcamPanel.Painter { + + public static void main(String[] args) throws InterruptedException { + new MultipointMotionDetectionExample(); + } + + private static final int INTERVAL = 100; // ms + + public static Webcam webcam; + public static WebcamPanel.Painter painter = null; + + public MultipointMotionDetectionExample(){ + webcam = Webcam.getDefault(); + webcam.setViewSize(WebcamResolution.VGA.getSize()); + + WebcamPanel panel = new WebcamPanel(webcam); + panel.setPreferredSize(WebcamResolution.VGA.getSize()); + panel.setPainter(this); + panel.setFPSDisplayed(true); + panel.setFPSLimited(true); + panel.setFPSLimit(20); + panel.setPainter(this); + panel.start(); + + painter = panel.getDefaultPainter(); + + JFrame window = new JFrame("Multipoint-motion detection"); + window.add(panel); + window.setResizable(true); + window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + window.pack(); + window.setVisible(true); + + + WebcamMotionDetector detector = new WebcamMotionDetector(webcam); + + //Sets the max amount of motion points to 300 and the minimum range between them to 40 + detector.setMaxMotionPoints(300); + detector.setPointRange(40); + + detector.setInterval(INTERVAL); + detector.addMotionListener(this); + + detector.start(); + } + + + //A HashMap to store all the current points and the current amount of times it has been rendered + //Time rendered is used to remove the point after a certain amount of time + public static HashMap motionPoints = new HashMap(); + + //Gets the motion points from the motion detector and adds it to the HashMap + @Override + public void motionDetected(WebcamMotionEvent wme) { + for(Point p : wme.getPoints()){ + motionPoints.put(p, 0); + } + } + + @Override + public void paintPanel(WebcamPanel panel, Graphics2D g2) { + if (painter != null) { + painter.paintPanel(panel, g2); + } + } + + + //Used to render the effect for the motion points + private static final Stroke STROKE = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1.0f, new float[] { 1.0f }, 0.0f); + + //The amount of time each point should be rendered for before being removed + public static final int renderTime = 3; + + //The actual size of the rendered effect for each point + public static final int renderSize = 20; + + @Override + public void paintImage(WebcamPanel panel, BufferedImage image, Graphics2D g2) { + + + if (painter != null) { + painter.paintImage(panel, image, g2); + } + + //Gets all the points and updates the amount of time they have been rendered for + //And removes the ones that exceed the renderTime variable + + ArrayList rem = new ArrayList(); + + for (Map.Entry ent : motionPoints.entrySet()) { + Point p = ent.getKey(); + + if (ent.getValue() != null) { + int tt = ent.getValue(); + if (tt >= renderTime) { + rem.add(ent.getKey()); + + } else { + int temp = ent.getValue() + 1; + motionPoints.put(p, temp); + } + + } + } + + for(Point p : rem){ + motionPoints.remove(p); + } + + + //Gets all the remaining points after removing the exceeded ones and then renders the current ones as a red square + for(Map.Entry ent : motionPoints.entrySet()){ + Point p = ent.getKey(); + + int xx = p.x - (renderSize / 2), yy = p.y - (renderSize / 2); + + Rectangle bounds = new Rectangle(xx, yy, renderSize, renderSize); + + int dx = (int) (0.1 * bounds.width); + int dy = (int) (0.2 * bounds.height); + int x = (int) bounds.x - dx; + int y = (int) bounds.y - dy; + int w = (int) bounds.width + 2 * dx; + int h = (int) bounds.height + dy; + + g2.setStroke(STROKE); + g2.setColor(Color.RED); + g2.drawRect(x, y, w, h); + + } + + } +} diff --git a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionDetector.java b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionDetector.java index e991a8d6..53f7d08b 100644 --- a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionDetector.java +++ b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionDetector.java @@ -276,7 +276,7 @@ protected void detect() { * @param image with the motion detected */ private void notifyMotionListeners(BufferedImage currentOriginal) { - WebcamMotionEvent wme = new WebcamMotionEvent(this, previousOriginal, currentOriginal, detectorAlgorithm.getArea(), detectorAlgorithm.getCog()); + WebcamMotionEvent wme = new WebcamMotionEvent(this, previousOriginal, currentOriginal, detectorAlgorithm.getArea(), detectorAlgorithm.getCog(), detectorAlgorithm.getPoints()); for (WebcamMotionListener l : listeners) { try { l.motionDetected(wme); @@ -437,4 +437,22 @@ public WebcamMotionDetectorAlgorithm getDetectorAlgorithm() { return detectorAlgorithm; } + + public void setMaxMotionPoints(int i){ + detectorAlgorithm.setMaxPoints(i); + } + + public int getMaxMotionPoints(){ + return detectorAlgorithm.getMaxPoints(); + } + + + public void setPointRange(int i){ + detectorAlgorithm.setPointRange(i); + } + + public int getPointRange(){ + return detectorAlgorithm.getPointRange(); + } + } diff --git a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionDetectorAlgorithm.java b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionDetectorAlgorithm.java index 110d9998..4cfdb80a 100644 --- a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionDetectorAlgorithm.java +++ b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionDetectorAlgorithm.java @@ -2,6 +2,7 @@ import java.awt.Point; import java.awt.image.BufferedImage; +import java.util.ArrayList; /** @@ -50,4 +51,36 @@ public interface WebcamMotionDetectorAlgorithm { * @return Return percentage image fraction covered by motion */ double getArea(); + + /** + * Set the minimum range between each point detected + * @param i the range to set + */ + void setPointRange(int i); + + /** + * Set the max amount of points that can be detected at one time + * @param i The amount of points that can be detected + */ + void setMaxPoints(int i); + + + /** + * Get the current minimum range between each point + * @return The current range + */ + int getPointRange(); + + /** + * Get the current max amount of points that can be detected at one time + * @return + */ + int getMaxPoints(); + + + /** + * Returns the currently stored points that have been detected + * @return The current points + */ + ArrayList getPoints(); } diff --git a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionDetectorDefaultAlgorithm.java b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionDetectorDefaultAlgorithm.java index 5a9a8a27..9c0e376b 100644 --- a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionDetectorDefaultAlgorithm.java +++ b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionDetectorDefaultAlgorithm.java @@ -1,11 +1,12 @@ package com.github.sarxos.webcam; -import java.awt.Point; -import java.awt.image.BufferedImage; - import com.github.sarxos.webcam.util.jh.JHBlurFilter; import com.github.sarxos.webcam.util.jh.JHGrayFilter; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.ArrayList; + /** * Default motion detector algorithm. */ @@ -71,6 +72,7 @@ public BufferedImage prepareImage(BufferedImage original) { @Override public boolean detect(BufferedImage previousModified, BufferedImage currentModified) { + points.clear(); int p = 0; int cogX = 0; @@ -79,6 +81,7 @@ public boolean detect(BufferedImage previousModified, BufferedImage currentModif int w = currentModified.getWidth(); int h = currentModified.getHeight(); + int j = 0; if (previousModified != null) { for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { @@ -88,10 +91,29 @@ public boolean detect(BufferedImage previousModified, BufferedImage currentModif int pid = combinePixels(cpx, ppx) & 0x000000ff; if (pid >= pixelThreshold) { - cogX += x; - cogY += y; - p += 1; - } + Point pp = new Point(x, y); + boolean keep = j < maxPoints; + + if (keep) { + for (Point g : points) { + if (g.x != pp.x || g.y != pp.y) { + if (pp.distance(g) <= range) { + keep = false; + break; + } + } + } + } + + if (keep) { + points.add(new Point(x, y)); + j += 1; + } + + cogX += x; + cogY += y; + p += 1; + } } } } @@ -198,5 +220,73 @@ private static int clamp(int c) { return 255; } return c; - } + } + + + /** + * ArrayList to store the points for a detected motion + */ + ArrayList points = new ArrayList(); + + /** + * The default minimum range between each point where motion has been detected + */ + public static final int DEFAULT_RANGE = 50; + + /** + * The default for the max amount of points that can be detected at one time + */ + public static final int DEFAULT_MAX_POINTS = 100; + + /** + * The current minimum range between points + */ + private int range = DEFAULT_RANGE; + + /** + * The current max amount of points + */ + private int maxPoints = DEFAULT_MAX_POINTS; + + /** + * Set the minimum range between each point detected + * @param i the range to set + */ + public void setPointRange(int i){ + range = i; + } + + /** + * Get the current minimum range between each point + * @return The current range + */ + public int getPointRange(){ + return range; + } + + + /** + * Set the max amount of points that can be detected at one time + * @param i The amount of points that can be detected + */ + public void setMaxPoints(int i){ + maxPoints = i; + } + + + /** + * Get the current max amount of points that can be detected at one time + * @return + */ + public int getMaxPoints(){ + return maxPoints; + } + + /** + * Returns the currently stored points that have been detected + * @return The current points + */ + public ArrayList getPoints(){ + return points; + } } diff --git a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionEvent.java b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionEvent.java index f8c1b3a9..2aa4c980 100644 --- a/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionEvent.java +++ b/webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionEvent.java @@ -2,6 +2,7 @@ import java.awt.Point; import java.awt.image.BufferedImage; +import java.util.ArrayList; import java.util.EventObject; @@ -30,6 +31,18 @@ public WebcamMotionEvent(WebcamMotionDetector detector, double strength, Point c this(detector, null, null, strength, cog); } + /** + * Create detected motion event. + * + * @param detector + * @param strength + * @param cog center of motion gravity + * @param points list of all detected points + */ + public WebcamMotionEvent(WebcamMotionDetector detector, double strength, Point cog, ArrayList points) { + this(detector, null, null, strength, cog, points); + } + /** * Create detected motion event. * @@ -46,6 +59,26 @@ public WebcamMotionEvent(WebcamMotionDetector detector, BufferedImage previousIm this.strength = strength; this.cog = cog; } + + /** + * Create detected motion event. + * + * @param detector + * @param previousImage + * @param currentImage + * @param strength + * @param cog center of motion gravity + * @param points list of all detected points + */ + public WebcamMotionEvent(WebcamMotionDetector detector, BufferedImage previousImage, BufferedImage currentImage, double strength, Point cog, ArrayList points) { + this(detector, previousImage, currentImage, strength, cog); + this.points = points; + } + + private ArrayList points; + public ArrayList getPoints(){ + return points; + } /** * Get percentage fraction of image covered by motion. 0 is no motion on @@ -85,4 +118,5 @@ public BufferedImage getCurrentImage() { public WebcamMotionDetector getSource() { return (WebcamMotionDetector) super.getSource(); } + }