📄 callbacks.c
字号:
// 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 + -