首页 > 代码库 > 图像运动检测系统
图像运动检测系统
运动图像检测系统:准备:移植Linux2.6.29运行于s3c2440板子上,按键驱动,USB host controller驱动声卡驱动动态链接文件系统制作SDK-MOTION/src/fs/rootfs-motion.tar.gzmadplay播放器移植图像运动检测程序设计报警主程序设计1.当移动物体进入监控范围,系统报警2.系统报警后保存移动物体图像3.报警时播放一段指定音乐,mp3,avi格式4.三分钟内检测到连续变化的次数超过20次,认为是在下雨,检测系统暂停2小时,2小时后重启。有两种方式触发报警:1.外部按键中断2.图像有变化触发报警ls app driver fs kernel shelltar zxvf linux2.6.29.tar.gzcd linux2.6.29make cleancp config-motion .config该.config文件采用NFS起根文件系统,且已经选择了声卡驱动,网眼V2000摄像头驱动。修改.config的CMDLINE行的IP配置,NFS起根文件系统。make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-配置内核编译内核,解压根文件系统。按键驱动移植:SDK-MOTION/src/driver/button目录,采用上升沿触发方式。cd motion/src/drivermake clean;make生成mini2440_buttons_rise.ko参考madplay移植到mini2440.doc移植完后cp madplay /nfsroot/rootfs-motion检测程序设计:运动图像检测最常用图像检测方法是将当前帧和前一帧(背景帧)比较,如果不同像素的点数超过阀值,则认为图像有变化。本项目图像检测程序采用开源软件motion:http://www.lavrsen.dk/foswiki/bin/view/Motion/WebHome参考motion-3.2.11.1.tar.gz,motion的使用.doc将motion和motion.conf拷贝到文件系统/nfsroot/rootfs-motion/motion拷贝脚本文件:报警文件11.mp3,22.mp3count.txt用于存放计算/root/motion中图像数key_pic_motion总的程序运行脚本appon(motion.conf中on_event_start本)appoff(motion.conf中on_event_end)mapplay(播放器)pic.txt(记录是否有图像运动被检测到)cd /home/motion/src/shellcp -a * /nfsroot/rootfs-motion/motion报警主程序设计:程序中使用定时器,每三分钟比较图像连续变化次数是否超过20次,如果超过则添加一个2小时定时器,在这2小时如有图像变化不处理,如果没有超过则添加下一个3分钟定时器。报警主程序为app-motion.ccd /home/motion/src/appmake clean;makecp app-motion /nfsroot/rootfs-motion/motion项目测试一:NFS方式起根文件系统,要求文件系统使用动态链接的文件系统。cd /motion./key_pic_motion该脚本包括按键驱动加载,检测程序运行,主程序运行。测试按键中断:当按键被按下时,[type1]button detect, button_value:4 [key]Now detect **key** have change表明主程序检测到键值4被按下,开始报警。[key]No,have not mp3 play 表明目前系统中没有mp3播放,[key]Start add 3 minute alarm! 第一次检测时,添加一个3分钟定时器。THIS SONG IS 11.mp3 报警铃声是11.mp3Now con_cnt=0表明当前连续变化的次数为0测试项目二:测试运动图像[key2]pic motion detect!表明检测到图像运动。Now con_cnt=2表明目前检测到图像连续变化的次数是2。测试项目三:3分钟到达20次以上时[pic]3alarm! con_cnt=23Now maybe it is raining! system will sleep 7200 seconds!测试项目四:系统处于睡眠状态时,有外部中断或者图像运动时会提示:It is raining! system is sleeping!summary time:7200 seconds, sleep:157 seconds,nees sleep:7043 seconds代码分析:主要程序是app-motion.c#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/ioctl.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <signal.h>#include <sys/select.h>#include <sys/time.h>#include <errno.h>#include <sys/wait.h>#include <string.h>#include <sys/ipc.h>#include <sys/shm.h>#include <time.h>/*1. 检测到图像变化,报警2. 检测到外部中断,报警3. 3分钟能连续检测图像变化20次,则暂停2小时,2小时后在开启*//*define globe variable*//*play_pid:当前播放的MP3子进程ID*/unsigned int play_pid = 0;/*gradchild:当前播放的MP3孙子进程ID*/unsigned int gradchild = 0;unsigned int play_flag;/*共享内存描述标记sharemem: byte1:孙子进程ID号 byte2:是否有MP3播放标识play_flag_2 //byte3:MP3播放次数*/int shmid;char *p_addr;#define PERM S_IRUSR|S_IWUSR /*报警铃声歌曲名,song1图像变化报警铃声song2外部中断报警铃声*/char *song1="11.mp3";char *song2="22.mp3";//char *song="234.mp3";/*定时器时间为3分钟*/#define THREE_ALARM 3*60/*睡眠时间为2小时*/#define SLEEP_TIME 2*60*60#define CPM_CNT 20int threemin_alarm = 1;static int con_cnt=0;int sleep_flag = 0;unsigned int time_tmp;#define max(flag) (flag) >1 ? "pic":"key"//#define DEBUGint alarm_flag;static int pic_cnt;int cnt_fd;/*计算图像变化次数,超过2次则认为有图像变化*/#define COMPARE_CNT 5/*************************************************Function name: count_picCalled by : 函数mainParameter : voidDescription : 计算图片变化数Return : intAutor & date : ykz 10.4.25**************************************************/int count_pic(void){ int fd,ret; char *buf; buf = (char *)malloc(10); system("ls /root/motion | wc -l > count.txt"); lseek(cnt_fd, 0 ,SEEK_SET); ret = read(cnt_fd , buf , 10); if(ret) ret = atoi(buf); free (buf); return ret;}/*************************************************Function name: my_func_sleepalarmCalled by : 函数my_func_3alarmParameter : sing_noDescription : 3分钟连续变化20次后,延时2小时后的唤醒函数Return : voidAutor & date : ykz 10.4.25**************************************************/void my_func_sleepalarm(int sign_no){ if( sign_no == SIGALRM){ printf("Now sleep time finished!start a new work!\n"); /*则睡眠表示sleep_flag为0*/ sleep_flag = 0; }//end sing_no}/*************************************************Function name: my_func_3alarmCalled by : 函数restart_caculate_playParameter : sing_noDescription : 每隔3分钟检测图像连续变化是否超过20次Return : voidAutor & date : ykz 10.4.25**************************************************/void my_func_3alarm(int sign_no){ if( sign_no == SIGALRM){ struct tm *p; time_t timep; unsigned int second; printf("\n------------------warning------------------\n"); printf("[%s]3alarm!con_cnt=%d\n",max(alarm_flag),con_cnt); /*判断图像运动次数是否超过20次 如果是:则系统睡眠2小时; 不是,则系统继续添加下一个3分钟的定时器*/ if( con_cnt >= CPM_CNT){ if(play_flag){ kill(play_pid,SIGKILL); kill(gradchild,SIGKILL); wait(NULL); } //sleep (1); time(&timep); p = localtime(&timep); second = (p->tm_hour)*60*60 + (p->tm_min) * 60 + p->tm_sec; time_tmp=second; printf("Now maybe it is rainning!,system will sleep %d seconds!\n",SLEEP_TIME); con_cnt = 0; /*置睡眠标识sleep_flag为1*/ sleep_flag = 1; /*系统睡眠2小时*/ if(signal(SIGALRM,my_func_sleepalarm)<0) perror("signal"); alarm(SLEEP_TIME); } else{ printf("Nornal test!not rainning!\n"); con_cnt = 0; /*添加下一个3分钟的定时器*/ if(signal(SIGALRM,my_func_3alarm)<0) perror("signal"); alarm(THREE_ALARM); } printf("\n------------------warning------------------\n"); } //end sing_no}/*************************************************Function name: playCalled by : 函数startplaymp3Parameter : voidDescription : 子进程创建孙子进程播放MP3Return : voidAutor & date : ykz 10.4.2**************************************************/void play(void){ pid_t fd; char *c_addr; char *song_name; int play_flag_gradchild1=1; int play_flag_gradchild2=2; int i=0; /*创建孙子进程*/ fd = fork(); if(fd == -1) { perror("fork"); exit(1); } else if(fd == 0) /*孙子进程,播放MP3*/ { printf("\n--------------play mp3----------------\n"); if(alarm_flag==1) song_name=song1; else song_name=song1; printf("THIS SONG IS %s\n",song_name); /*使用madplay播放MP3*/ execl("/motion/madplay","madplay",song_name,NULL); printf("\n\n\n"); } else /*子进程*/ { /*把孙子进程的id传入共享内存*/ memcpy(c_addr,&fd,sizeof(pid_t)); /*目前在播放MP3,将播放标记传入共享内存*/ memcpy(c_addr+sizeof(int),&play_flag_gradchild1,4); /*等待孙子进程结束,只要结束: 传回play_flag_gradchild2=2,表示现在MP3没有播放*/ if(fd == wait(NULL)) { printf("\n------------------warning------------------\n"); /*通过共享内存传回play_flag_gradchild2=2,表明后面的一定不是连续的MP3播放*/ memcpy(c_addr+sizeof(int),&play_flag_gradchild2,4); printf("Gradchild normal finish!\n"); printf("------------------warning------------------\n"); }//end if(fd == wait(NULL)) }}/*************************************************Function name: startplaymp3Called by : 函数caculate_play,restart_caculate_playParameter : pid_t *childpidDescription : 主进程创建子进程Return : voidAutor & date : ykz 10.4.2**************************************************/void startplaymp3(pid_t *childpid,int flag){ int ret = 0; pid_t cun_pid; /*创建子进程*/ cun_pid = fork(); if(cun_pid == -1) { perror("son fork"); exit(1); } if(cun_pid == 0) /*子进程*/ play(); if(cun_pid > 0) /*父进程*/ { *childpid = cun_pid; sleep(1); /*让孙子进程先执行*/ /*如果是图像运动变化,将全局变量con_cnt加1*/ if( flag == 2 ) con_cnt++; printf("\nNow con_cnt=%d\n",con_cnt); /*把孙子进程的pid传给父进程*/ memcpy(&gradchild,p_addr,sizeof(pid_t)); }}/*************************************************Function name: caculate_playCalled by : 函数key_pic_mp3Parameter : int flagDescription : 连续播放时,计算连续播放时间,调用函数startplaymp3开始新的播放Return : intAutor & date : ykz 10.4.2**************************************************/int caculate_play(int flag){ int ret; /*kill掉当前播放MP3的子进程,孙子进程*/ kill(play_pid,SIGKILL); kill(gradchild,SIGKILL); wait(NULL); /*将共享内存清空*/ memset(p_addr,‘\0‘,1024); startplaymp3(&play_pid , flag); return 1;}/*************************************************Function name: restart_caculate_playCalled by : 函数key_pic_mp3Parameter : int flagDescription : 未超过连续播放时间时,有新的图像或者外部中断检测到时调用函数Return : voidAutor & date : ykz 10.4.2**************************************************/void restart_caculate_play(int flag){ int ret; /*add 3 minute alarm*/ if(threemin_alarm){ if(signal(SIGALRM,my_func_3alarm)<0) perror("signal"); ret = alarm(THREE_ALARM); printf("[%s]Start add 3 minute alarm!\n",max(flag)); threemin_alarm = 0; }#if 1 /*判断是否有子进程,或者孙子进程,如果有则KILL掉*/ if(play_flag){ kill(play_pid,SIGKILL); kill(gradchild,SIGKILL); wait(NULL); //sleep(1); }#endif play_pid = 0; gradchild = 0; memset(p_addr,‘\0‘,1024); /*开始播放MP3*/ startplaymp3(&play_pid,flag);}/*************************************************Function name: key_pic_mp3Called by : 函数mainParameter : int flagDescription : 当检测到有外部中断,或者图像变化时处理函数Return : intAutor & date : ykz 10.4.2**************************************************/int key_pic_mp3(int flag){ printf("------------------------- KEY_PIC_MP3 ----------------------------\n"); printf("[%s]Now detect ** %s ** have change\n",max(flag),max(flag)); int ret = 0; int over_flag_2; int play_flag_2; /*sleep_flag 用于判断,检测系统是否处于2小时的睡眠状态*/ if(sleep_flag){ printf("It is rainning!system is sleeping!\n"); struct tm *p; time_t timep; unsigned int second; time(&timep); p = localtime(&timep); second = (p->tm_hour)*60*60 + (p->tm_min) * 60 + p->tm_sec; printf("summary time:%d seconds,sleep:%d seconds,need sleep:%d seconds\n", SLEEP_TIME,second-time_tmp,SLEEP_TIME-(second-time_tmp)); return 0; } alarm_flag = flag; /*从sharemem中读出是否有MP3处在播放状态标识*/ memcpy(&play_flag_2,p_addr + sizeof(int),sizeof(int));// printf("===>key_pic_mp3,play_flag_2=%d\n",play_flag_2); play_flag = play_flag_2; /*play_flag_2:当前是否有MP3在播放 0:当前没有MP3播放 1:子进程当前处在MP3播放状态 2:孙子当前播放MP3正常结束,且当前没有MP3播放*/ /*当前有MP3在播放*/ if(play_flag_2 == 1){ printf("[%s]Yes,have mp3 play\n",max(flag)); /*调用*/ ret = caculate_play(flag); } /*当前无MP3在播放*/ else{ printf("[%s]No, have not mp3 play\n",max(flag)); restart_caculate_play(flag); } return ret;}/*************************************************Function name: mainCalled by : Parameter : voidDescription : 主函数,检测按键是否有按下,通过pic.txt检测图像是否有变化Return : intAutor & date : ykz 10.4.2**************************************************/main(void){ int buttons_fd,pic_fd; char pic_buf[1]; int key_value; int flag; int ret; int tmp_cnt; /*设备文件的打开*/ buttons_fd = open("/dev/buttons", 0); if(buttons_fd < 0) { perror("open device buttons"); exit(1); } printf("open buttons sucess!\n"); /*文件pic.txt记录是否有图像变化。 1:有图像变化 0:没有图像变化*/ pic_fd = open("pic.txt",O_RDWR | O_CREAT,0666); if(pic_fd < 0) { perror("open pic.txt"); exit(1); } printf("open pic.txt success!\n"); /*文件count.txt用于图像连续变化时,记录/root/motion中图片张数*/ cnt_fd = open("count.txt",O_RDWR | O_CREAT,0666); if(cnt_fd < 0){ perror("open count.txt"); exit(1); } printf("open count.txt success!\n"); system("ls > count.txt"); /*共享内存申请*/ if((shmid = shmget(IPC_PRIVATE,20,PERM))== -1) exit(1); p_addr = shmat(shmid,0,0); memset(p_addr,‘\0‘,1024); /*主循环,首先判断是外部中断还是图像变化*/ while(1){ /*外部中断检测,监听获取键值*/ ret = read(buttons_fd, &key_value, sizeof key_value); if (ret != sizeof key_value) perror("read buttons\n"); else { if(key_value){ printf("====================================================================\n"); printf("\n\n\n====================================================================\n"); printf("[type1]button detect,buttons_value: %d\n", key_value); /*外部中断处理*/ key_pic_mp3(1); } } //end else /*图形变化检测,当有图像变化时motion会产生一个事件, 事件处理为脚本/motion/appon,该脚本先点亮LED灯; 然后向文件/motion/pic.txt写入字符"1"表明现在有图像变化被检测到; 读取文件/motion/pic.txt第一个字符 0:没有图像变化 1:有图像变化*/ lseek(pic_fd, 0 ,SEEK_SET); ret = read(pic_fd, pic_buf, 1); if(ret==1) { if(pic_buf[0] == ‘1‘){ /*有图像变化被检测到*/ printf("====================================================================\n"); printf("\n\n\n====================================================================\n"); printf("[type2]pic motion detect!\n"); lseek(pic_fd, 0 ,SEEK_SET); if((ret = write(pic_fd, "0", 1))) lseek(pic_fd, 0 ,SEEK_SET); // system("rm /root/motion/* -rf"); pic_cnt = count_pic(); //printf("first pic_cnt=%d\n",pic_cnt); /*图像运动变化处理*/ key_pic_mp3(2); } else if(pic_buf[0] == ‘0‘){ tmp_cnt = count_pic(); if( (tmp_cnt-pic_cnt) > COMPARE_CNT){ printf("====================================================================\n"); printf("\n\n\n====================================================================\n"); printf("[type3]pic motion detect!\n"); // system("rm /root/motion/* -rf"); pic_cnt = count_pic(); /*连续图像运动变化处理*/ key_pic_mp3(2); } } //end else if } sleep (2); }//end while close (cnt_fd); close (pic_fd); close (buttons_fd); exit(0); }
该项目按键驱动程序:mini2440_buttons_rise.c#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/poll.h>#include <linux/irq.h>#include <asm/irq.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include <mach/regs-gpio.h>#include <mach/hardware.h>#include <linux/platform_device.h>#include <linux/cdev.h>#include <linux/miscdevice.h>#define DEVICE_NAME "buttons"struct button_irq_desc { int irq; int pin; int pin_setting; int number; char *name; };static struct button_irq_desc button_irqs [] = { {IRQ_EINT8 , S3C2410_GPG0 , S3C2410_GPG0_EINT8 , 0, "KEY0"}, {IRQ_EINT11, S3C2410_GPG3 , S3C2410_GPG3_EINT11 , 1, "KEY1"}, {IRQ_EINT13, S3C2410_GPG5 , S3C2410_GPG5_EINT13 , 2, "KEY2"}, {IRQ_EINT14, S3C2410_GPG6 , S3C2410_GPG6_EINT14 , 3, "KEY3"}, {IRQ_EINT15, S3C2410_GPG7 , S3C2410_GPG7_EINT15 , 4, "KEY4"}, {IRQ_EINT19, S3C2410_GPG11, S3C2410_GPG11_EINT19, 5, "KEY5"},};static int key_values = 0;static DECLARE_WAIT_QUEUE_HEAD(button_waitq);static volatile int ev_press = 0;static irqreturn_t buttons_interrupt(int irq, void *dev_id){ struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id; int down; // udelay(0); down = !s3c2410_gpio_getpin(button_irqs->pin); if (!down) { //printk("rising\n"); key_values = button_irqs->number + 1; ev_press = 1; wake_up_interruptible(&button_waitq); } else { //printk("falling\n"); ev_press = 0; return 0; } return IRQ_RETVAL(IRQ_HANDLED);}static int s3c24xx_buttons_open(struct inode *inode, struct file *file){ int i; int err = 0; for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) { //printk("gpio setup\n"); s3c2410_gpio_cfgpin(button_irqs[i].pin, button_irqs[i].pin_setting); //add by ykz if (button_irqs[i].irq < 0) { continue; } /* IRQ_TYPE_EDGE_FALLING,IRQ_TYPE_EDGE_RISING,IRQ_TYPE_EDGE_BOTH */ //err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH, // button_irqs[i].name, (void *)&button_irqs[i]); err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_RISING, button_irqs[i].name, (void *)&button_irqs[i]); if (err) break; } if (err) { i--; for (; i >= 0; i--) { if (button_irqs[i].irq < 0) { continue; } disable_irq(button_irqs[i].irq); free_irq(button_irqs[i].irq, (void *)&button_irqs[i]); } return -EBUSY; } ev_press = 0; return 0;}static int s3c24xx_buttons_close(struct inode *inode, struct file *file){ int i; for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) { if (button_irqs[i].irq < 0) { continue; } free_irq(button_irqs[i].irq, (void *)&button_irqs[i]); } return 0;}static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp){ unsigned long err; //int i=0;#if 0 if (!ev_press) { if (filp->f_flags & O_NONBLOCK) return -EAGAIN; else wait_event_interruptible(button_waitq, ev_press); }#endif if(count != sizeof key_values) return -EINVAL; ev_press = 0; err = copy_to_user(buff, &key_values, sizeof(key_values)); key_values = 0; return sizeof(key_values);}static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait){ unsigned int mask = 0; poll_wait(file, &button_waitq, wait); //printk("poll\n"); if (ev_press){ //printk("==>read\n"); mask |= POLLIN | POLLRDNORM; } return mask;}static struct file_operations dev_fops = { .owner = THIS_MODULE, .open = s3c24xx_buttons_open, .release = s3c24xx_buttons_close, .read = s3c24xx_buttons_read, .poll = s3c24xx_buttons_poll,};static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops,};static int __init dev_init(void){ int ret; ret = misc_register(&misc); printk (DEVICE_NAME"\tinitialized\n"); return ret;}static void __exit dev_exit(void){ misc_deregister(&misc);}module_init(dev_init);module_exit(dev_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("FriendlyARM Inc.");
图像运动检测系统
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。