diff -p a/alg.c b/alg.c *** a/alg.c 2007-09-17 19:59:27.000000000 +0200 --- b/alg.c 2007-09-17 19:59:28.000000000 +0200 *************** int alg_switchfilter(struct context *cnt *** 1063,1065 **** --- 1063,1154 ---- } return 0; } + + /** + * alg_update_reference_frame + * + * Called from 'motion_loop' to calculate the reference frame + * Moving objects are excluded from the reference frame for a certain + * amount of time to improve detection. + * + * Parameters: + * + * cnt - current thread's context struct + * action - UPDATE_REF_FRAME or RESET_REF_FRAME + * + */ + #define ACCEPT_STATIC_OBJECT 20 + #define DISCARD_STATIC_OBJECT -120 + #define NOISE_CORRECTION_PERCENT 90 + void alg_update_reference_frame(struct context *cnt, int action) + { + int t_pos[4]; + int i , x, u, v, z, width, height, line, pos, colorflag, threshold_ref; + unsigned char *image_virgin = cnt->imgs.image_virgin; + unsigned char *ref = cnt->imgs.ref; + unsigned char *smartmask = cnt->imgs.smartmask_final; + char *ref_dyn = cnt->imgs.ref_dyn; + unsigned char *ref_y, *ref_u, *ref_v, *virgin_y, *virgin_u, *virgin_v; + + if (action == UPDATE_REF_FRAME) { + u = cnt->imgs.motionsize; + v = u + (u / 4); + width = cnt->imgs.width; + height = cnt->imgs.height; + ref_y = cnt->imgs.ref; + ref_u = ref_y + u; + ref_v = ref_y + v; + virgin_y = cnt->imgs.image_virgin; + virgin_u = virgin_y + u; + virgin_v = virgin_y + v; + /* add some correction to reduce ghost pixels at object borders */ + threshold_ref = cnt->noise * NOISE_CORRECTION_PERCENT / 100; + for (i = 0; i < height; i += 2) { + line = i * width; + for (x = 0; x < width; x += 2) { + colorflag = 0; + /* handle quadpixels separately in order to treat color info right. */ + /* Colors may be important for future use (e.g. shadow detection). */ + t_pos[0] = line + x; + t_pos[1] = line + x + 1; + t_pos[2] = line + width + x; + t_pos[3] = line + width + x + 1; + for (z = 3; z >= 0; z--) { + pos = t_pos[z]; + if (((int)(abs(ref[pos] - image_virgin[pos])) > threshold_ref) && (smartmask[pos])) { + if (ref_dyn[pos] < 0) { /* Static Object moves again? */ + ref_dyn[pos] = 0; + ref[pos] = image_virgin[pos]; + } + else if (ref_dyn[pos] > ACCEPT_STATIC_OBJECT) { /* Include static Object after some time */ + ref_dyn[pos] = -1; + ref[pos] = image_virgin[pos]; + } else { + ref_dyn[pos]++; /* Motionpixel? Exclude from ref frame */ + colorflag++; + } + } + else { + // ref[pos] = image_virgin[pos]; /* No motion: copy to ref frame */ + ref[pos] = ((ref[pos] + image_virgin[pos]) / 2); /* No motion: copy to ref frame */ + if ((ref_dyn[pos] >= 0) || (ref_dyn[pos] == DISCARD_STATIC_OBJECT)) /* Discard static object again after a while */ + ref_dyn[pos] = 0; + else + ref_dyn[pos]--; /* Still keep static object in mind */ + } + } /* end for z */ + if (colorflag == 0) { /* copy U and V only when none of the 4 pixels had motion */ + *ref_u = *virgin_u; + *ref_v = *virgin_v; + } + ref_u++; + ref_v++; + virgin_u++; + virgin_v++; + } /* end for x */ + } /* end for i */ + } else { /* action == RESET_REF_FRAME - also used to initialize the frame at startup */ + memcpy(cnt->imgs.ref, cnt->imgs.image_virgin, cnt->imgs.size); /* copy fresh image */ + memset(ref_dyn, 0, cnt->imgs.motionsize); /* reset static objects */ + } + } diff -p a/alg.h b/alg.h *** a/alg.h 2007-09-17 19:59:28.000000000 +0200 --- b/alg.h 2007-09-17 19:59:28.000000000 +0200 *************** void alg_noise_tune(struct context *, un *** 41,45 **** --- 41,46 ---- void alg_threshold_tune(struct context *, int, int); int alg_despeckle(struct context *, int); void alg_tune_smartmask(struct context *); + void alg_update_reference_frame(struct context *, int); #endif /* _INCLUDE_ALG_H */ diff -p a/motion.c b/motion.c *** a/motion.c 2007-09-17 19:59:28.000000000 +0200 --- b/motion.c 2007-09-17 19:59:28.000000000 +0200 *************** static void context_destroy(struct conte *** 239,244 **** --- 239,246 ---- free(cnt->imgs.out); if (cnt->imgs.ref) free(cnt->imgs.ref); + if (cnt->imgs.ref_dyn) + free(cnt->imgs.ref_dyn); if (cnt->imgs.image_virgin) free(cnt->imgs.image_virgin); if (cnt->imgs.labels) *************** static void motion_init(struct context * *** 629,634 **** --- 631,637 ---- cnt->imgs.ref = mymalloc(cnt->imgs.size); cnt->imgs.out = mymalloc(cnt->imgs.size); + cnt->imgs.ref_dyn = mymalloc(cnt->imgs.motionsize); /* contains the moving objects of ref. frame */ cnt->imgs.image_virgin = mymalloc(cnt->imgs.size); memset(cnt->imgs.image_virgin, 0x80, cnt->imgs.size); /* initialize to grey */ cnt->imgs.smartmask = mymalloc(cnt->imgs.motionsize); *************** static void motion_init(struct context * *** 675,681 **** } /* create a reference frame */ ! memcpy(cnt->imgs.ref, cnt->imgs.image_virgin, cnt->imgs.size); #ifndef WITHOUT_V4L #if (!defined(BSD)) --- 678,684 ---- } /* create a reference frame */ ! alg_update_reference_frame(cnt, RESET_REF_FRAME); #ifndef WITHOUT_V4L #if (!defined(BSD)) *************** static void *motion_loop(void *arg) *** 965,974 **** /* Set flags to 0 */ cnt->current_image->flags = 0; cnt->current_image->cent_dist = 0; ! ! /* Clear location data */ memset(&cnt->current_image->location, 0, sizeof(cnt->current_image->location)); ! cnt->current_image->total_labels = 0; } /***** MOTION LOOP - RETRY INITIALIZING NETCAM SECTION *****/ --- 968,977 ---- /* Set flags to 0 */ cnt->current_image->flags = 0; cnt->current_image->cent_dist = 0; ! ! /* Clear location data */ memset(&cnt->current_image->location, 0, sizeof(cnt->current_image->location)); ! cnt->current_image->total_labels = 0; } /***** MOTION LOOP - RETRY INITIALIZING NETCAM SECTION *****/ *************** static void *motion_loop(void *arg) *** 1137,1142 **** --- 1140,1146 ---- if (cnt->moved < 5) cnt->moved = 5; cnt->current_image->diffs = 0; + alg_update_reference_frame(cnt, RESET_REF_FRAME); } } *************** static void *motion_loop(void *arg) *** 1175,1180 **** --- 1179,1188 ---- } else if (!cnt->conf.setup_mode) cnt->current_image->diffs = 0; + /* Update reference frame once per second */ + if (cnt->shots == 0) + alg_update_reference_frame(cnt, UPDATE_REF_FRAME); + /* Manipulate smart_mask sensitivity (only every smartmask_ratio seconds) */ if (cnt->smartmask_speed) { if (!--smartmask_count){ *************** static void *motion_loop(void *arg) *** 1404,1434 **** /* Save/send to movie some images */ process_image_ring(cnt, 2); - /***** MOTION LOOP - REFERENCE FRAME SECTION *****/ - - /* Update reference frame */ - if ((cnt->current_image->diffs > cnt->threshold * 2) || - (cnt->moved && (cnt->track.type || cnt->conf.lightswitch))) { - /* Prevent the motion created by moving camera or sudden light intensity - * being detected by creating a fresh reference frame. Decaying is also - * disabled when motion is above a certain threshold to make tracking - * more accurate. - */ - memcpy(cnt->imgs.ref, cnt->imgs.image_virgin, cnt->imgs.size); - } else if (cnt->threshold) { - /* Old image slowly decays, this will make it even harder on - * a slow moving object to stay undetected - */ - unsigned char *imgs_ref_ptr = cnt->imgs.ref; - unsigned char *newimg_ptr = cnt->imgs.image_virgin; - for (i=cnt->imgs.size-1; i>=0; i--) { - *imgs_ref_ptr = (*imgs_ref_ptr + *newimg_ptr)/2; - imgs_ref_ptr++; - newimg_ptr++; - } - } - - /***** MOTION LOOP - SETUP MODE CONSOLE OUTPUT SECTION *****/ /* If setup_mode enabled output some numbers to console */ --- 1412,1417 ---- *************** static void *motion_loop(void *arg) *** 1545,1551 **** */ if (cnt->shots == 0 && time_current_frame % cnt->conf.timelapse <= time_last_frame % cnt->conf.timelapse) ! event(cnt, EVENT_TIMELAPSE, cnt->current_image->image, NULL, NULL, &cnt->current_image->timestamp_tm); } /* if timelapse mpeg is in progress but conf.timelapse is zero then close timelapse file --- 1528,1535 ---- */ if (cnt->shots == 0 && time_current_frame % cnt->conf.timelapse <= time_last_frame % cnt->conf.timelapse) ! //jw event(cnt, EVENT_TIMELAPSE, cnt->current_image->image, NULL, NULL, &cnt->current_image->timestamp_tm); ! event(cnt, EVENT_TIMELAPSE, cnt->imgs.ref, NULL, NULL, &cnt->current_image->timestamp_tm); } /* if timelapse mpeg is in progress but conf.timelapse is zero then close timelapse file *************** static void *motion_loop(void *arg) *** 1578,1584 **** } else { event(cnt, EVENT_IMAGE, cnt->current_image->image, NULL, &cnt->pipe, &cnt->current_image->timestamp_tm); if (!cnt->conf.webcam_motion || cnt->shots == 1) ! event(cnt, EVENT_WEBCAM, cnt->current_image->image, NULL, NULL, &cnt->current_image->timestamp_tm); } event(cnt, EVENT_IMAGEM, cnt->imgs.out, NULL, &cnt->mpipe, cnt->currenttime_tm); --- 1562,1569 ---- } else { event(cnt, EVENT_IMAGE, cnt->current_image->image, NULL, &cnt->pipe, &cnt->current_image->timestamp_tm); if (!cnt->conf.webcam_motion || cnt->shots == 1) ! //jw event(cnt, EVENT_WEBCAM, cnt->current_image->image, NULL, NULL, &cnt->current_image->timestamp_tm); ! event(cnt, EVENT_WEBCAM, cnt->imgs.ref, NULL, NULL, &cnt->current_image->timestamp_tm); } event(cnt, EVENT_IMAGEM, cnt->imgs.out, NULL, &cnt->mpipe, cnt->currenttime_tm); diff -p a/motion.h b/motion.h *** a/motion.h 2007-09-17 19:59:28.000000000 +0200 --- b/motion.h 2007-09-17 19:59:28.000000000 +0200 *************** *** 172,177 **** --- 172,180 ---- #define LOCATE_NORMAL 0 #define LOCATE_BOTH 1 + #define UPDATE_REF_FRAME 1 + #define RESET_REF_FRAME 2 + /* Forward declaration, used in track.h */ struct images; *************** struct images { *** 247,252 **** --- 250,256 ---- unsigned char *ref; /* The reference frame */ unsigned char *out; /* Picture buffer for motion images */ + char *ref_dyn; /* Dynamic objects to be excluded from reference frame */ unsigned char *image_virgin; /* Last picture frame with no text or locate overlay */ struct image_data preview_image; /* Picture buffer for best image when enables */ unsigned char *mask; /* Buffer for the mask file */