首页 > 代码库 > 图像运动检测系统

图像运动检测系统

运动图像检测系统:准备:移植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.");

 

图像运动检测系统