Hi,
Hoping someone can help. I'm trying to do motion detection on my little android, but it needs optimising. There's quite a few things I need to look out for:
1) Moving grass. Can get quite long at times!
2) Noise. It's a low quality camera
3) Dark picture. I want this to work until as late as possible (it'll turn itself off when the picture gets too dark and wait til the morning)
This is what I have so far:
http://www.mikeefranklin.co.uk/birds/birdy2.html
This is working perfectly. So long as I have ONE white pixel there, it's doing its job - and that's with each pixel 'noised' by 20% on both the previous frame and the current frame.
This is my 'optimised' java version that I tried to make:
java code:
package com.mikeefranklin.birdcam;
import android.util.Log;
public class Detector {
int[] previous_frame;
public Detector() {
}
public boolean detect(int[] data, int width, int height)
{
// greyscale first
int min = 255;
int max = 0;
int i = 0;
for(int y=0; y<height; y++){
for(int x=0; x<width; x++){
int avg = ((data[i] + data[i + 1] + data[i + 2]) / 3);
data[i] = avg;
data[i + 1] = avg;
data[i + 2] = avg;
min = Math.min(min, avg);
max = Math.max(max, avg);
i += 3;
}
}
int[] diff_data;
if (previous_frame != null){
diff_data = new int[data.length];
}else {
diff_data = new int[0];
}
// normalize it to deal with low contrast
int dist = Math.max(1, max - min);
i = 0;
boolean hasChange = false;
for(int y=0; y<height; y++){
for(int x=0; x<width; x++){
int newgrey = ((data[i] - min) / dist) * 255;
data[i] = newgrey;
data[i + 1] = newgrey;
data[i + 2] = newgrey;
// if theres a previous frame, lets do a diff on it
if (previous_frame != null) {
// but first, lets morph 30% of the background in
diff_data[i] = ((int)(0.7*(data[i]) ) + (int)(0.3*(previous_frame[i]))) - previous_frame[i];
diff_data[i] = ( diff_data[i] < 0 ) ? -diff_data[i] : diff_data[i];
diff_data[i] = diff_data[i] > 40 ? 255 : 0;
diff_data[i+1] = diff_data[i+2] = diff_data[i];
if (diff_data[i] == 255) {
hasChange = true;
}
}
i += 3;
}
}
// save old frame, or return false here if theres no change at all yet
previous_frame = data;
if (previous_frame == null || !hasChange){
return false;
}
// if there's change, we'll erode any pixels that have a black pixel within 4 of itself
i = 0;
int ii = 0;
int size = 2;
for(int y=0; y<height; y++){
for(int x=0; x<width; x++){
boolean erode = false;
if (diff_data[i] == 255){
for (int yi=-size;yi<=size;yi++){
for (int xi=-size;xi<=size;xi++){
int px = ((y+yi) * 3) * width + (x+xi) * 3;
if (diff_data[px] == 0){
erode = true;
break;
}
ii += 3;
}
}
// break early if there's no erosion to be had
if (!erode){
return true;
}
}
i += 3;
}
}
return false;
}
}
Anyone got any ideas I could try?
I really do need accuracy, because my last version was resulting in way too many false positives.