Skip to content

Commit 1a8501f

Browse files
committed
Merge pull request #350 from tm1990/master
Added support for multiple points for source of motion
2 parents 9827348 + 41bce6b commit 1a8501f

File tree

5 files changed

+326
-9
lines changed

5 files changed

+326
-9
lines changed
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package com.github.sarxos.webcam;
2+
3+
import javax.swing.*;
4+
import java.awt.*;
5+
import java.awt.image.BufferedImage;
6+
import java.util.ArrayList;
7+
import java.util.HashMap;
8+
import java.util.Map;
9+
10+
public class MultipointMotionDetectionExample implements WebcamMotionListener, WebcamPanel.Painter {
11+
12+
public static void main(String[] args) throws InterruptedException {
13+
new MultipointMotionDetectionExample();
14+
}
15+
16+
private static final int INTERVAL = 100; // ms
17+
18+
public static Webcam webcam;
19+
public static WebcamPanel.Painter painter = null;
20+
21+
public MultipointMotionDetectionExample(){
22+
webcam = Webcam.getDefault();
23+
webcam.setViewSize(WebcamResolution.VGA.getSize());
24+
25+
WebcamPanel panel = new WebcamPanel(webcam);
26+
panel.setPreferredSize(WebcamResolution.VGA.getSize());
27+
panel.setPainter(this);
28+
panel.setFPSDisplayed(true);
29+
panel.setFPSLimited(true);
30+
panel.setFPSLimit(20);
31+
panel.setPainter(this);
32+
panel.start();
33+
34+
painter = panel.getDefaultPainter();
35+
36+
JFrame window = new JFrame("Multipoint-motion detection");
37+
window.add(panel);
38+
window.setResizable(true);
39+
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
40+
window.pack();
41+
window.setVisible(true);
42+
43+
44+
WebcamMotionDetector detector = new WebcamMotionDetector(webcam);
45+
46+
//Sets the max amount of motion points to 300 and the minimum range between them to 40
47+
detector.setMaxMotionPoints(300);
48+
detector.setPointRange(40);
49+
50+
detector.setInterval(INTERVAL);
51+
detector.addMotionListener(this);
52+
53+
detector.start();
54+
}
55+
56+
57+
//A HashMap to store all the current points and the current amount of times it has been rendered
58+
//Time rendered is used to remove the point after a certain amount of time
59+
public static HashMap<Point, Integer> motionPoints = new HashMap<Point, Integer>();
60+
61+
//Gets the motion points from the motion detector and adds it to the HashMap
62+
@Override
63+
public void motionDetected(WebcamMotionEvent wme) {
64+
for(Point p : wme.getPoints()){
65+
motionPoints.put(p, 0);
66+
}
67+
}
68+
69+
@Override
70+
public void paintPanel(WebcamPanel panel, Graphics2D g2) {
71+
if (painter != null) {
72+
painter.paintPanel(panel, g2);
73+
}
74+
}
75+
76+
77+
//Used to render the effect for the motion points
78+
private static final Stroke STROKE = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1.0f, new float[] { 1.0f }, 0.0f);
79+
80+
//The amount of time each point should be rendered for before being removed
81+
public static final int renderTime = 3;
82+
83+
//The actual size of the rendered effect for each point
84+
public static final int renderSize = 20;
85+
86+
@Override
87+
public void paintImage(WebcamPanel panel, BufferedImage image, Graphics2D g2) {
88+
89+
90+
if (painter != null) {
91+
painter.paintImage(panel, image, g2);
92+
}
93+
94+
//Gets all the points and updates the amount of time they have been rendered for
95+
//And removes the ones that exceed the renderTime variable
96+
97+
ArrayList<Point> rem = new ArrayList<Point>();
98+
99+
for (Map.Entry<Point, Integer> ent : motionPoints.entrySet()) {
100+
Point p = ent.getKey();
101+
102+
if (ent.getValue() != null) {
103+
int tt = ent.getValue();
104+
if (tt >= renderTime) {
105+
rem.add(ent.getKey());
106+
107+
} else {
108+
int temp = ent.getValue() + 1;
109+
motionPoints.put(p, temp);
110+
}
111+
112+
}
113+
}
114+
115+
for(Point p : rem){
116+
motionPoints.remove(p);
117+
}
118+
119+
120+
//Gets all the remaining points after removing the exceeded ones and then renders the current ones as a red square
121+
for(Map.Entry<Point, Integer> ent : motionPoints.entrySet()){
122+
Point p = ent.getKey();
123+
124+
int xx = p.x - (renderSize / 2), yy = p.y - (renderSize / 2);
125+
126+
Rectangle bounds = new Rectangle(xx, yy, renderSize, renderSize);
127+
128+
int dx = (int) (0.1 * bounds.width);
129+
int dy = (int) (0.2 * bounds.height);
130+
int x = (int) bounds.x - dx;
131+
int y = (int) bounds.y - dy;
132+
int w = (int) bounds.width + 2 * dx;
133+
int h = (int) bounds.height + dy;
134+
135+
g2.setStroke(STROKE);
136+
g2.setColor(Color.RED);
137+
g2.drawRect(x, y, w, h);
138+
139+
}
140+
141+
}
142+
}

webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionDetector.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ protected void detect() {
276276
* @param image with the motion detected
277277
*/
278278
private void notifyMotionListeners(BufferedImage currentOriginal) {
279-
WebcamMotionEvent wme = new WebcamMotionEvent(this, previousOriginal, currentOriginal, detectorAlgorithm.getArea(), detectorAlgorithm.getCog());
279+
WebcamMotionEvent wme = new WebcamMotionEvent(this, previousOriginal, currentOriginal, detectorAlgorithm.getArea(), detectorAlgorithm.getCog(), detectorAlgorithm.getPoints());
280280
for (WebcamMotionListener l : listeners) {
281281
try {
282282
l.motionDetected(wme);
@@ -437,4 +437,22 @@ public WebcamMotionDetectorAlgorithm getDetectorAlgorithm() {
437437
return detectorAlgorithm;
438438
}
439439

440+
441+
public void setMaxMotionPoints(int i){
442+
detectorAlgorithm.setMaxPoints(i);
443+
}
444+
445+
public int getMaxMotionPoints(){
446+
return detectorAlgorithm.getMaxPoints();
447+
}
448+
449+
450+
public void setPointRange(int i){
451+
detectorAlgorithm.setPointRange(i);
452+
}
453+
454+
public int getPointRange(){
455+
return detectorAlgorithm.getPointRange();
456+
}
457+
440458
}

webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionDetectorAlgorithm.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.awt.Point;
44
import java.awt.image.BufferedImage;
5+
import java.util.ArrayList;
56

67

78
/**
@@ -50,4 +51,36 @@ public interface WebcamMotionDetectorAlgorithm {
5051
* @return Return percentage image fraction covered by motion
5152
*/
5253
double getArea();
54+
55+
/**
56+
* Set the minimum range between each point detected
57+
* @param i the range to set
58+
*/
59+
void setPointRange(int i);
60+
61+
/**
62+
* Set the max amount of points that can be detected at one time
63+
* @param i The amount of points that can be detected
64+
*/
65+
void setMaxPoints(int i);
66+
67+
68+
/**
69+
* Get the current minimum range between each point
70+
* @return The current range
71+
*/
72+
int getPointRange();
73+
74+
/**
75+
* Get the current max amount of points that can be detected at one time
76+
* @return
77+
*/
78+
int getMaxPoints();
79+
80+
81+
/**
82+
* Returns the currently stored points that have been detected
83+
* @return The current points
84+
*/
85+
ArrayList<Point> getPoints();
5386
}

webcam-capture/src/main/java/com/github/sarxos/webcam/WebcamMotionDetectorDefaultAlgorithm.java

Lines changed: 98 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package com.github.sarxos.webcam;
22

3-
import java.awt.Point;
4-
import java.awt.image.BufferedImage;
5-
63
import com.github.sarxos.webcam.util.jh.JHBlurFilter;
74
import com.github.sarxos.webcam.util.jh.JHGrayFilter;
85

6+
import java.awt.*;
7+
import java.awt.image.BufferedImage;
8+
import java.util.ArrayList;
9+
910
/**
1011
* Default motion detector algorithm.
1112
*/
@@ -71,6 +72,7 @@ public BufferedImage prepareImage(BufferedImage original) {
7172

7273
@Override
7374
public boolean detect(BufferedImage previousModified, BufferedImage currentModified) {
75+
points.clear();
7476
int p = 0;
7577

7678
int cogX = 0;
@@ -79,6 +81,7 @@ public boolean detect(BufferedImage previousModified, BufferedImage currentModif
7981
int w = currentModified.getWidth();
8082
int h = currentModified.getHeight();
8183

84+
int j = 0;
8285
if (previousModified != null) {
8386
for (int x = 0; x < w; x++) {
8487
for (int y = 0; y < h; y++) {
@@ -88,10 +91,29 @@ public boolean detect(BufferedImage previousModified, BufferedImage currentModif
8891
int pid = combinePixels(cpx, ppx) & 0x000000ff;
8992

9093
if (pid >= pixelThreshold) {
91-
cogX += x;
92-
cogY += y;
93-
p += 1;
94-
}
94+
Point pp = new Point(x, y);
95+
boolean keep = j < maxPoints;
96+
97+
if (keep) {
98+
for (Point g : points) {
99+
if (g.x != pp.x || g.y != pp.y) {
100+
if (pp.distance(g) <= range) {
101+
keep = false;
102+
break;
103+
}
104+
}
105+
}
106+
}
107+
108+
if (keep) {
109+
points.add(new Point(x, y));
110+
j += 1;
111+
}
112+
113+
cogX += x;
114+
cogY += y;
115+
p += 1;
116+
}
95117
}
96118
}
97119
}
@@ -198,5 +220,73 @@ private static int clamp(int c) {
198220
return 255;
199221
}
200222
return c;
201-
}
223+
}
224+
225+
226+
/**
227+
* ArrayList to store the points for a detected motion
228+
*/
229+
ArrayList<Point> points = new ArrayList<Point>();
230+
231+
/**
232+
* The default minimum range between each point where motion has been detected
233+
*/
234+
public static final int DEFAULT_RANGE = 50;
235+
236+
/**
237+
* The default for the max amount of points that can be detected at one time
238+
*/
239+
public static final int DEFAULT_MAX_POINTS = 100;
240+
241+
/**
242+
* The current minimum range between points
243+
*/
244+
private int range = DEFAULT_RANGE;
245+
246+
/**
247+
* The current max amount of points
248+
*/
249+
private int maxPoints = DEFAULT_MAX_POINTS;
250+
251+
/**
252+
* Set the minimum range between each point detected
253+
* @param i the range to set
254+
*/
255+
public void setPointRange(int i){
256+
range = i;
257+
}
258+
259+
/**
260+
* Get the current minimum range between each point
261+
* @return The current range
262+
*/
263+
public int getPointRange(){
264+
return range;
265+
}
266+
267+
268+
/**
269+
* Set the max amount of points that can be detected at one time
270+
* @param i The amount of points that can be detected
271+
*/
272+
public void setMaxPoints(int i){
273+
maxPoints = i;
274+
}
275+
276+
277+
/**
278+
* Get the current max amount of points that can be detected at one time
279+
* @return
280+
*/
281+
public int getMaxPoints(){
282+
return maxPoints;
283+
}
284+
285+
/**
286+
* Returns the currently stored points that have been detected
287+
* @return The current points
288+
*/
289+
public ArrayList<Point> getPoints(){
290+
return points;
291+
}
202292
}

0 commit comments

Comments
 (0)