📄 alg.c
字号:
/* Reset mm5 to zero, set the mm6 mask, and store the multiplied noise * level as four words in mm7. */ movq_m2r(mmtemp, mm7); /* U */ pcmpeqb_r2r(mm6, mm6); /* V */ pxor_r2r(mm5, mm5); /* U */ psrlw_i2r(8, mm6); /* V */ /* We must unload mm5 every 255th round, because the diffs accumulate * in each packed byte, which can hold at most 255 diffs before it * gets saturated. */ unload=255; for (; i>7; i-=8) { /* Calculate abs(*ref-*new) for 8 pixels in parallel. */ movq_m2r(*ref, mm0); /* U: mm0 = r7 r6 r5 r4 r3 r2 r1 r0 */ pxor_r2r(mm4, mm4); /* V: mm4 = 0 */ movq_m2r(*new, mm1); /* U: mm1 = n7 n6 n5 n4 n3 n2 n1 n0 */ movq_r2r(mm0, mm2); /* V: mm2 = r7 r6 r5 r4 r3 r2 r1 r0 */ /* These subtractions are saturated, i.e. won't go below 0. */ psubusb_r2r(mm1, mm0); /* U: mm0 = (r7-n7) ... (r0-n0) */ psubusb_r2r(mm2, mm1); /* V: mm1 = (n7-r7) ... (n0-r0) */ /* Each byte dX in mm0 is abs(nX-rX). */ por_r2r(mm1, mm0); /* U: mm0 = d7 d6 d5 d4 d3 d2 d1 d0 */ /* Expand the absolute differences to words in mm0 and mm1. */ movq_r2r(mm0, mm1); /* U: mm1 = d7 d6 d5 d4 d3 d2 d1 d0 */ punpcklbw_r2r(mm4, mm0); /* V: mm0 = d3 d2 d1 d0 */ punpckhbw_r2r(mm4, mm1); /* U: mm1 = d7 d6 d5 d4 */ if (mask) { /* Load and expand 8 mask bytes to words in mm2 and mm3. Then * multiply by mm0 and mm1, respectively. */ movq_m2r(*mask, mm2); /* U: mm2 = m7 m6 m5 m4 m3 m2 m1 m0 */ movq_r2r(mm2, mm3); /* U: mm3 = m7 m6 m5 m4 m3 m2 m1 m0 */ punpcklbw_r2r(mm4, mm2); /* v: mm2 = m3 m2 m1 m0 */ punpckhbw_r2r(mm4, mm3); /* U: mm3 = m7 m6 m5 m4 */ pmullw_r2r(mm2, mm0); /* V: mm0 = (d3*m3) ... (d0*m0) */ pmullw_r2r(mm3, mm1); /* U: mm1 = (d7*m7) ... (d4*m4) */ mask+=8; } else { /* Not using mask - multiply the absolute differences by 255. We * do this by left-shifting 8 places and then subtracting dX. */ movq_r2r(mm0, mm2); /* U: mm2 = d3 d2 d1 d0 */ psllw_i2r(8, mm0); /* V: mm2 = (256*d3) ... (256*d0) */ movq_r2r(mm1, mm3); /* U: mm3 = d7 d6 d5 d4 */ psllw_i2r(8, mm1); /* V: mm3 = (256*d7) ... (256*d4) */ psubusw_r2r(mm2, mm0); /* U */ psubusw_r2r(mm3, mm1); /* V */ } /* Next, compare the multiplied absolute differences with the multiplied * noise level (repeated as 4 words in mm7), resulting in a "motion flag" * for each pixel. * * Since pcmpgtw performs signed comparisons, we have to subtract noise, * test for equality to 0 and then invert the result. * * Note that it is safe to generate the "motion flags" before the * smartmask code, as all that can happen is that individual flags get * reset to 0 because of the smartmask. */ psubusw_r2r(mm7, mm0); /* U: subtract by (multiplied) noise */ psubusw_r2r(mm7, mm1); /* V */ pcmpeqw_r2r(mm4, mm0); /* U: test for equality with 0 */ pcmpeqw_r2r(mm4, mm1); /* V */ pand_r2r(mm6, mm0); /* U: convert 0xffff -> 0x00ff */ pand_r2r(mm6, mm1); /* V */ pxor_r2r(mm6, mm0); /* U: invert the result */ pxor_r2r(mm6, mm1); /* V */ /* Each fX is the "motion flag" = 0 for no motion, 0xff for motion. */ packuswb_r2r(mm1, mm0); /* U: mm0 = f7 f6 f5 f4 f3 f2 f1 f0 */ if (smartmask_speed) { /* Apply the smartmask. Basically, if *smartmask_final is 0, the * corresponding "motion flag" in mm0 will be reset. */ movq_m2r(*smartmask_final, mm3); /* U: mm3 = s7 s6 s5 s4 s3 s2 s1 s0 */ /* ...but move the "motion flags" to memory before, in order to * increment *smartmask_buffer properly below. */ movq_r2m(mm0, mmtemp); /* U */ pcmpeqb_r2r(mm4, mm3); /* V: mm3 = 0xff where sX==0 */ /* ANDN negates the target before anding. */ pandn_r2r(mm0, mm3); /* U: mm3 = 0xff where dX>noise && sX>0 */ movq_r2r(mm3, mm0); /* U */ /* Add to *smartmask_buffer. This is probably the fastest way to do it. */ if (cnt->event_nr != cnt->prev_event) { if (mmtemp.ub[0]) smartmask_buffer[0]+=SMARTMASK_SENSITIVITY_INCR; if (mmtemp.ub[1]) smartmask_buffer[1]+=SMARTMASK_SENSITIVITY_INCR; if (mmtemp.ub[2]) smartmask_buffer[2]+=SMARTMASK_SENSITIVITY_INCR; if (mmtemp.ub[3]) smartmask_buffer[3]+=SMARTMASK_SENSITIVITY_INCR; if (mmtemp.ub[4]) smartmask_buffer[4]+=SMARTMASK_SENSITIVITY_INCR; if (mmtemp.ub[5]) smartmask_buffer[5]+=SMARTMASK_SENSITIVITY_INCR; if (mmtemp.ub[6]) smartmask_buffer[6]+=SMARTMASK_SENSITIVITY_INCR; if (mmtemp.ub[7]) smartmask_buffer[7]+=SMARTMASK_SENSITIVITY_INCR; } smartmask_buffer+=8; smartmask_final+=8; } movq_m2r(*new, mm2); /* U: mm1 = n7 n6 n5 n4 n3 n2 n1 n0 */ /* Cancel out pixels in *new according to the "motion flags" in mm0. * Each NX is either 0 or nX as from *new. */ pand_r2r(mm0, mm2); /* U: mm1 = N7 N6 N5 N4 N3 N2 N1 N0 */ psubb_r2r(mm0, mm4); /* V: mm4 = 0x01 where dX>noise */ /* mm5 holds 8 separate counts - each one is increased according to * the contents of mm4 (where each byte is either 0x00 or 0x01). */ movq_r2m(mm2, *out); /* U: this will stall */ paddusb_r2r(mm4, mm5); /* V: add counts to mm5 */ /* Every 255th turn, we need to unload mm5 into the diffs variable, * because otherwise the packed bytes will get saturated. */ if (--unload==0) { /* Unload mm5 to memory and reset it. */ movq_r2m(mm5, mmtemp); /* U */ pxor_r2r(mm5, mm5); /* V: mm5 = 0 */ diffs += mmtemp.ub[0] + mmtemp.ub[1] + mmtemp.ub[2] + mmtemp.ub[3] + mmtemp.ub[4] + mmtemp.ub[5] + mmtemp.ub[6] + mmtemp.ub[7]; unload=255; } out+=8; ref+=8; new+=8; } /* Check if there are diffs left in mm5 that need to be copied to the * diffs variable. */ if (unload<255) { movq_r2m(mm5, mmtemp); diffs += mmtemp.ub[0] + mmtemp.ub[1] + mmtemp.ub[2] + mmtemp.ub[3] + mmtemp.ub[4] + mmtemp.ub[5] + mmtemp.ub[6] + mmtemp.ub[7]; } emms();#endif /* Note that the non-MMX code is present even if the MMX code is present. * This is necessary if the resolution is not a multiple of 8, in which * case the non-MMX code needs to take care of the remaining pixels. */ for (; i>0; i--) { register unsigned char curdiff=(int)(abs(*ref - *new)); /* using a temp variable is 12% faster */ /* apply fixed mask */ if (mask) curdiff=((int)(curdiff * *mask++)/255); if (smartmask_speed) { if (curdiff > noise) { /* increase smart_mask sensitivity every frame when motion is detected. (with speed=5, mask is increased by 1 every second. To be able to increase by 5 every second (with speed=10) we add 5 here. NOT related to the 5 at ratio- calculation. */ if (cnt->event_nr != cnt->prev_event) (*smartmask_buffer) += SMARTMASK_SENSITIVITY_INCR; /* apply smart_mask */ if (!*smartmask_final) curdiff=0; } smartmask_final++; smartmask_buffer++; } /* Pixel still in motion after all the masks? */ if (curdiff > noise) { *out=*new; diffs++; } out++; ref++; new++; } return diffs;}/* Very fast diff function, does not apply mask overlaying.*/static char alg_diff_fast(struct context *cnt, int max_n_changes, unsigned char *new){ struct images *imgs=&cnt->imgs; int i, diffs=0, step=imgs->motionsize/10000; int noise=cnt->noise; unsigned char *ref=imgs->ref; if (!step%2) step++; /* we're checking only 1 of several pixels */ max_n_changes /= step; i=imgs->motionsize; for (; i>0; i-=step) { register unsigned char curdiff=(int)(abs((char)(*ref-*new))); /* using a temp variable is 12% faster */ if (curdiff > noise) { diffs++; if (diffs > max_n_changes) return 1; } ref+=step; new+=step; } return 0;}/* alg_diff uses diff_fast to quickly decide if there is anything worth * sending to diff_standard.*/int alg_diff(struct context *cnt, unsigned char *new){ int diffs=0; if (alg_diff_fast(cnt, cnt->conf.max_changes/2, new)) diffs=alg_diff_standard(cnt, new); return diffs;}/* Detect a sudden massive change in the picture. It is assumed to be the light being switched on or a camera displacement. In any way the user doesn't think it is worth capturing. */int alg_lightswitch(struct context *cnt, int diffs){ struct images *imgs=&cnt->imgs; if (cnt->conf.lightswitch < 0) cnt->conf.lightswitch = 0; if (cnt->conf.lightswitch > 100) cnt->conf.lightswitch = 100; /* is lightswitch percent of the image changed? */ if (diffs > (imgs->motionsize * cnt->conf.lightswitch / 100)) return 1; return 0;}int alg_switchfilter(struct context *cnt, int diffs, unsigned char *newimg){ int linediff = diffs / cnt->imgs.height; unsigned char *out = cnt->imgs.out; int y, x, line; int lines=0, vertlines=0; for (y=0; y < cnt->imgs.height; y++) { line=0; for (x=0; x < cnt->imgs.width; x++) { if (*(out++)) { line++; } } if (line > cnt->imgs.width/18) { vertlines++; } if (line > linediff*2) { lines++; } } if (vertlines > cnt->imgs.height/10 && lines < vertlines/3 && (vertlines > cnt->imgs.height/4 || lines - vertlines > lines/2)) { if (cnt->conf.text_changes) { char tmp[80]; sprintf(tmp, "%d %d", lines, vertlines); draw_text(newimg, cnt->imgs.width-10, 20, cnt->imgs.width, tmp, cnt->conf.text_double); } return diffs; } 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 * *//* Seconds */#define ACCEPT_STATIC_OBJECT_TIME 10#define EXCLUDE_LEVEL_PERCENT 20void alg_update_reference_frame(struct context *cnt, int action) { int accept_timer = cnt->lastrate * ACCEPT_STATIC_OBJECT_TIME; int i, threshold_ref; int *ref_dyn = cnt->imgs.ref_dyn; unsigned char *image_virgin = cnt->imgs.image_virgin; unsigned char *ref = cnt->imgs.ref; unsigned char *smartmask = cnt->imgs.smartmask_final; unsigned char *out = cnt->imgs.out; if (cnt->lastrate > 5) /* match rate limit */ accept_timer /= (cnt->lastrate / 3); if (action == UPDATE_REF_FRAME) { /* black&white only for better performance */ threshold_ref = cnt->noise * EXCLUDE_LEVEL_PERCENT / 100; for (i = cnt->imgs.motionsize; i > 0; i--) { /* exclude pixels from ref frame well below noise level */ if (((int)(abs(*ref - *image_virgin)) > threshold_ref) && (*smartmask)) { if (*ref_dyn == 0) { /* Always give new pixels a chance */ *ref_dyn = 1; } else if (*ref_dyn > accept_timer) { /* Include static Object after some time */ *ref_dyn = 0; *ref = *image_virgin; } else if (*out) (*ref_dyn)++; /* Motionpixel? Keep excluding from ref frame */ else { *ref_dyn = 0; /* Nothing special - release pixel */ *ref = (*ref + *image_virgin) / 2; } } else { /* No motion: copy to ref frame */ *ref_dyn = 0; /* reset pixel */ *ref = *image_virgin; } ref++; image_virgin++; smartmask++; ref_dyn++; out++; } /* 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(cnt->imgs.ref_dyn, 0, cnt->imgs.motionsize * sizeof(cnt->imgs.ref_dyn)); /* reset static objects */ }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -