A motion detection algoritm for use with the Java Media Framework API (JMF). : JMF « 2D Graphics GUI « Java

Home
Java
1.2D Graphics GUI
2.2D Graphics GUI1
3.3D
4.Advanced Graphics
5.Ant
6.Apache Common
7.Chart
8.Class
9.Collections Data Structure
10.Data Type
11.Database SQL JDBC
12.Design Pattern
13.Development Class
14.EJB3
15.Email
16.Event
17.File Input Output
18.Game
19.Generics
20.GWT
21.Hibernate
22.I18N
23.J2EE
24.J2ME
25.JDK 6
26.JNDI LDAP
27.JPA
28.JSP
29.JSTL
30.Language Basics
31.Network Protocol
32.PDF RTF
33.Reflection
34.Regular Expressions
35.Scripting
36.Security
37.Servlets
38.Spring
39.Swing Components
40.Swing JFC
41.SWT JFace Eclipse
42.Threads
43.Tiny Application
44.Velocity
45.Web Services SOA
46.XML
Java Tutorial
Java Source Code / Java Documentation
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
SCJP
Java » 2D Graphics GUI » JMFScreenshots 
A motion detection algoritm for use with the Java Media Framework API (JMF).
  


/**
 * A motion detection algoritm for use with the Java Media Framework API (JMF).
 * The main idea of the algorithm is to compare the pixelcolours of two successive frames in an incoming videostream.
 * To prevent noise to be mistaken for motion each frame is divided into many small squares for which only the mean colour is used for compairson.
 @version 2002-09-26
 @author Mattias Hedlund, mathed-8.
 @author Fredrik Jonsson, frejon-9.
 @author David Åberg, davabe-9 all students at Luleå University of Technology.
 */

import javax.media.*;
import javax.media.format.*;
import java.awt.*;
import java.io.IOException;

public class MotionDetectionEffect implements Effect {
    /**
     * The initial square side.
     */
    private final static int INITIAL_SQUARE_SIZE = 5;

    public final static Format[] supportedFormat = new Format[] { // 
    new RGBFormat(null, //
            Format.NOT_SPECIFIED, // 
            Format.byteArray, //
            Format.NOT_SPECIFIED, //
            24//
            321//
            3, Format.NOT_SPECIFIED, //
            Format.TRUE, //
            Format.NOT_SPECIFIED//
    };

    private Format inputFormat;

    private Format outputFormat;

    private Format[] inputFormats;

    private Format[] outputFormats;

    private int[] bwPixels;

    private byte[] bwData;

    /**
     * Visual mode is set.
     */
    private boolean visualize = true;

    /**
     * Server mode is set.
     */
    private boolean serverActive = true;

    /**
     * Update requested is set.
     */
    private boolean updateRequested;

    private int avg_ref_intensity;

    private int avg_img_intensity;

    /**
     * The RGBFormat of the inbuffer.
     */
    private RGBFormat vfIn = null;

    /**
     * Four different thresholds. Set initial values here.
     */
    private int[] threshs = 20304050 };

    private int det_thresh = threshs[1];

    /**
     *  The corresponding colours to the four different thresholds.
     */
    private int[] colors = 0x00FF00000x00FF99000x00FFFF000x00FFFFFF };

    /**
     *  The mean values of all squares in an image.
     */
    private int[] newImageSquares = null;

    /**
     *  The mean values of all squares in an image.
     */
    private int[] oldImageSquares = null;

    /**
     *  The difference of all the mean values of all squares in an image.
     */
    private int[] changedSquares = null;

    /**
     * The number of squares fitted in the image.
     */
    private int numberOfSquaresWide;

    /**
     * The number of squares fitted in the image.
     */
    private int numberOfSquaresHigh;

    /**
     * The number of squares fitted in the image.
     */
    private int numberOfSquares;

    /**
     * The square side, in pixels.
     */
    private int sqSide = INITIAL_SQUARE_SIZE;

    /**
     * The square area, in pixels.
     */
    private int sqArea = 0;

    /**
     * The amount of pixels left when all normal sized squares have been removed.
     */
    private int sqWidthLeftover = 0;

    /**
     * The amount of pixels left when all normal sized squares have been removed.
     */
    private int sqHeightLeftover = 0;

    /**
     * Optional, less processing is needed if some pixels are left out during some of the calculations.
     */
    private int pixelSpace = 0;

    /**
     * Image property.
     */
    private int imageWidth = 0;

    /**
     * Image property.
     */
    private int imageHeight = 0;

    /**
     * Image property.
     */
    private int imageArea = 0;

    /**
     * Initialize the effect plugin.
     */
    public MotionDetectionEffect() {
        inputFormats = new Format[] { new RGBFormat(null, Format.NOT_SPECIFIED, Format.byteArray, Format.NOT_SPECIFIED, 243213, Format.NOT_SPECIFIED, Format.TRUE, Format.NOT_SPECIFIED) };

        outputFormats = new Format[] { new RGBFormat(null, Format.NOT_SPECIFIED, Format.byteArray, Format.NOT_SPECIFIED, 243213, Format.NOT_SPECIFIED, Format.TRUE, Format.NOT_SPECIFIED) };

    }

    /**
     * Get the inputformats that we support.
     @return  All supported Formats.
     */
    public Format[] getSupportedInputFormats() {
        return inputFormats;
    }

    /**
     * Get the outputformats that we support.
     @param input the current inputformat.
     @return  All supported Formats.
     */
    public Format[] getSupportedOutputFormats(Format input) {
        if (input == null) {
            return outputFormats;
        }
        if (matches(input, inputFormats!= null) {
            return new Format[] { outputFormats[0].intersects(input) };
        else {
            return new Format[0];
        }
    }

    /**
     * Set the input format.
     
     */
    public Format setInputFormat(Format input) {
        inputFormat = input;
        return input;
    }

    /**
     * Set our output format.
     *
     */
    public Format setOutputFormat(Format output) {

        if (output == null || matches(output, outputFormats== null)
            return null;

        RGBFormat incoming = (RGBFormatoutput;

        Dimension size = incoming.getSize();
        int maxDataLength = incoming.getMaxDataLength();
        int lineStride = incoming.getLineStride();
        float frameRate = incoming.getFrameRate();
        int flipped = incoming.getFlipped();
        int endian = incoming.getEndian();

        if (size == null)
            return null;
        if (maxDataLength < size.width * size.height * 3)
            maxDataLength = size.width * size.height * 3;
        if (lineStride < size.width * 3)
            lineStride = size.width * 3;
        if (flipped != Format.FALSE)
            flipped = Format.FALSE;

        outputFormat = outputFormats[0].intersects(new RGBFormat(size, maxDataLength, null, frameRate, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, lineStride, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED));

        return outputFormat;
    }

    /**
     * Process the buffer. This is where motion is analysed and optionally visualized.
     *
     */

    public synchronized int process(Buffer inBuffer, Buffer outBuffer) {
        int outputDataLength = ((VideoFormatoutputFormat).getMaxDataLength();
        validateByteArraySize(outBuffer, outputDataLength);
        outBuffer.setLength(outputDataLength);
        outBuffer.setFormat(outputFormat);
        outBuffer.setFlags(inBuffer.getFlags());

        byte[] inData = (byte[]) inBuffer.getData();
        byte[] outData = (byte[]) outBuffer.getData();
        int[] sqAvg = null;
        int[] refsqAvg = null;

        vfIn = (RGBFormatinBuffer.getFormat();
        Dimension sizeIn = vfIn.getSize();

        int pixStrideIn = vfIn.getPixelStride();
        int lineStrideIn = vfIn.getLineStride();

        imageWidth = (vfIn.getLineStride()) 3//Divide by 3 since each pixel has 3 colours.
        imageHeight = ((vfIn.getMaxDataLength()) 3/ imageWidth;
        imageArea = imageWidth * imageHeight;

        int r, g, b = 0//Red, green and blue values.

        if (oldImageSquares == null) { //For the first frame.
            changeSqSize(INITIAL_SQUARE_SIZE);
            updateRequested = true;
        }

        //Copy all data from the inbuffer to the outbuffer. The purpose is to display the video input on the screen.
        System.arraycopy(inData, 0, outData, 0, outData.length);

        // Simplify the image to black and white, image information shrinks to one third of the original amount. Less processing needed.
        bwPixels = new int[outputDataLength / 3];
        for (int ip = 0; ip < outputDataLength; ip += 3) {
            int bw = 0;
            r = (intinData[ip0xFF;
            g = (intinData[ip + 10xFF;
            b = (intinData[ip + 20xFF;
            bw = (int) ((r + b + g(double3);
            bwPixels[ip / 3= bw; //Now containing a black and white image. 
        }

        if (updateRequested) {
            updateRequested = false;
            updateSquares();
            return BUFFER_PROCESSED_OK;
        else {
            updateSquares();
            oldNewChange();
            int c = 0;
            for (int i = 0; i < changedSquares.length; i++) {
                if (changedSquares[i> det_thresh) {
                    c++;
                }
            }

            if (c > 10 && serverActive) {
                //    try{
                System.out.println("Motion detected (motion at " + c + "areas");
                //      multicast.send("Motion detected");  - Disabled
                //    } catch(IOException e){}
            }

            // If chosen, the detected motion is presented on top of the video input, thus covering the edges of the moving object. 
            if (visualize) {
                for (int i = 1; i <= numberOfSquares; i++) { // For all blobs
                    if ((changedSquares[i - 1> threshs[0])) { // Critical threshold, if less, then no motion is said to have occured.
                        if (((i % numberOfSquaresWide!= 0&& (numberOfSquares - i> numberOfSquaresWide) {//Normal square, the other cases is not presented!
                            int begin ((((i % numberOfSquaresWide1* sqSide((i / numberOfSquaresWide* imageWidth * sqSide)) 3//Calculate start of square.

                            if (changedSquares[i - 1> threshs[3]) { //Very strong motion.
                                b = (byte) (colors[30xFF);
                                g = (byte) ((colors[3>> 80xFF);
                                r = (byte) ((colors[3>> 160xFF);
                            else if (changedSquares[i - 1> threshs[2]) { //Strong motion.
                                b = (byte) (colors[20xFF);
                                g = (byte) ((colors[2>> 80xFF);
                                r = (byte) ((colors[2>> 160xFF);
                            else if (changedSquares[i - 1> threshs[1]) { //Weak motion.
                                b = (byte) (colors[10xFF);
                                g = (byte) ((colors[1>> 80xFF);
                                r = (byte) ((colors[1>> 160xFF);
                            else //The Weakest motion detected.
                                b = (byte) (colors[00xFF);
                                g = (byte) ((colors[0>> 80xFF);
                                r = (byte) ((colors[0>> 160xFF);
                            }
                            for (int k = begin; k < (begin (sqSide * imageWidth * 3)); k = k + (imageWidth * 3)) { //Ev <=
                                for (int j = k; j < (k + (sqSide * 3)); j = j + 3) {
                                    try {
                                        outData[j(byteb;
                                        outData[j + 1(byteg;
                                        outData[j + 2(byter;
                                    catch (ArrayIndexOutOfBoundsException e) {
                                        System.out.println("Nullpointer: j = " + j + ". Outdata.length = " + outData.length);
                                        System.exit(1);
                                    }
                                }
                            }

                        }
                    }
                }
            }
        }
        return BUFFER_PROCESSED_OK;
    }

    // Methods for interface PlugIn
    public String getName() {
        return "Motion Detection Codec";
    }

    public void open() {
    }

    public void close() {
    }

    public void reset() {
    }

    // Methods for interface javax.media.Controls
    public Object getControl(String controlType) {
        System.out.println(controlType);
        return null;
    }

    public Object[] getControls() {
        return null;
    }

    // Utility methods.
    public Format matches(Format in, Format outs[]) {
        for (int i = 0; i < outs.length; i++) {
            if (in.matches(outs[i]))
                return outs[i];
        }

        return null;
    }

    // Credit : example at www.java.sun.com
    byte[] validateByteArraySize(Buffer buffer, int newSize) {
        Object objectArray = buffer.getData();
        byte[] typedArray;

        if (objectArray instanceof byte[]) { // Has correct type and is not null
            typedArray = (byte[]) objectArray;
            if (typedArray.length >= newSize) { // Has sufficient capacity
                return typedArray;
            }

            byte[] tempArray = new byte[newSize]// Reallocate array
            System.arraycopy(typedArray, 0, tempArray, 0, typedArray.length);
            typedArray = tempArray;
        else {
            typedArray = new byte[newSize];
        }

        buffer.setData(typedArray);
        return typedArray;
    }

    /**
     * Sets the current pixelspace, default is zero.
     * This is mainly for use where limited processing capacity are availible. Some pixels are left out in the calculations.
     @param newSpace the space between two successive pixels.
     */
    private void setPixelSpace(int newSpace) {
        pixelSpace = newSpace;
    }

    /**
     * Changes the size of the square shaped area that divides the detection area into many small parts.
     @param newSide the side of the square, in pixels.
     */
    private void changeSqSize(int newSide) {
        sqSide = newSide;
        sqArea = newSide * newSide;
        int wid = (imageWidth / sqSide)//The number of squares wide.
        int hei = (imageHeight / sqSide)//The number of squares high.
        sqWidthLeftover = imageWidth % sqSide;
        sqHeightLeftover = imageHeight % sqSide;
        if (sqWidthLeftover > 0) {
            wid++;
        }
        if (sqHeightLeftover > 0) {
            hei++;
        }

        numberOfSquaresWide = wid;
        numberOfSquaresHigh = hei;
        numberOfSquares = wid * hei;

        newImageSquares = new int[numberOfSquares];
        oldImageSquares = new int[numberOfSquares];
        changedSquares = new int[numberOfSquares];
    }

    /**
     * Calculates the average colour in each square thus indirect eliminate noise.
     @param startX the starting position of this square, in pixels, left edge.
     @param startY the starting position of this square, in pixels, bottom edge.
     @param sqWidth the width of this square, in pixels.
     @param sqHeight the height of this square, in pixels.
     @return The average greyscale value for this square.
     */
    private int averageInSquare(int startX, int startY, int sqWidth, int sqHeight) {
        int average = 0;
        for (int i = 0; i < sqHeight; i = i + + pixelSpace) {// For all pixels
            for (int j = 0; j < sqWidth; j = j + + pixelSpace) {
                average += bwPixels[(((startY + i* imageWidth(startX + j))]//Sum all the pixel values.
            }
        }
        average = average / (sqWidth * sqHeight)//Divide by the number of pixels to get the average value.
        return average;
    }

    /**
     * Backup the most recent frame examined. For the new frame, calculate the average greyscale value for all squares.
     */
    private void updateSquares() {
        System.arraycopy(newImageSquares, 0, oldImageSquares, 0, newImageSquares.length);
        int sqCount = 0//Keep track of the current square
        for (int j = 0; j < (imageHeight); j = j + sqSide) { //For all squares
            for (int i = 0; i < (imageWidth); i = i + sqSide) {
                if (i <= (imageWidth - sqSide&& j <= (imageHeight - sqSide)) {
                    newImageSquares[sqCount= averageInSquare(i, j, sqSide, sqSide)//No edge!
                else if (i > (imageWidth - sqSide&& j <= (imageHeight - sqSide)) {
                    newImageSquares[sqCount= averageInSquare(i, j, sqWidthLeftover, sqSide)//Right edge!
                else if (i <= (imageWidth - sqSide&& j > (imageHeight - sqSide)) {
                    newImageSquares[sqCount= averageInSquare(i, j, sqSide, sqHeightLeftover)//Bottom edge!
                else if (i > (imageWidth - sqSide&& j > (imageHeight - sqSide)) {
                    newImageSquares[sqCount= averageInSquare(i, j, sqWidthLeftover, sqHeightLeftover)//Bottom right edge!
                }
                sqCount++;
            }
        }
    }

    /**
     * Calculate the difference per square between currently stored frames. 
     */
    private void oldNewChange() {
        for (int i = 0; i <= (numberOfSquares - 1); i++) { //For all squares
            int difference = Math.abs((newImageSquares[i]) (oldImageSquares[i]))//Compare each square with the corresponding square in the previous frame.
            changedSquares[i= difference; //Save the difference.
        }
    }

    public synchronized void updateModel(boolean visualize, boolean serverActive, boolean simplified, int[] threshs, int[] colors, int sqSide, int det_thresh) {

        this.visualize = visualize;
        this.serverActive = serverActive;
        if (sqSide != this.sqSide)
            changeSqSize(sqSide);
        if (!simplified) {
            System.out.println((colors == null" " (this.colors == null));
            System.arraycopy(colors, 0this.colors, 0, colors.length);
            System.arraycopy(threshs, 0this.threshs, 0, colors.length);
            this.det_thresh = det_thresh;
            System.out.println("New det_threhsh: " this.det_thresh);
        }
        updateRequested = true;
    }

    /**
     *Check if the visualize variable is set.
     *@returns the current value.
     */
    public boolean isVisual() {
        return visualize;
    }

    /**
     *Get the current threshold values in a vector.
     *@returns the current values.
     */
    public int[] getThreshholds() {
        return threshs;
    }

    /**
     *Check if the server is active.
     *@returns the current value.
     */
    public boolean isServerActive() {
        return serverActive;
    }

    public int[] getColors() {
        return colors;
    }

    /**
     *Get the current square side.
     *@returns the current value.
     */
    public int getSqSide() {
        return sqSide;
    }

}

   
    
  
Related examples in the same category
1.Query the installed version of the JMFQuery the installed version of the JMF
2.Select a media file from tjelocal file system and gain statistics
3.Renderer for RGB images using AWT Image using Java Media API
4.javax.media
5.Media player
6.Sample program to demonstrate FramePositioningControl.
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.