📄 main.c
字号:
// 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);// printf("reference image avg intensity = %u\n",avg); avg_ref_intensity = (unsigned char)avg; }//=====================================================================// 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){ int x,y; unsigned char *pdest; unsigned char *psrc; unsigned char *pref; unsigned char red; unsigned char green; unsigned char blue; unsigned char cresult; float fresult = 0.0f; int pixcnt; unsigned char 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 int context; char sbuf[256]; static int first = 1; char *cp; char **toks; char *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;// printf("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 = (unsigned char)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; } // label main view with time/date location stamp (display and filesave) if (blob_cnt > 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// 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 > alarm_threshold ) || ((image_cnt % periodic_save_interval) == 0)) { time(&t); tm = localtime(&t); strftime(line,sizeof(line)-1,"CSPY%H%M%S.jpg",tm); put_image_jpeg(line, rgb_buf, 640, 480, 80); } // on each alarm, execute a user command if (( blob_cnt > 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);// } } return fresult;}/* * read rgb image from v4l device * return: mmap'ed buffer and size * * sample call: * int size; * char *image; * int dev = v4l_open(VIDEO_DEV, IN_DEFAULT); * image = get_image (dev, width, height, input, norm, palette, &size); * // process rgb image buffer as required here * // then dont forget to release buffers * if (size) * munmap(image, size); * else if (image) * free(image); * v4l_close(dev);*/char *get_image(int dev, int width, int height, int input,int norm,int fmt,int *size){ struct video_capability vid_caps; struct video_mbuf vid_buf; struct video_mmap vid_mmap; struct video_channel vid_chnl; char *map = NULL; int len; *size = 0; // keep caller happy on error returns // setting input = 1 gets some users going if (ioctl (dev, VIDIOCGCAP, &vid_caps) == -1) { printf("ioctl (VIDIOCGCAP) failed\n"); return (NULL); } if (input != IN_DEFAULT) { vid_chnl.channel = -1; if (ioctl (dev, VIDIOCGCHAN, &vid_chnl) == -1) { printf("ioctl (VIDIOCGCHAN) failed\n"); } else { vid_chnl.channel = input; vid_chnl.norm = norm; if (ioctl (dev, VIDIOCSCHAN, &vid_chnl) == -1) { printf("ioctl (VIDIOCSCHAN) failed"); return (NULL); } } } // if no video buffer set, then set it //printf("before VIDIOCGMBUF vidbuf size=%d bytes\n",vid_buf.size); if (ioctl (dev, VIDIOCGMBUF, &vid_buf) == -1) { //printf("after VIDIOCGMBUF vidbuf size=%d bytes\n",vid_buf.size); // to do a normal read() map = malloc (width * height * 3); len = read (dev, map, width * height * 3); if (len <= 0) { free (map); return (NULL); } *size = 0; return (map); } map = mmap (0, vid_buf.size, PROT_READ|PROT_WRITE,MAP_SHARED,dev,0); if ((unsigned char *)-1 == (unsigned char *)map) { printf("mmap() failed \n"); return (NULL); } vid_mmap.format = fmt; vid_mmap.frame = 0; vid_mmap.width = width; vid_mmap.height =height;//printf("VIDIOCMCAPTURE started\n"); if (ioctl (dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { printf("VIDIOCMCAPTURE failed\n"); munmap (map, vid_buf.size); return (NULL); }//printf("VIDIOCSYNC started\n"); if (ioctl (dev, VIDIOCSYNC, &vid_mmap) == -1) { printf("VIDIOCSYNC failed \n"); munmap (map, vid_buf.size); return (NULL); }//printf("VIDIOCSYNC finished %d bytes\n",vid_buf.size); // vid_buf.size is actually the size of 2 frame buffers in the driver *size = vid_buf.size; return (map);}/* * int v4l_open(char *device) * example call int dev = v4l_open(VIDEO_DEV); * * */int v4l_open(char *device){ int dev = -1; int max_try = 5; /* we try 5 seconds/times to open the device */ /* open the video4linux device */ while (max_try) { dev = open (device, O_RDWR); if (dev == -1) { if (!--max_try) { fprintf (stderr, "Can't open device %s\n", device); exit (0); } sleep (1); } else { break; } } return dev;}/* * void v4l_close(int dev) * example call v4l_close(dev); * */void v4l_close(int dev){ if (dev > 0) close(dev);}int main( int argc, char *argv[] ){ int size; char *image; char tmp; char *img_ptr; int cnt; // used to store supported webcam palette mode struct video_picture v_pict; v_pict.palette=0; // mark supported palette unknown dev = v4l_open(video_device); // open the camera device if (dev <= 0) { printf("Unable to use v4l camera device... open failed???"); return TRUE; } if(!v_pict.palette) { // get palette info if(ioctl(dev, VIDIOCGPICT, &v_pict)==-1) { printf("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 printf("RGB24 not supported, trying YUV420P...\n"); v_pict.palette=VIDEO_PALETTE_YUV420P; if(ioctl(dev, VIDIOCSPICT, &v_pict)==-1) { printf("YUV420P not supported. Unable to use this device\n"); return TRUE; } } } } for (;;) { //grab a v4l frame 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 printf("image capture failed\n"); // then dont forget to release buffers if (size) munmap(image, size); else if (image) free(image); 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 sleep( picture_interval ); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -