
com.github.sarxos.webcam.WebcamMotionDetectorDefaultAlgorithm Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of webcam-capture Show documentation
Show all versions of webcam-capture Show documentation
This library allows you to use your PC webcam, IP or network cameras directly from Java. It's compatible with most operating systems (Windows, Linux, MacOS).
package com.github.sarxos.webcam;
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.
*/
public class WebcamMotionDetectorDefaultAlgorithm implements WebcamMotionDetectorAlgorithm {
/**
* Default pixel difference intensity threshold (set to 25).
*/
public static final int DEFAULT_PIXEL_THREASHOLD = 25;
/**
* Default percentage image area fraction threshold (set to 0.2%).
*/
public static final double DEFAULT_AREA_THREASHOLD = 0.2;
/**
* Pixel intensity threshold (0 - 255).
*/
private volatile int pixelThreshold = DEFAULT_PIXEL_THREASHOLD;
/**
* Pixel intensity threshold (0 - 100).
*/
private volatile double areaThreshold = DEFAULT_AREA_THREASHOLD;
/**
* Motion strength (0 = no motion, 100 = full image covered by motion).
*/
private double area = 0;
/**
* Center of motion gravity.
*/
private Point cog = null;
/**
* Blur filter instance.
*/
private final JHBlurFilter blur = new JHBlurFilter(6, 6, 1);
/**
* Gray filter instance.
*/
private final JHGrayFilter gray = new JHGrayFilter();
/**
* Creates default motion detector algorithm.
*
* @param pixelThreshold intensity threshold (0 - 255)
* @param areaThreshold percentage threshold of image covered by motion
*/
public WebcamMotionDetectorDefaultAlgorithm(int pixelThreshold, double areaThreshold) {
setPixelThreshold(pixelThreshold);
setAreaThreshold(areaThreshold);
}
@Override
public BufferedImage prepareImage(BufferedImage original) {
BufferedImage modified = blur.filter(original, null);
modified = gray.filter(modified, null);
return modified;
}
@Override
public boolean detect(BufferedImage previousModified, BufferedImage currentModified) {
points.clear();
int p = 0;
int cogX = 0;
int cogY = 0;
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++) {
int cpx = currentModified.getRGB(x, y);
int ppx = previousModified.getRGB(x, y);
int pid = combinePixels(cpx, ppx) & 0x000000ff;
if (pid >= pixelThreshold) {
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;
}
}
}
}
area = p * 100d / (w * h);
if (area >= areaThreshold) {
cog = new Point(cogX / p, cogY / p);
return true;
} else {
cog = new Point(w / 2, h / 2);
return false;
}
}
@Override
public Point getCog() {
return this.cog;
}
@Override
public double getArea() {
return this.area;
}
/**
* Set pixel intensity difference threshold above which pixel is classified
* as "moved". Minimum value is 0 and maximum is 255. Default value is 10.
* This value is equal for all RGB components difference.
*
* @param threshold the pixel intensity difference threshold
* @see #DEFAULT_PIXEL_THREASHOLD
*/
public void setPixelThreshold(int threshold) {
if (threshold < 0) {
throw new IllegalArgumentException("Pixel intensity threshold cannot be negative!");
}
if (threshold > 255) {
throw new IllegalArgumentException("Pixel intensity threshold cannot be higher than 255!");
}
this.pixelThreshold = threshold;
}
/**
* Set percentage fraction of detected motion area threshold above which it
* is classified as "moved". Minimum value for this is 0 and maximum is 100,
* which corresponds to full image covered by spontaneous motion.
*
* @param threshold the percentage fraction of image area
* @see #DEFAULT_AREA_THREASHOLD
*/
public void setAreaThreshold(double threshold) {
if (threshold < 0) {
throw new IllegalArgumentException("Area fraction threshold cannot be negative!");
}
if (threshold > 100) {
throw new IllegalArgumentException("Area fraction threshold cannot be higher than 100!");
}
this.areaThreshold = threshold;
}
private static int combinePixels(int rgb1, int rgb2) {
// first ARGB
int a1 = (rgb1 >> 24) & 0xff;
int r1 = (rgb1 >> 16) & 0xff;
int g1 = (rgb1 >> 8) & 0xff;
int b1 = rgb1 & 0xff;
// second ARGB
int a2 = (rgb2 >> 24) & 0xff;
int r2 = (rgb2 >> 16) & 0xff;
int g2 = (rgb2 >> 8) & 0xff;
int b2 = rgb2 & 0xff;
r1 = clamp(Math.abs(r1 - r2));
g1 = clamp(Math.abs(g1 - g2));
b1 = clamp(Math.abs(b1 - b2));
// in case if alpha is enabled (translucent image)
if (a1 != 0xff) {
a1 = a1 * 0xff / 255;
int a3 = (255 - a1) * a2 / 255;
r1 = clamp((r1 * a1 + r2 * a3) / 255);
g1 = clamp((g1 * a1 + g2 * a3) / 255);
b1 = clamp((b1 * a1 + b2 * a3) / 255);
a1 = clamp(a1 + a3);
}
return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
}
/**
* Clamp a value to the range 0..255
*/
private static int clamp(int c) {
if (c < 0) {
return 0;
}
if (c > 255) {
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;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy