图像运动检测系统

运动图像检测系统:

准备:

移植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!\n");

        /*则睡眠表示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("\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: 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("\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: 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("\nNow con_cnt=%d\n",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,'\0',1024);



     startplaymp3(&play_pid , flag);

   return 1;

}





/*************************************************

Function name: restart_caculate_play

Called by         : 函数key_pic_mp3

Parameter    : int flag

Description     : 未超过连续播放时间时,有新的图像或者外部中断检测到时调用函数

Return           : void

Autor & 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_mp3

Called by         : 函数main

Parameter    : int flag

Description     : 当检测到有外部中断,或者图像变化时处理函数

Return           : int

Autor & 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: main

Called by         : 

Parameter    : void

Description     : 主函数,检测按键是否有按下,通过pic.txt检测图像是否有变化

Return           : int

Autor & 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.");

 

你可能感兴趣的:(系统)