运动图像检测系统: 准备: 移植Linux2.6.29运行于s3c2440板子上, 按键驱动, USB host controller驱动 声卡驱动 动态链接文件系统制作SDK-MOTION/src/fs/rootfs-motion.tar.gz madplay播放器移植 图像运动检测程序设计 报警主程序设计 1.当移动物体进入监控范围,系统报警 2.系统报警后保存移动物体图像 3.报警时播放一段指定音乐,mp3,avi格式 4.三分钟内检测到连续变化的次数超过20次,认为是在下雨,检测系统暂停2小时,2小时后重启。 有两种方式触发报警: 1.外部按键中断 2.图像有变化触发报警 ls app driver fs kernel shell tar zxvf linux2.6.29.tar.gz cd linux2.6.29 make clean cp 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/driver make 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.mp3 count.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/shell cp -a * /nfsroot/rootfs-motion/motion 报警主程序设计: 程序中使用定时器,每三分钟比较图像连续变化次数是否超过20次,如果超过则添加一个2小时定时 器,在这2小时如有图像变化不处理,如果没有超过则添加下一个3分钟定时器。 报警主程序为app-motion.c cd /home/motion/src/app make clean;make cp 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.mp3 Now con_cnt=0表明当前连续变化的次数为0 测试项目二:测试运动图像 [key2]pic motion detect!表明检测到图像运动。 Now con_cnt=2表明目前检测到图像连续变化的次数是2。 测试项目三: 3分钟到达20次以上时 [pic]3alarm! con_cnt=23 Now 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 20 int threemin_alarm = 1; static int con_cnt=0; int sleep_flag = 0; unsigned int time_tmp; #define max(flag) (flag) >1 ? "pic":"key" //#define DEBUG int alarm_flag; static int pic_cnt; int cnt_fd; /*计算图像变化次数,超过2次则认为有图像变化*/ #define COMPARE_CNT 5 /************************************************* Function name: count_pic Called by : 函数main Parameter : void Description : 计算图片变化数 Return : int Autor & 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_sleepalarm Called by : 函数my_func_3alarm Parameter : sing_no Description : 3分钟连续变化20次后,延时2小时后的唤醒函数 Return : void Autor & 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! "); /*则睡眠表示sleep_flag为0*/ sleep_flag = 0; }//end sing_no } /************************************************* Function name: my_func_3alarm Called by : 函数restart_caculate_play Parameter : sing_no Description : 每隔3分钟检测图像连续变化是否超过20次 Return : void Autor & 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(" ------------------warning------------------ "); printf("[%s]3alarm!con_cnt=%d ",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! ",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! "); con_cnt = 0; /*添加下一个3分钟的定时器*/ if(signal(SIGALRM,my_func_3alarm)<0) perror("signal"); alarm(THREE_ALARM); } printf(" ------------------warning------------------ "); } //end sing_no } /************************************************* Function name: play Called by : 函数startplaymp3 Parameter : void Description : 子进程创建孙子进程播放MP3 Return : void Autor & 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(" --------------play mp3---------------- "); if(alarm_flag==1) song_name=song1; else song_name=song1; printf("THIS SONG IS %s ",song_name); /*使用madplay播放MP3*/ execl("/motion/madplay","madplay",song_name,NULL); printf(" "); } 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(" ------------------warning------------------ "); /*通过共享内存传回play_flag_gradchild2=2,表明后面的一定不是连续的MP3播放*/ memcpy(c_addr+sizeof(int),&play_flag_gradchild2,4); printf("Gradchild normal finish! "); printf("------------------warning------------------ "); }//end if(fd == wait(NULL)) } } /************************************************* Function name: startplaymp3 Called by : 函数caculate_play,restart_caculate_play Parameter : pid_t *childpid Description : 主进程创建子进程 Return : void Autor & 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(" Now con_cnt=%d ",con_cnt); /*把孙子进程的pid传给父进程*/ memcpy(&gradchild,p_addr,sizeof(pid_t)); } } /************************************************* Function name: caculate_play Called by : 函数key_pic_mp3 Parameter : int flag Description : 连续播放时,计算连续播放时间,调用函数startplaymp3开始新的播放 Return : int Autor & 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,'