Skip to content

Commit

Permalink
Updated the HSL conversions and the state detector
Browse files Browse the repository at this point in the history
git-svn-id: https://android-motion-detection.googlecode.com/svn/trunk@13 996b93ed-3e4d-4b21-1044-74bd19560d1d
  • Loading branch information
[email protected] committed Aug 29, 2011
1 parent 74d0316 commit b9d911e
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 105 deletions.
11 changes: 7 additions & 4 deletions src/com/jwetherell/motion_detection/MotionDetectionActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ public void onPreviewFrame(byte[] data, Camera cam) {
Camera.Size size = cam.getParameters().getPreviewSize();
if (size == null) return;

DetectionThread thread = new DetectionThread(data,size.width,size.height);
thread.start();
DetectionThread thread = new DetectionThread(data,size.width,size.height);
thread.start();
}
};

Expand Down Expand Up @@ -150,7 +150,7 @@ public DetectionThread(byte[] data, int width, int height) {
@Override
public void run() {
if (!processing.compareAndSet(false, true)) return;

Looper.prepare();
Log.d(TAG, "BEGIN PROCESSING...");
try {
Expand All @@ -159,7 +159,10 @@ public void run() {
if (SAVE_PREVIOUS) pre = MotionDetection.getPrevious();

//Current frame (with changes)
int[] rgb = ImageProcessing.decodeYUV420SP(data, width, height);
long bRGB = System.currentTimeMillis();
int[] rgb = ImageProcessing.decodeYUV420SPtoRGB(data, width, height);
long aRGB = System.currentTimeMillis();
Log.d(TAG, "Convert to RGB "+(aRGB-bRGB));

//Current frame (without changes)
int[] org = null;
Expand Down
48 changes: 26 additions & 22 deletions src/com/jwetherell/motion_detection/detection/Comparer.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,36 +34,37 @@ public Comparison compare(State s1, State s2) {
if (s1==null || s2==null) return null;
if (s1.getWidth()!=s2.getWidth() || s1.getHeight()!=s2.getHeight()) return null;

int cx = comparex;
if (cx > s1.getWidth()) cx = s1.getWidth();
int cy = comparey;
if (cy > s1.getHeight()) cy = s1.getHeight();
// number of boxes
int xBoxes = comparex;
if (xBoxes > s1.getWidth()) xBoxes = s1.getWidth();
int yBoxes = comparey;
if (yBoxes > s1.getHeight()) yBoxes = s1.getHeight();

// how many points per section
int bx = (int)(Math.floor(s1.getWidth() / cx));
if (bx <= 0) bx = 1;
int by = (int)(Math.floor(s1.getHeight() / cy));
if (by <= 0) by = 1;
int[][] variance = new int[cy][cx];
// how many points per box
int xPixelsPerBox = (int)(Math.floor(s1.getWidth() / xBoxes));
if (xPixelsPerBox <= 0) xPixelsPerBox = 1;
int yPixelsPerBox = (int)(Math.floor(s1.getHeight() / yBoxes));
if (yPixelsPerBox <= 0) yPixelsPerBox = 1;
int[][] variance = new int[yBoxes][xBoxes];

// set to a different by default, if a change is found then flag non-match
boolean different = false;
// loop through whole image and compare individual blocks of images
int ty = 0;
for (int y = 0; y < cy; y++) {
for (int y = 0; y < yBoxes; y++) {
StringBuilder output = new StringBuilder();
if (debugMode > 0) output.append("|");
ty = y*by;
for (int x = 0; x < cx; x++) {
int tx = x*bx;
int b1 = aggregateMapArea(s1.getMap(), tx, ty, bx, by);
int b2 = aggregateMapArea(s2.getMap(), tx, ty, bx, by);
ty = y*yPixelsPerBox;
for (int x = 0; x < xBoxes; x++) {
int tx = x*xPixelsPerBox;
int b1 = aggregateMapArea(s1.getMap(), tx, ty, xPixelsPerBox, yPixelsPerBox);
int b2 = aggregateMapArea(s2.getMap(), tx, ty, xPixelsPerBox, yPixelsPerBox);
int diff = Math.abs(b1 - b2);
variance[y][x] = diff;
// the difference in a certain region has passed the threshold value
if (diff > leniency) different = true;
if (debugMode == 1) output.append((diff > leniency ? "X" : " "));
if (debugMode == 2) output.append(diff + (x < cx - 1 ? "," : ""));
if (debugMode == 1) output.append((different ? "X" : " "));
if (debugMode == 2) output.append(diff + (x < xBoxes - 1 ? "," : ""));
}
if (debugMode > 0) {
output.append("|");
Expand All @@ -77,11 +78,14 @@ private static int aggregateMapArea(int[][] map, int ox, int oy, int w, int h) {
if (map==null) return Integer.MIN_VALUE;

int t = 0;
for (int i = 0; i < h; i++) {
int ty = oy+i;
for (int j = 0; j < w; j++) t += map[ty][ox+j];
for (int y = 0; y < h; y++) {
int ty = oy+y;
for (int x = 0; x < w; x++) {
int tx = ox+x;
t += map[ty][tx];
}
}
return (int)(t/(w*h));
return (t/(w*h));
}

public int getComparex() {
Expand Down
40 changes: 26 additions & 14 deletions src/com/jwetherell/motion_detection/detection/Comparison.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.jwetherell.motion_detection.detection;

import android.graphics.Color;

/**
* This class is adapted from the web site below. It is used to indicate the variance in two state objects.
* http://mindmeat.blogspot.com/2008/11/java-image-comparison.html
Expand All @@ -25,25 +27,35 @@ public Comparison(State s1, State s2, int[][] variance, boolean different) {
this.height = variance.length;
this.width = variance[0].length;
}

/*
public BufferedImage getChangeIndicator(BufferedImage cx, Comparer comparer) {
// setup change display image
Graphics2D gc = cx.createGraphics();
gc.setColor(Color.RED);

float bx = (cx.getWidth() / width);
float by = (cx.getHeight() / height);
public void getChangeIndicator(int[] data, int width, int height, Comparer comparer) {
int bx = (width / this.width);
int by = (height / this.height);

int tx = 0;
int ty = 0;
for (int y = 0; y < by; y++) {
ty = (int)(y * by);
for (int x = 0; x < bx; x++) {
tx = (int)(x * bx);
if (variance[y][x] > comparer.getLeniency()) {
paintArea(data,tx,ty,bx,by);
}
}
}
}

private static void paintArea(int[] data, int ox, int oy, int w, int h) {
if (data==null) return;

for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (variance[y][x] > comparer.leniency)
gc.drawRect((int)(x * bx), (int)(y * by), (int)bx, (int)by);
int ty = 0;
for (int y = 1; y <= h; y++) {
ty = oy*y;
for (int x = 0, xy=ty; x < w; x++, xy++) {
data[xy] = Color.RED;
}
}
return cx;
}
*/

public int[][] getVariance() {
return variance;
Expand Down
58 changes: 34 additions & 24 deletions src/com/jwetherell/motion_detection/detection/MotionDetection.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@ public abstract class MotionDetection {
private static final boolean USE_RGB = true;
private static final boolean USE_HSL = false;
private static final boolean USE_STATE = false;
private static final int mThreshold = 10000; //Number of different pixels
private static final int mPixelThreshold = 50; //Difference in pixel

//RGB Specific settings
private static final int mRgbThreshold = 10000; //Number of different pixels
private static final int mRgbPixelThreshold = 50; //Difference in pixel

//HSL Specific settings
private static final int mHslThreshold = 1000; //Number of different pixels
private static final int mHslPixelThreshold = 1; //Difference in brightness

private static int[] mPrevious = null;
private static int mPreviousWidth = 0;
private static int mPreviousHeight = 0;
Expand All @@ -33,26 +39,27 @@ protected static boolean isDifferentComparingState(int[] first, int width, int h
if (mPreviousWidth != width || mPreviousHeight != height) return true;

if (mPreviousState==null) mPreviousState = new State(mPrevious, mPreviousWidth, mPreviousHeight);

State state = new State(first, width, height);
Comparer ic = new Comparer((width/10), (height/10), 0);

Comparer ic = new Comparer((width/10), (height/10), 25);
ic.setDebugMode(1);
Comparison c = ic.compare(mPreviousState, state);
Comparison c = ic.compare(state,mPreviousState);

boolean different = c.isDifferent();
String output = "isDifferent="+different;
if (different) {
Log.e(TAG, output);
c.getChangeIndicator(first, width, height, ic);
} else {
Log.d(TAG, output);
}

mPreviousState = state;
mPreviousState = state.clone();

return different;
}
protected static boolean isDifferentComparingRGB(int[] first, int width, int height) {

protected static boolean isDifferentComparingHSL(int[] first, int width, int height) {
if (first==null || mPrevious==null) return false;
if (first.length != mPrevious.length) return true;
if (mPreviousWidth != width || mPreviousHeight != height) return true;
Expand All @@ -71,15 +78,18 @@ protected static boolean isDifferentComparingRGB(int[] first, int width, int hei
if (otherPix < 0) otherPix = 0;
if (otherPix > 255) otherPix = 255;

if (Math.abs(pix - otherPix) >= mPixelThreshold) {
int b1 = ImageProcessing.getBrightnessAtPoint(pix);
int b2 = ImageProcessing.getBrightnessAtPoint(otherPix);

if (Math.abs(b1 - b2) >= mHslPixelThreshold) {
totDifferentPixels++;
//Paint different pixel red
first[ij] = Color.RED;
}
}
}
if (totDifferentPixels <= 0) totDifferentPixels = 1;
boolean different = totDifferentPixels > mThreshold;
boolean different = totDifferentPixels > mHslThreshold;

int percent = 100/(size/totDifferentPixels);
String output = "Number of different pixels: " + totDifferentPixels + "> " + percent + "%";
Expand All @@ -92,7 +102,7 @@ protected static boolean isDifferentComparingRGB(int[] first, int width, int hei
return different;
}

protected static boolean isDifferentComparingHSL(int[] first, int width, int height) {
protected static boolean isDifferentComparingRGB(int[] first, int width, int height) {
if (first==null || mPrevious==null) return false;
if (first.length != mPrevious.length) return true;
if (mPreviousWidth != width || mPreviousHeight != height) return true;
Expand All @@ -111,18 +121,15 @@ protected static boolean isDifferentComparingHSL(int[] first, int width, int hei
if (otherPix < 0) otherPix = 0;
if (otherPix > 255) otherPix = 255;

float b1 = ImageProcessing.getBrightnessAtPoint(pix);
float b2 = ImageProcessing.getBrightnessAtPoint(otherPix);

if (Math.abs(b1 - b2) >= mPixelThreshold) {
if (Math.abs(pix - otherPix) >= mRgbPixelThreshold) {
totDifferentPixels++;
//Paint different pixel red
first[ij] = Color.RED;
}
}
}
if (totDifferentPixels <= 0) totDifferentPixels = 1;
boolean different = totDifferentPixels > mThreshold;
boolean different = totDifferentPixels > mRgbThreshold;

int percent = 100/(size/totDifferentPixels);
String output = "Number of different pixels: " + totDifferentPixels + "> " + percent + "%";
Expand All @@ -134,10 +141,10 @@ protected static boolean isDifferentComparingHSL(int[] first, int width, int hei

return different;
}

public static boolean detect(int[] data, int width, int height) {
if (data==null) return false;
int[] original = data.clone();
public static boolean detect(int[] rgb, int width, int height) {
if (rgb==null) return false;
int[] original = rgb.clone();

// Create the "mPrevious" picture, the one that will be used to check the next frame against.
if(mPrevious == null) {
Expand All @@ -148,11 +155,14 @@ public static boolean detect(int[] data, int width, int height) {
return false;
}

long bDetection = System.currentTimeMillis();
boolean motionDetected = false;
if (USE_RGB) motionDetected = isDifferentComparingRGB(data, width, height);
if (USE_HSL) motionDetected = isDifferentComparingHSL(data, width, height);
if (USE_STATE) motionDetected = isDifferentComparingState(data, width, height);

if (USE_RGB) motionDetected = isDifferentComparingRGB(rgb, width, height);
if (USE_HSL) motionDetected = isDifferentComparingHSL(rgb, width, height);
if (USE_STATE) motionDetected = isDifferentComparingState(rgb, width, height);
long aDetection = System.currentTimeMillis();
Log.d(TAG, "Detection "+(aDetection-bDetection));

// Replace the current image with the previous.
mPrevious = original;
mPreviousWidth = width;
Expand Down
39 changes: 33 additions & 6 deletions src/com/jwetherell/motion_detection/detection/State.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,18 @@
* @author Justin Wetherell <[email protected]>
*/
public class State {
private int[][] map;
private int[][] map = null;
private int width;
private int height;
private int average;

public State(State other) {
this.map = other.map.clone();
this.width = other.width;
this.height = other.height;
this.average = other.average;
}

public State(int[] data, int width, int height) {
if (data==null) return;

Expand All @@ -27,15 +34,14 @@ public State(int[] data, int width, int height) {

// build map and stats
average = 0;
int ta = 0;
for (int y = 0; y < height; y++) {
for (int x = 0, xy = 0; x < width; x++, xy++) {
ta = (int)(100*ImageProcessing.getBrightnessAtPoint(data[xy]));
for (int y = 0, xy=0; y < this.height; y++) {
for (int x = 0; x < this.width; x++, xy++) {
int ta = ImageProcessing.getBrightnessAtPoint(data[xy]);
map[y][x] = ta;
average += ta;
}
}
average = (int)(average / (width * height));
average = (average / (this.width * this.height));
}

public int[][] getMap() {
Expand All @@ -49,4 +55,25 @@ public int getWidth() {
public int getHeight() {
return height;
}

@Override
public String toString() {
StringBuilder output = new StringBuilder();
output.append("h="+height+" w="+width+"\n");
for (int y = 0; y < height; y++) {
output.append('|');
for (int x = 0;x < width; x++) {
output.append(map[y][x]);
output.append('|');
}
output.append("\n");
}
return output.toString();
}

@Override
public State clone() {
State newState = new State(this);
return newState;
}
}
Loading

0 comments on commit b9d911e

Please sign in to comment.