Motion Detection

From: Mikee26 Jun 2012 10:30
To: ALL13 of 14
Decided to only check a fraction of the pixels. I seem to be getting a similar result, but now it's a bit faster and I can add erosion to clear any dead pixels.

http://www.mikeefranklin.co.uk/birds/birdy2.html

Hopefully this will be enough and HOPEFULLY it'll transfer over to java well enough. In this javascript version I'm having to convert over to YUV first to simulate android so it's a bit slower.

javascript code:
 
fastdetect : function(that){
 
				var half_height = this.pixels.height / 2;
				var half_width = this.pixels.width / 2;
 
				for(var y=0; y<half_height; y++){
					for(var x=0; x<half_width; x++){
						var i = (y * 8) * this.pixels.width + x * 8;
 
						var r = this.pixels.data[i];
						var g = this.pixels.data[i+1];
						var b = this.pixels.data[i+2];
 
						var tr = that.pixels.data[i];
						var tg = that.pixels.data[i+1];
						var tb = that.pixels.data[i+2];
 
						var yuv = rgb_to_yuv(r, g, b);
						var yuv2 = rgb_to_yuv(tr, tg, tb);
 
						var this_col = yuv[0];
						var that_col = yuv2[0];
 
						this_col = (((5 * this_col) + (5 * that_col))/10)-that_col;
 
						if (this_col < 0) this_col = -this_col;
 
						this_col = this_col > 15 ?  255 : 0;
 
						this.pixels.data[i] = this_col;
						this.pixels.data[i+1] = this_col;
						this.pixels.data[i+2] = this_col;
 
					}
				}
				var mask = [];
				for(var y=0; y<half_height; y++){
					for(var x=0; x<half_width; x++){
						var i = (y * 8) * this.pixels.width + x * 8;
						var erode = false;
						if (this.pixels.data[i] == 255){
							for (var yi=-2;yi<=2;yi+=2){
								for (var xi=-2;xi<=2;xi+=2){
									var px = ((y+yi) * 8) * this.pixels.width + (x+xi) * 8;
									if (this.pixels.data[px] == 0){
										erode = true;
										break;
									}
								}
							}
							mask.push({'i' : i, 'erode' : erode ? 0 : 255});
						}else {
							mask.push({'i' : i, 'erode' : 0});
						}
 
					}
				}
				for (var i=0; i<mask.length; i++){
					this.pixels.data[mask[i].i] = mask[i].erode;
					this.pixels.data[mask[i].i+1] = mask[i].erode;
					this.pixels.data[mask[i].i+2] = mask[i].erode;
				}
 
return false;
			}
 
EDITED: 26 Jun 2012 10:31 by MIKEE
From: Mikee26 Jun 2012 11:43
To: ALL14 of 14
This seems to be the fastest, most accurate version yet:

java code:
 
	public boolean detect(byte[] data, int width, int height) {
 
 		// half width and height to reduce loops
		int half_height = height / 2;
		int half_width = width / 2;
 
		// boolean map to hold our threshold pic
		boolean[] map = new boolean[half_height * half_width];
		for (int y = 0, i = 0, ii = 0; y < half_height; y++) {
			for (int x = 0; x < half_width; x++, i+=2,ii++) {
				int l = (0xff & ((int) data[i])) - 16;
				if (previous_frame != null) {
					int pl = (0xff & ((int) previous_frame[i])) - 16;
					int d = pl;
					// merge 50% of each frame, lets not use division
					d = ((int)((5 * l) + (5 * d))-(d*10));
					// if theres a negative diff, lets reverse it
					if (d < 0){
						d = -d;
					}
					//build up our threshold map
					map[ii] = d > 150;
				}
			}
		}
		previous_frame = data;
		boolean erode = false;
		for (int y = 0, i = 0; y < half_height; y++) {
			for (int x = 0; x < half_width; x++, i++) {
				erode = false;
				if (map[i]) {
					loop through the pixels around it
					for (int yi=-2;yi<=2;yi++){
						for (int xi=-2;xi<=2;xi++){
							int px = (y+yi) * half_width + (x+xi);
							if (px >= 0 && px < map.length) {
								// if a pixel is eroded, carry on
								if (!map[px]) {
									erode = true;
									break;
								}
							}
						}
					}
					// if no pixels around this pixel have been eroded, we know there's probably some motion
					if (!erode) {
						return true;
					}
				}
			}
		}
		return false;
	}
 


I'm getting plenty of frames and I'm eroding noise. I might try to fit my 'normalize' code back in now, too, so I can make sure it works well at night.

 
EDITED: 26 Jun 2012 11:59 by MIKEE