⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 alg.c

📁 video motion detection of linux base
💻 C
📖 第 1 页 / 共 2 页
字号:
				*(yp + i) = blob;				sum++;			}		}		/* Store zeros in the vertical sides. */		*yp = *(yp + width - 1) = 0;		yp += width;	}	return sum;}/* Erodes a 3x3 box */static int erode9(unsigned char *img, int width, int height, void *buffer, unsigned char flag){	int y, i, sum = 0;	char *Row1,*Row2,*Row3;	Row1 = buffer;	Row2 = Row1 + width;	Row3 = Row1 + 2*width;	memset(Row2, flag, width);	memcpy(Row3, img, width);	for (y = 0; y < height; y++) {		memcpy(Row1, Row2, width);		memcpy(Row2, Row3, width);		if (y == height-1)			memset(Row3, flag, width);		else			memcpy(Row3, img+(y+1)*width, width);		for (i = width-2; i >= 1; i--) {			if (Row1[i-1] == 0 ||				Row1[i]   == 0 ||				Row1[i+1] == 0 ||				Row2[i-1] == 0 ||				Row2[i]   == 0 ||				Row2[i+1] == 0 ||				Row3[i-1] == 0 ||				Row3[i]   == 0 ||				Row3[i+1] == 0)				img[y*width+i] = 0;			else				sum++;		}		img[y*width] = img[y*width+width-1] = flag;	}	return sum;}/* Erodes in a + shape */static int erode5(unsigned char *img, int width, int height, void *buffer, unsigned char flag){	int y, i, sum = 0;	char *Row1,*Row2,*Row3;	Row1 = buffer;	Row2 = Row1 + width;	Row3 = Row1 + 2*width;	memset(Row2, flag, width);	memcpy(Row3, img, width);	for (y = 0; y < height; y++) {		memcpy(Row1, Row2, width);		memcpy(Row2, Row3, width);		if (y == height-1)			memset(Row3, flag, width);		else			memcpy(Row3, img+(y+1)*width, width);		for (i = width-2; i >= 1; i--) {			if (Row1[i]   == 0 ||				Row2[i-1] == 0 ||				Row2[i]   == 0 ||				Row2[i+1] == 0 ||				Row3[i]   == 0)				img[y*width+i] = 0;			else				sum++;		}		img[y*width] = img[y*width+width-1] = flag;	}	return sum;}/*  * Despeckling routine to remove noisy detections. */int alg_despeckle(struct context *cnt, int olddiffs){	int diffs = 0;	unsigned char *out = cnt->imgs.out;	int width = cnt->imgs.width;	int height= cnt->imgs.height;	int done = 0, i, len = strlen(cnt->conf.despeckle);	unsigned char *common_buffer = cnt->imgs.common_buffer;	for (i = 0; i < len; i++) {		switch (cnt->conf.despeckle[i]) {		case 'E':			if ((diffs = erode9(out, width, height, common_buffer, 0)) == 0) i=len;			done=1;			break;		case 'e':			if ((diffs = erode5(out, width, height, common_buffer, 0)) == 0) i=len;			done=1;			break;		case 'D':			diffs = dilate9(out, width, height, common_buffer);			done=1;			break;		case 'd':			diffs = dilate5(out, width, height, common_buffer);			done=1;			break;		/* no further despeckle after labeling! */		case 'l':			diffs = alg_labeling(cnt);			i=len;			done=2;			break;		}	}	/* If conf.despeckle contains any valid action EeDdl */	if (done){		if (done != 2) cnt->imgs.labelsize_max = 0; // Disable Labeling		return diffs;	}		else		cnt->imgs.labelsize_max = 0; // Disable Labeling		return olddiffs;}/* Generate actual smartmask. Calculate sensitivity based on motion */void alg_tune_smartmask(struct context *cnt){	int i, diff;		int motionsize = cnt->imgs.motionsize;	unsigned char *smartmask = cnt->imgs.smartmask;	unsigned char *smartmask_final = cnt->imgs.smartmask_final;	int *smartmask_buffer = cnt->imgs.smartmask_buffer;	int sensitivity=cnt->lastrate*(11-cnt->smartmask_speed);	for (i=0; i<motionsize; i++)	{		/* Decrease smart_mask sensitivity every 5*speed seconds only */		if (smartmask[i] > 0)			smartmask[i]--;		/* Increase smart_mask sensitivity based on the buffered values */		diff = smartmask_buffer[i]/sensitivity;		if (diff){			if (smartmask[i] <= diff+80)				smartmask[i]+=diff;			else				smartmask[i]=80;			smartmask_buffer[i]%=sensitivity;		}		/* Transfer raw mask to the final stage when above trigger value */		if (smartmask[i]>20)			smartmask_final[i]=0;		else			smartmask_final[i]=255;	}	/* Further expansion (here:erode due to inverted logic!) of the mask */	diff = erode9(smartmask_final, cnt->imgs.width, cnt->imgs.height, cnt->imgs.common_buffer, 255);	diff = erode5(smartmask_final, cnt->imgs.width, cnt->imgs.height, cnt->imgs.common_buffer, 255);}/* Increment for *smartmask_buffer in alg_diff_standard. */#define SMARTMASK_SENSITIVITY_INCR 5int alg_diff_standard (struct context *cnt, unsigned char *new){	struct images *imgs=&cnt->imgs;	int i, diffs=0;	long int level=0;	int noise=cnt->noise;	int smartmask_speed=cnt->smartmask_speed;	unsigned char *ref=imgs->ref;	unsigned char *out=imgs->out;	unsigned char *mask=imgs->mask;	unsigned char *smartmask_final=imgs->smartmask_final;	int *smartmask_buffer=imgs->smartmask_buffer;#ifdef HAVE_MMX	mmx_t mmtemp; /* used for transferring to/from memory */	int unload;   /* counter for unloading diff counts */#endif	/* If the average level of the picture is to low, compensate by 	 * lowering the noise threshold	 */	if (cnt->conf.nightcomp) {		i=imgs->motionsize;		for (i--; i>=0; i--) {			level+=(unsigned char)new[i];		}		level/=imgs->motionsize;		if (level < noise*2)			noise/=2;	}	i=imgs->motionsize;	memset(out+i, 128, i/2); /* motion pictures are now b/w i.o. green */	/* Keeping this memset in the MMX case when zeroes are necessarily 	 * written anyway seems to be beneficial in terms of speed. Perhaps a	 * cache thing?	 */	memset(out, 0, i);#ifdef HAVE_MMX	/* NOTE: The Pentium has two instruction pipes: U and V. I have grouped MMX	 * instructions in pairs according to how I think they will be scheduled in 	 * the U and V pipes. Due to pairing constraints, the V pipe will sometimes	 * be empty (for example, memory access always goes into the U pipe).	 *	 * The following MMX registers are kept throughout the loop:	 * mm5 - 8 separate diff counters (unloaded periodically)	 * mm6 - mask: 00ff 00ff 00ff 00ff	 * mm7 - noise level as 8 packed bytes	 *	 * -- Per Jonsson	 */	/* To avoid a div, we work with differences multiplied by 255 in the	 * default case and *mask otherwise. Thus, the limit to compare with is	 * 255*(noise+1)-1).	 */	mmtemp.uw[0] = mmtemp.uw[1] = mmtemp.uw[2] = mmtemp.uw[3] =		(unsigned short)(noise * 255 + 254);		/* 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 (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. */				(*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 do nightcompensation or 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;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -