From 50fd09349e4bf5dda19b3cd0f198c2aad91a6fd0 Mon Sep 17 00:00:00 2001 From: "phishman3579@gmail.com" Date: Tue, 30 Aug 2011 04:25:17 +0000 Subject: [PATCH] Updated the HSL code to use luma instead git-svn-id: https://android-motion-detection.googlecode.com/svn/trunk@14 996b93ed-3e4d-4b21-1044-74bd19560d1d --- .../MotionDetectionActivity.java | 32 +++++-- .../detection/MotionDetection.java | 39 ++++---- .../motion_detection/detection/State.java | 7 +- .../image/ImageProcessing.java | 91 ++++--------------- 4 files changed, 60 insertions(+), 109 deletions(-) diff --git a/src/com/jwetherell/motion_detection/MotionDetectionActivity.java b/src/com/jwetherell/motion_detection/MotionDetectionActivity.java index 2681ed9..341fcc9 100644 --- a/src/com/jwetherell/motion_detection/MotionDetectionActivity.java +++ b/src/com/jwetherell/motion_detection/MotionDetectionActivity.java @@ -159,16 +159,21 @@ public void run() { if (SAVE_PREVIOUS) pre = MotionDetection.getPrevious(); //Current frame (with changes) - long bRGB = System.currentTimeMillis(); - int[] rgb = ImageProcessing.decodeYUV420SPtoRGB(data, width, height); - long aRGB = System.currentTimeMillis(); - Log.d(TAG, "Convert to RGB "+(aRGB-bRGB)); + long bConversion = System.currentTimeMillis(); + int[] img = null; + if (MotionDetection.USE_RGB) { + img = ImageProcessing.decodeYUV420SPtoRGB(data, width, height); + } else { + img = ImageProcessing.decodeYUV420SPtoLuminescence(data, width, height); + } + long aConversion = System.currentTimeMillis(); + Log.d(TAG, "Converstion="+(aConversion-bConversion)); //Current frame (without changes) int[] org = null; - if (SAVE_ORIGINAL && rgb!=null) org = rgb.clone(); + if (SAVE_ORIGINAL && img!=null) org = img.clone(); - if (rgb!=null && MotionDetection.detect(rgb, width, height)) { + if (img!=null && MotionDetection.detect(img, width, height)) { // The delay is necessary to avoid taking a picture while in the // middle of taking another. This problem can causes some phones // to reboot. @@ -177,13 +182,22 @@ public void run() { mReferenceTime = now; Bitmap previous = null; - if (SAVE_PREVIOUS && pre!=null) previous = ImageProcessing.rgbToBitmap(pre, width, height); + if (SAVE_PREVIOUS && pre!=null) { + if (MotionDetection.USE_RGB) previous = ImageProcessing.rgbToBitmap(pre, width, height); + else previous = ImageProcessing.lumToGreyscale(img, width, height); + } Bitmap original = null; - if (SAVE_ORIGINAL && org!=null) original = ImageProcessing.rgbToBitmap(org, width, height); + if (SAVE_ORIGINAL && org!=null) { + if (MotionDetection.USE_RGB) original = ImageProcessing.rgbToBitmap(org, width, height); + else original = ImageProcessing.lumToGreyscale(img, width, height); + } Bitmap bitmap = null; - if (SAVE_CHANGES && rgb!=null) bitmap = ImageProcessing.rgbToBitmap(rgb, width, height); + if (SAVE_CHANGES && img!=null) { + if (MotionDetection.USE_RGB) bitmap = ImageProcessing.rgbToBitmap(img, width, height); + else bitmap = ImageProcessing.lumToGreyscale(img, width, height); + } Log.i(TAG,"Saving.. previous="+previous+" original="+original+" bitmap="+bitmap); new SavePhotoTask().execute(previous,original,bitmap); diff --git a/src/com/jwetherell/motion_detection/detection/MotionDetection.java b/src/com/jwetherell/motion_detection/detection/MotionDetection.java index 53b4908..d0e22cf 100644 --- a/src/com/jwetherell/motion_detection/detection/MotionDetection.java +++ b/src/com/jwetherell/motion_detection/detection/MotionDetection.java @@ -1,10 +1,9 @@ package com.jwetherell.motion_detection.detection; -import com.jwetherell.motion_detection.image.ImageProcessing; - import android.graphics.Color; import android.util.Log; + /** * This abstract class is used to process integer arrays containing RGB data and detects motion. * @@ -12,23 +11,20 @@ */ public abstract class MotionDetection { private static final String TAG = "MotionDetection"; - private static final boolean USE_RGB = true; - private static final boolean USE_HSL = false; - private static final boolean USE_STATE = false; - - //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 - + //Specific settings + private static final int mThreshold = 10000; //Number of different pixels + private static final int mPixelThreshold = 50; //Difference in pixel + private static int[] mPrevious = null; private static int mPreviousWidth = 0; private static int mPreviousHeight = 0; private static State mPreviousState = null; + public static final boolean USE_RGB = true; + public static final boolean USE_LUM = false; + public static final boolean USE_STATE = false; + public static int[] getPrevious() { return ((mPrevious!=null)?mPrevious.clone():null); } @@ -54,12 +50,12 @@ protected static boolean isDifferentComparingState(int[] first, int width, int h Log.d(TAG, output); } - mPreviousState = state.clone(); + mPreviousState = state; return different; } - protected static boolean isDifferentComparingHSL(int[] first, int width, int height) { + protected static boolean isDifferentComparingLuminescence(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; @@ -78,10 +74,7 @@ protected static boolean isDifferentComparingHSL(int[] first, int width, int hei if (otherPix < 0) otherPix = 0; if (otherPix > 255) otherPix = 255; - int b1 = ImageProcessing.getBrightnessAtPoint(pix); - int b2 = ImageProcessing.getBrightnessAtPoint(otherPix); - - if (Math.abs(b1 - b2) >= mHslPixelThreshold) { + if (Math.abs(pix - otherPix) >= mPixelThreshold) { totDifferentPixels++; //Paint different pixel red first[ij] = Color.RED; @@ -89,7 +82,7 @@ protected static boolean isDifferentComparingHSL(int[] first, int width, int hei } } if (totDifferentPixels <= 0) totDifferentPixels = 1; - boolean different = totDifferentPixels > mHslThreshold; + boolean different = totDifferentPixels > mThreshold; int percent = 100/(size/totDifferentPixels); String output = "Number of different pixels: " + totDifferentPixels + "> " + percent + "%"; @@ -121,7 +114,7 @@ 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) >= mRgbPixelThreshold) { + if (Math.abs(pix - otherPix) >= mPixelThreshold) { totDifferentPixels++; //Paint different pixel red first[ij] = Color.RED; @@ -129,7 +122,7 @@ protected static boolean isDifferentComparingRGB(int[] first, int width, int hei } } if (totDifferentPixels <= 0) totDifferentPixels = 1; - boolean different = totDifferentPixels > mRgbThreshold; + boolean different = totDifferentPixels > mThreshold; int percent = 100/(size/totDifferentPixels); String output = "Number of different pixels: " + totDifferentPixels + "> " + percent + "%"; @@ -158,7 +151,7 @@ public static boolean detect(int[] rgb, int width, int height) { long bDetection = System.currentTimeMillis(); boolean motionDetected = false; if (USE_RGB) motionDetected = isDifferentComparingRGB(rgb, width, height); - if (USE_HSL) motionDetected = isDifferentComparingHSL(rgb, width, height); + if (USE_LUM) motionDetected = isDifferentComparingLuminescence(rgb, width, height); if (USE_STATE) motionDetected = isDifferentComparingState(rgb, width, height); long aDetection = System.currentTimeMillis(); Log.d(TAG, "Detection "+(aDetection-bDetection)); diff --git a/src/com/jwetherell/motion_detection/detection/State.java b/src/com/jwetherell/motion_detection/detection/State.java index 6aacd76..8066015 100644 --- a/src/com/jwetherell/motion_detection/detection/State.java +++ b/src/com/jwetherell/motion_detection/detection/State.java @@ -1,6 +1,5 @@ package com.jwetherell.motion_detection.detection; -import com.jwetherell.motion_detection.image.ImageProcessing; /** * This class is adapted from the web site below. It creates a state object based on the brightness of a RGB image @@ -36,9 +35,9 @@ public State(int[] data, int width, int height) { average = 0; 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; + int lum = data[xy]; + map[y][x] = lum; + average += lum; } } average = (average / (this.width * this.height)); diff --git a/src/com/jwetherell/motion_detection/image/ImageProcessing.java b/src/com/jwetherell/motion_detection/image/ImageProcessing.java index 167ed94..da4c982 100644 --- a/src/com/jwetherell/motion_detection/image/ImageProcessing.java +++ b/src/com/jwetherell/motion_detection/image/ImageProcessing.java @@ -1,11 +1,11 @@ package com.jwetherell.motion_detection.image; import java.io.ByteArrayOutputStream; - import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Color; import android.graphics.Matrix; -import android.util.Log; + /** * This abstract class is used to process images. @@ -74,86 +74,18 @@ public static int[] convertToHSL(int r, int g, int b) { //Since they were converted from float to int return (new int[]{(int)h,(int)s,(int)l}); } - - public static int getBrightnessAtPoint(int pixel) { - //Get RGB from Integer - int r = (pixel >> 16) & 0xff; - int g = (pixel >> 8) & 0xff; - int b = (pixel) & 0xff; - - //Convert RGB to HSL (not using method above because I don't want to create - //an extra float[] for every pixel. - float red = r; - float green = g; - float blue = b; - red = red / 255; - green = green / 255; - blue = blue / 255; - - float h=0,s=0,l=0; - float minComponent = Math.min(red, Math.min(green, blue)); - float maxComponent = Math.max(red, Math.max(green, blue)); - float range = maxComponent - minComponent; - - l = (maxComponent + minComponent) / 2; - - if(range == 0) { // Monochrome image - h = s = 0; - } else { - s = (l > 0.5) ? - range / (2 - range) - : - range / (maxComponent + minComponent); - if (Float.compare(red,maxComponent)==0) { - h = (blue - green) / range; - } else if(Float.compare(green,maxComponent)==0) { - h = 2 + (blue - red) / range; - } else if(Float.compare(blue,maxComponent)==0) { - h = 4 +(red - green) / range; - } else { - Log.e("TAG", "Should not get here!"); - } - } - - //convert to 0-360 - h = h * 60; - if (h<0) h = h + 360; - - //convert to 0-100 - s = s * 100; - l = l * 100; - - //Convert the HSL into a single "brightness" representation - //brightness is between 0-100 using 50% lightness and 50% hue - int brightness = (int)((l * 0.5) + ((h / 360) * 50)); - return brightness; - } - public static int[][] decodeYUV420SPtoHSL(byte[] yuv420sp, int width, int height) { + public static int[] decodeYUV420SPtoLuminescence(byte[] yuv420sp, int width, int height) { if (yuv420sp==null) return null; final int frameSize = width * height; - int[][] hsl = new int[frameSize][3]; + int[] hsl = new int[frameSize]; for (int j = 0, yp = 0; j < height; j++) { - int uvp = frameSize + (j >> 1) * width, u = 0, v = 0; for (int i = 0; i < width; i++, yp++) { int y = (0xff & ((int) yuv420sp[yp])) - 16; if (y < 0) y = 0; - if ((i & 1) == 0) { - v = (0xff & yuv420sp[uvp++]) - 128; - u = (0xff & yuv420sp[uvp++]) - 128; - } - int y1192 = 1192 * y; - int r = (y1192 + 1634 * v); - int g = (y1192 - 833 * v - 400 * u); - int b = (y1192 + 2066 * u); - - if (r < 0) r = 0; else if (r > 262143) r = 262143; - if (g < 0) g = 0; else if (g > 262143) g = 262143; - if (b < 0) b = 0; else if (b > 262143) b = 262143; - - hsl[yp] = convertToHSL(r,g,b); + hsl[yp] = y; } } return hsl; @@ -197,6 +129,19 @@ public static Bitmap rgbToBitmap(int[] rgb, int width, int height) { return bitmap; } + public static Bitmap lumToGreyscale(int[] lum, int width, int height) { + if (lum==null) return null; + + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + for(int y=0, xy=0; y