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

📄 callbacks.c

📁 基于V4L开发的一个运动监测的程序
💻 C
📖 第 1 页 / 共 3 页
字号:
		for ( ; p1 < &ds1_buf[0]+sizeof(ds1_buf);p1++,p0++ )
		{
			*p1 = *p0 + correction;
			// fix up overflows
			if ( *p1 < *p0 ) *p1 = 255;
		}
	}
	else if(avg_ds_intensity == avg_ref_intensity)
	{
		// make exact copy
//		g_print("no image correction required\n");		
		memcpy(p1,p0,sizeof(ds1_buf));
	}
	
	else if(avg_ds_intensity > avg_ref_intensity)
	{
		correction = avg_ds_intensity - avg_ref_intensity;
//		g_print("making image darker by %d\n",correction);
		// make ds1 image darker to match ref image
		for (; p1 < &ds1_buf[0]+sizeof(ds1_buf); p1++,p0++ )
		{
			*p1 = *p0 - correction;
			// fix up underflows
			if ( *p1 > *p0 ) *p1 = 0;
		}
	
	}
	
	// for debug, its nice to know the avg intensity of the corrected buffer
	// it should be close to the ref buffer unless clipping occured due to
	// saturation at 0 or 255 limits
	for ( p1 = &ds1_buf[0]; p1 < &ds1_buf[0]+sizeof(ds1_buf); p1++ )
	{
		avg += *p1;
	}
	avg /= sizeof(ds1_buf);
	avg_ds1_intensity = avg;

}


//=====================================================================
// This procedure adds some of the new image in with lots of the old 
// image. This gives us a long time constant average reference picture.
// This allows the system to adapt to new items in the image over time
// but still alarm again if they move in the picture. Also, changing
// lighting conditions are less of a problem.
//=====================================================================
void update_reference_image(void)
{
  	GtkWidget *wid;
	gint x,y;
	guchar *pdest;
	guchar *psrc;
	float old;
	unsigned int avg = 0;
	guchar *p1;
	static int first = 1;
	
	if ( first == 1 )
	{
		// on first pass, the first picture becomes the reference picture
		memcpy(ref_buf,ds_buf,sizeof(ref_buf));
		first = 0;
	}
	else
	{		
		// now update reference buffer by using some of old image and some of new
		psrc  = &ds_buf[0];
		pdest = &ref_buf[0];	
		old = 1.0 - ref_update_fraction;
		for (y=0; y<240; y++)
		{
			for (x=0; x<320; x++)
			{
				// give the fpu something to do...
				*pdest++ = old * *pdest + ref_update_fraction * *psrc++ + 0.5;	// red
				*pdest++ = old * *pdest + ref_update_fraction * *psrc++ + 0.5;	// green
				*pdest++ = old * *pdest + ref_update_fraction * *psrc++ + 0.5;	// blue
			}
		}
	}

	// compute new avg intensity for the reference buffer
	for ( p1 = &ref_buf[0]; p1 < &ref_buf[0]+sizeof(ref_buf); p1++ )
	{
		avg += *p1;
	}
	avg /= sizeof(ref_buf);
//	g_print(_("reference image avg intensity = %u\n"),avg);
	avg_ref_intensity = (guchar)avg;
	
	// let the widget know that it needs to be updated
	wid = GTK_WIDGET(lookup_widget(window1,"drawingarea2"));
	gtk_widget_queue_draw(wid);
		
}
//=====================================================================
// call with a number 0..100 for graph update
//=====================================================================
void update_history_graph(int percent, int alarm_level)
{
  	GtkWidget *wid;
	static int first = 1;
	int		y;
	guchar *ptr;
	static int call_cnt = 0;	// used for threshold line on graph
	
	call_cnt++;
	
	// if first time through, clear graph to black
	if (first)
	{
		memset(&grf_buf[0],0,sizeof(grf_buf));
		first = 0;
	}
	
  	for (y=0; y<50; y++)
  	{
	  	// move each row of pixels over in memory (scroll left)
	  	memmove( grf_buf+y*320*3,grf_buf+y*320*3+3,319*3); 

	  	// init last column to black
	  	ptr = grf_buf + y*320*3 + 319*3;
	  	*ptr++ = 0;  	  //red
	  	*ptr++ = 0;  	  //grn
	  	*ptr++ = 0;  	  //blu

  	}
	
	// turn on 1 pixel in last column
	// limit range so pixel always gets displayed 0...99
	if (percent < 0)
		percent = 0;
	if (percent > 99)
		percent = 99;

	// invert graph so that 0 is at bottom, scale range to fit 50 pixel image
	ptr = grf_buf + ((99-percent)/2)*320*3 + 319*3;
	while ( ptr < grf_buf + sizeof(grf_buf))
	{
		if ( percent > alarm_level )
		{		
			*ptr = 255;
			*(ptr+1) = 32;
			*(ptr+2) = 32;
		}
		else
		{
			*ptr = 32;
			*(ptr+1) = 255;
			*(ptr+2) = 32;
		}
		ptr += 320 * 3;	// bump down 1 line
	}		

	// time to put a reference dot on the plot showing alarm threshold
	if ( call_cnt %4 == 0)
	{
		if ( alarm_level < 0)
			alarm_level = 0;
		if (alarm_level > 99)
			alarm_level = 99;
		ptr = grf_buf + ((99-alarm_level)/2)*320*3 + 319*3;
		*ptr++ = 32;
		*ptr++ = 255;
		*ptr = 255;
	}

	// let the widget know that it needs to be updated
	wid = GTK_WIDGET(lookup_widget(window1,"drawingarea4"));
	gtk_widget_queue_draw(wid);
}


//=====================================================================
// routine to subtract downsized image from the reference image
// this will give us an image with only the changes showing
// its not quite a simple subtraction, we look at each color and
// look for color changes as well. Significantly changed pixels are
// set to bright white. Result is a b/w image with additional
// blob filtering to look for areas of change (marked as red pixels).
// Each blob is a pixel surrounded by 8 neighbors
//=====================================================================
float do_motion_analysis(void)
{
  	GtkWidget *wid;
	gint x,y;
	guchar *pdest;
	guchar *psrc;
	guchar *pref;
	guchar red;
	guchar green;
	guchar blue;
	guchar cresult;
	float  fresult = 0.0f;
	int		pixcnt;
	guchar threshold;
	int    blob_cnt;
	int i;	
    time_t      t;
    struct tm  *tm;
    char        line[128];
	static	int image_cnt = 0;		// used to force saves on periodic basis
	guint context;
	char sbuf[256];
	static int first = 1;
    char *cp;
    gchar **toks;
    gchar *new_cmd;
        
    	
	// on the first pass, we dont have a ref image stored yet so
	// we cannot do a difference that is meaningful.
	if ( first == 1 )
	{
		first = 0;
		return 0.0;
	}
	
	alarm_zone.x1 = 640;			// init bounding box of alarm blobs
	alarm_zone.x2 = -1;
	alarm_zone.y1 = 480;
	alarm_zone.y2 = -1;

//	g_print(_("new image is %s, %u %u %u\n"),
//			( avg_ds_intensity <= avg_ref_intensity ) ? _("darker or ==") : _("lighter"),
//			avg_ds_intensity, avg_ds1_intensity, avg_ref_intensity);	
	pref  = &ref_buf[0];		
	psrc  = &ds1_buf[0];	// intensity corrected buffer
	pdest = &res_buf[0];
	
	for (y=0; y<240; y++)
	{
		for (x=0; x<320; x++)
		{
		
			// give the cpu something to do...
			// compute rms diff between all pixels
			// detection of color or intensity changes detected
			red = (*pref > *psrc) ? *pref- *psrc : *psrc- *pref;	// red
			pref++; psrc++;
			green = (*pref > *psrc) ? *pref- *psrc : *psrc- *pref;;	// green
			pref++; psrc++;
			blue  = (*pref > *psrc) ? *pref- *psrc : *psrc- *pref;;	// blue
			pref++; psrc++;
			cresult = sqrt((red*red + green*green + blue*blue)/3);
			*pdest++ = cresult;		// make b/w image
			*pdest++ = cresult;
			*pdest++ = cresult;
			fresult += (float)cresult;
		}
	}
	// calculate normalized difference over picture
	fresult = fresult/(float)(320*240);
	
	// detect and mark pixels that are significantly different
	threshold = (guchar)sig_pix_threshold;
	pixcnt = 0;
	psrc  = &res_buf[0];
	while ( psrc < res_buf+sizeof(res_buf))
	{
		if ( *psrc > threshold )
		{
			pixcnt++;
			*psrc = 255;		// alarm active areas in white
			*(psrc+1) = 255;
			*(psrc+2) = 255;
		}
			
		psrc += 3;			// only need to look at reds of each pixel
							// because g and b are set to the same thing			
	}
	
	// to eliminate small changes (wind blown objects) from causing so much
	// havoc, we will try to eliminate false alarms by scanning for blobs	
	// A blob is a 3x3 pixel area, all must be 'hot' (white)
	blob_cnt = 0;
	psrc  = res_buf + 320 * 3;
	while ( psrc < (res_buf+sizeof(res_buf)-320*3))
	{
		for (i=0;i<1;i++)
		{
			if (*psrc < 255) break;			// central pixel must be lite
			if (*(psrc-320*3) < 255) break;	// pixel above must be lite
			if (*(psrc+320*3) < 255) break;	// pixel below must be lite
			if (*(psrc-3) < 255) break;		// pixel to left must be lite
			if (*(psrc+3) < 255) break;		// pixel to right must be light
			if (*(psrc-320*3+3) < 255) break;		// pixel to  NE must be light			
			if (*(psrc-320*3-3) < 255) break;		// pixel to  NW must be light						
			if (*(psrc+320*3+3) < 255) break;		// pixel to  SE must be light						
			if (*(psrc+320*3-3) < 255) break;		// pixel to  SW must be light						
			// mark blob as blob on screen
			*(psrc+2) = 0;	// shut off blue
			*(psrc+1) = 0;  // shut off green
			blob_cnt++;
			x = ((psrc - res_buf) % (320 * 3))/3;
			y = (psrc - res_buf) / (320 * 3);
			if ( x < alarm_zone.x1 )		// set first occurance location
				alarm_zone.x1 = x;
			if ( alarm_zone.x2 < x )		// keep highest occurance
				alarm_zone.x2 = x;			
			if ( y < alarm_zone.y1 )		// set first occurance location
				alarm_zone.y1 = y;
			if ( alarm_zone.y2 < y )		// keep highest occurance
				alarm_zone.y2 = y;			
		}
		psrc += 3;
	}

	// update status bar with some of our calcs
	wid = lookup_widget(window1,"statusbar1");
	context = gtk_statusbar_get_context_id(GTK_STATUSBAR(wid),"do_motion_analysis()");
	sprintf(sbuf,_("Image%d : alarmpix = %u   alarm pixels = %d, alarm blobs = %d rmsdiff=%.1f"),
    	    image_cnt,alarm_pix,pixcnt,blob_cnt, fresult);
	gtk_statusbar_pop(GTK_STATUSBAR(wid),context);
	gtk_statusbar_push(GTK_STATUSBAR(wid),context,sbuf);
	
	// let the widget know that it needs to be updated
	wid = GTK_WIDGET(lookup_widget(window1,"drawingarea3"));
	gtk_widget_queue_draw(wid);

	// label main view with time/date location stamp (display and filesave)
	if (blob_cnt*graph_scale > alarm_threshold)
	{
		alarm_pix++;
        if ( show_target_box )
		    mark_alarm_zone(&alarm_zone);			// box in alarm window
		add_rgb_text(rgb_buf,640,480, 1);		// red text lable on pix
		if (beep_on_alarm)						// wakeup the operator
			gdk_beep();
	}
	else
		add_rgb_text(rgb_buf,640,480, 0);		// white text label on pix	
		
	
	image_cnt++;	// save image on motion or every xxx pictures

	if (( blob_cnt*graph_scale > alarm_threshold ) || 
		((image_cnt % periodic_save_interval) == 0))
	{
    	time(&t);
    	tm = localtime(&t);
    	strftime(line,sizeof(line)-1,"GSPY%H%M%S.jpg",tm);	
		put_image_jpeg(line, rgb_buf, 640, 480, 80);
	}
    
    // on each alarm, execute a user command
    if (( blob_cnt*graph_scale > alarm_threshold ) &&
        ( strlen(alarm_command) > 1 ) )
    {
        if ((cp = strstr(alarm_command,"%f%")) == NULL)
            // no filename substitution required in user provided string
            system(alarm_command);
        else
        {
            // user put filename(s) in command line using %f%, then we need
            // to insert the current filename into the user command string

            toks = g_strsplit(alarm_command,"%f%",0);
            new_cmd = g_strjoinv(full_name,toks);
            system(new_cmd);
            free(new_cmd);
            g_strfreev(toks);
            

        }
    }    
	update_history_graph(blob_cnt*graph_scale,alarm_threshold);	

	return fresult;
}
//=====================================================================
//=====================================================================
gboolean on_drawingarea1_expose_event  (GtkWidget       *widget,
                                        GdkEventExpose  *event,
                                        gpointer         user_data)
{
	gdk_draw_rgb_image(widget->window,widget->style->fg_gc[GTK_STATE_NORMAL],
	           0,0,640,480,GDK_RGB_DITHER_NORMAL,rgb_buf,3*640); 
 	return FALSE;
}

//=====================================================================
//=====================================================================
gboolean on_drawingarea2_expose_event  (GtkWidget       *widget,
                                        GdkEventExpose  *event,
                                        gpointer         user_data)

⌨️ 快捷键说明

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