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

📄 callbacks.c

📁 基于V4L开发的一个运动监测的程序
💻 C
📖 第 1 页 / 共 3 页
字号:
// callbacks.c
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <gnome.h>

#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
 
#include "callbacks.h"
#include "interface.h"
#include "support.h"
#include "fileio.h"
#include <dirent.h>
#include "v4lif.h"
#include <math.h>
#include <string.h>
#include <time.h>
#include "ccvt.h" 

static guchar rgb_buf[3*640*480];	// main 640x480 live display image buffer
static guchar ds_buf[3*320*240];	// temp for downsized live image
static guchar ds1_buf[3*320*240];	// temp for downsized live image corrected for avg intensity
static guchar ref_buf[3*320*240];	// temp for reference picture buffer (time averaged)
static guchar res_buf[3*320*240];	// temp for motion analysis picture buffer (graphical results)
static guchar grf_buf[3*320*50];	// strip chart graph buffer 
struct video_picture v_pict;		// used to store prefered webcam palette

// the following is declared in main()... needed for lookup_widget() calls
extern GtkWidget *window1;

// the following is declared in fileio.c
extern char full_name[];        // a hack!. full path/filename of last written picture

// for setup items
GtkWidget *propertybox1;

gchar image_directory[1024];	// where the jpg's get put
gchar image_label[256];			// used by strftime to date stamp image
gchar video_device[256];		// opened to read images via v4l
gint picture_interval;			// seconds between pictures

float ref_update_fraction;		// amount a new image contributes to
								// reference image each cycle
gint alarm_threshold;			// percent of graph for alarm
float sig_pix_threshold;		// amount pixel must be different
								// (x*avg difference)		
float graph_scale;				// amount data is scaled before
								// being sent to 0-100 range plot																				
gint periodic_save_interval;	// force a save every xx snapshots

gint beep_on_alarm;				// console beep on alarm
gint show_target_box;           // puts active area on pictures
gchar alarm_command[1025];      // user command to execute on alarms


int dev;						// handle for v4l video camera device

struct alarm_zone alarm_zone;
unsigned int  	avg_ref_intensity;
unsigned int	avg_ds_intensity;
unsigned int	avg_ds1_intensity;
unsigned int	alarm_pix = 0;

/* The file selection widget and the string to store the chosen filename */
GtkWidget *file_selector;


gchar *selected_filename;

//=====================================================================
//=====================================================================
void on_exit1_activate                 (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	printf(_("on_exit1_activate\n"));
	v4l_close(dev);	
	gtk_main_quit();	
}

//=====================================================================
//=====================================================================
void
on_preferences1_activate               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
  	GtkWidget *wid;
	char buf[1025];
	
  	propertybox1 = create_propertybox1 ();
	
	// grey out the help button.... none written yet
	gnome_dialog_set_sensitive((GnomeDialog*)propertybox1, 3, FALSE);	

	// set all the displays to whatever the current memory settings are
	wid = lookup_widget(GTK_WIDGET(propertybox1),"image_dir");
	gtk_entry_set_text(GTK_ENTRY(wid),image_directory);

	wid = lookup_widget(GTK_WIDGET(propertybox1),"img_label");
	gtk_entry_set_text(GTK_ENTRY(wid),image_label);

	wid = lookup_widget(GTK_WIDGET(propertybox1),"Pix_interval");
	sprintf(buf,"%d",picture_interval);
	gtk_entry_set_text(GTK_ENTRY(wid),buf);

	wid = lookup_widget(GTK_WIDGET(propertybox1),"save_interval");
	sprintf(buf,"%d",periodic_save_interval);
	gtk_entry_set_text(GTK_ENTRY(wid),buf);

	wid = lookup_widget(GTK_WIDGET(propertybox1),"video_src");
	gtk_entry_set_text(GTK_ENTRY(wid),video_device);

	wid = lookup_widget(GTK_WIDGET(propertybox1),"ref_fraction");
	sprintf(buf,"%.2f",ref_update_fraction);
	gtk_entry_set_text(GTK_ENTRY(wid),buf);

	wid = lookup_widget(GTK_WIDGET(propertybox1),"alrm_threshold");
	sprintf(buf,"%d",alarm_threshold);	
	gtk_entry_set_text(GTK_ENTRY(wid),buf);

	wid = lookup_widget(GTK_WIDGET(propertybox1),"sig_pix_thres");
	sprintf(buf,"%.1f",sig_pix_threshold);	
	gtk_entry_set_text(GTK_ENTRY(wid),buf);

	wid = lookup_widget(GTK_WIDGET(propertybox1),"plt_scaler");
	sprintf(buf,"%.2f",graph_scale);	
	gtk_entry_set_text(GTK_ENTRY(wid),buf);

	wid = lookup_widget(GTK_WIDGET(propertybox1),"beep_on_alrm");
	gtk_toggle_button_set_active((GtkToggleButton *)wid, beep_on_alarm);
    
	wid = lookup_widget(GTK_WIDGET(propertybox1),"show_target_box");
	gtk_toggle_button_set_active((GtkToggleButton *)wid, show_target_box);
    
	wid = lookup_widget(GTK_WIDGET(propertybox1),"alarm_command");
	sprintf(buf,"%s",alarm_command);	
	gtk_entry_set_text(GTK_ENTRY(wid),buf);
    
    
	
	// since setting all the boxes seems to mark items as changed,
	// set box box to unchanged so apply button is greyed out until
	// the user changes an item
	gnome_property_box_set_state((GnomePropertyBox *)propertybox1,FALSE);
		
  	gtk_widget_show (propertybox1);	
}


//=====================================================================
//=====================================================================
void
on_about1_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
  	GtkWidget *about2;

  	about2 = create_about2 ();	
  	gtk_widget_show (about2);	
}

//=====================================================================
// save image via menu file/save command, prefix pixname with 'SP'
// to keep it different from alarm pictures
//=====================================================================
void
on_save1_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    time_t      t;
    struct tm  *tm;
    char        line[128];
		
	// write a copy to file because user asked for it
	time(&t);
    tm = localtime(&t);
    strftime(line,sizeof(line)-1,"SP%H%M%S.jpg",tm);	
	put_image_jpeg(line, rgb_buf, 640, 480, QUAL_DEFAULT);

}

//=====================================================================
// this routine gets called periodically (2 sec typically) and is the 
// driving force for capturing images.
//=====================================================================
gint timeout_callback( gpointer data )
{
	int size;
	char *image;
  	GtkWidget *wid;
	char tmp;
	char *img_ptr;
	int cnt;

	

	//grab a v4l frame
	if (dev <= 0)
	{
		g_print(_("Unable to use v4l camera device... open failed???"));	
		return TRUE;				// keep ticker happening
	}

	if(!v_pict.palette)
	{
		// get palette info
		if(ioctl(dev, VIDIOCGPICT, &v_pict)==-1)
		{
			g_print(_("Unable to get picture properties from webcam (VIDIOCGPICT failed)\n"));
			return TRUE;
		}
		if(v_pict.palette!=VIDEO_PALETTE_YUV420P && v_pict.palette!=VIDEO_PALETTE_RGB24)
		{
			// try to switch to RGB24 palette
			v_pict.palette=VIDEO_PALETTE_RGB24;
			if(ioctl(dev, VIDIOCSPICT, &v_pict)==-1)
			{
				// try to switch to YUV420P palette
				g_print(_("RGB24 not supported, trying YUV420P...\n"));
				v_pict.palette=VIDEO_PALETTE_YUV420P;
				if(ioctl(dev, VIDIOCSPICT, &v_pict)==-1)
				{
					g_print(_("YUV420P not supported. Unable to use this device\n"));
					return TRUE;
				}
			}
			
		}
	}
	
	image = get_image(dev,640,480,IN_DEFAULT,NORM_NTSC,v_pict.palette,&size);

	if ( image )
	{
		if(v_pict.palette==VIDEO_PALETTE_YUV420P)
		//YUV420P palette format
			ccvt_420p_rgb24(640,480,image,image+(640*480),image+(640*600),rgb_buf);
		else
		//BGR24 palette format
		{
			// grab a static memory copy for use in calcs and redraws
			memcpy(rgb_buf,image,sizeof(rgb_buf));
			// v4l returns bgr not rgb, so we need to swap red and blue
			// for our display
			img_ptr = rgb_buf;		
			for (cnt=0; cnt < 640*480; cnt++)
			{
				tmp = img_ptr[0];			// get blue for safe keeping
				img_ptr[0] = img_ptr[2];	// move red into correct place
				img_ptr[2] = tmp;			// park blue in correct place
				img_ptr += 3;				// bump to next triplet
			}
		}
    }
	else
		g_print(_("image capture failed\n"));
	
	// then dont forget to release buffers
	if (size)
    	munmap(image, size);
	else 
	if (image)
    	free(image);

	// let the widget know that it needs to be updated
	wid = GTK_WIDGET(lookup_widget(window1,"drawingarea1"));
	gtk_widget_queue_draw(wid);
	
	down_sample_image();		// convert 640x480 pix to 320x240 in ds_buf

	do_motion_analysis();		// check difference between ds_buf and ref_buf
	
	update_reference_image();	// avg ds_buf into ref_buff
	
	// keep us ticking... return 0 to terminate	

	return TRUE;
};

//=====================================================================
// given a box containing the alarm window, modify pixels in main
// display window to show box. Note main display is displayed at twice
// the x and y dimensions so scaling of the alarm_zone is required.
//=====================================================================
void mark_alarm_zone( struct alarm_zone *zone )
{
	int x,y;
	char *p1,*p2;

	if (zone->x1 < 0 || zone->x2 < 0 || zone->y1 < 0 || zone->y2 < 0 )
		return;
	if (zone->x1 > 639 || zone->x2 > 639 || zone->y1 > 479 || zone->y2 > 479 )
		return;
		
	p1 = rgb_buf + (zone->y1 * 2)*640*3;
	p2 = rgb_buf + (zone->y2 * 2)*640*3;
	for( x = 0; x < 640; x++)
	{
		*p1 = ~*p1;			// invert red component
		*(p1+1) = ~*(p1+1);	// invert green
		*(p1+2) = ~*(p1+2);	// invert blue

		*p2 = ~*p2;			// draw both horizontal lines
		*(p2+1) = ~*(p2+1);
		*(p2+2) = ~*(p2+2);	

		p1 += 3;
		p2 += 3;
	}

	p1 = rgb_buf + (zone->x1 * 2)*3;
	p2 = rgb_buf + (zone->x2 * 2)*3;	
	for( y = 0; y < 480; y++)
	{
		*p1 = ~*p1;			// invert red component
		*(p1+1) = ~*(p1+1);	// invert green
		*(p1+2) = ~*(p1+2);	// invert blue

		*p2 = ~*p2;			// draw both vertical lines
		*(p2+1) = ~*(p2+1);
		*(p2+2) = ~*(p2+2);	
		
		p1 += 640*3;
		p2 += 640*3;	
	}
}




//=====================================================================
// convert 640x480 picture down to 320x240
// use pixel averaging for best quality instead of subsampling
// 2 output buffers are filled...
// ds_buf[] has the downsampled image
// ds1_buf[] has a copy of the downsampled image corrected for
// 	intensity to make its avg intensity match the reference image
//=====================================================================
void down_sample_image(void)
{
	gint x,y;
	guchar *p0;
	guchar *p1;
	guchar *p2;
	guchar *p3;
	guchar *p4;
	guchar *pdest;
	unsigned int avg = 0;
	guchar correction;
	
	pdest = &ds_buf[0];
	for (y=0; y< 240; y++)
	{
		p1 = rgb_buf + (y*2) * 640 * 3;		// upper left cell
		p2 = p1 + 3;			            // upper right cell
		p3 = p1 + (640 * 3);				// lower left cell
		p4 = p3 + 3;						// lower right cell
		for (x=0; x<320; x++)
		{
			*pdest++ = (*p1++ + *p2++ + *p3++ + *p4++) / 4;	//red cells avg
			*pdest++ = (*p1++ + *p2++ + *p3++ + *p4++) / 4;	//grn cells avg
			*pdest++ = (*p1++ + *p2++ + *p3++ + *p4++) / 4;	//blu cells avg
			p1 += 3;
			p2 += 3;
			p3 += 3;
			p4 += 3;
		}
	}
	
	for ( p1 = &ds_buf[0]; p1 < &ds_buf[0]+sizeof(ds_buf); p1++ )
	{
		avg += *p1;
	}
	avg /= sizeof(ds_buf);
	avg_ds_intensity = avg;
//	g_print(_("downsampled image avg intensity = %u\n"),avg);

	// now generate an intensity normalized image
	p0 = &ds_buf[0];
	p1 = &ds1_buf[0];
	if (avg_ds_intensity < avg_ref_intensity)
	{
		correction = avg_ref_intensity - avg_ds_intensity;
//		g_print("making image lighter by %d\n",correction);		
		// make ds1 image brighter to match ref image

⌨️ 快捷键说明

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