zoukankan      html  css  js  c++  java
  • 【OpenCV学习】安防监控可疑走动报警

    作者:gnuhpc
    出处:http://www.cnblogs.com/gnuhpc/

    /*
     * =====================================================================================
     *
     *       Filename:  motiondetect.c
     *
     *    Description:  A method of detecting the motion
     *
     *        Version:  1.0
     *        Created:  01/10/2009 03:32:21 PM
     *       Revision:  none
     *       Compiler:  gcc
     *
     *         Author:  Futuredaemon (BUPT), gnuhpc@gmail.com
     *        Company:  BUPT_UNITED
     *
     * =====================================================================================
     */
    #include <stdio.h>
    #include <time.h>
    #include <cv.h>
    #include <cxcore.h>
    #include <highgui.h>
    int main( int argc, char** argv )
    {
    //声明IplImage指针
      IplImage* pFrame = NULL;     //pFrame为视频截取的一帧
      IplImage* pFrame1 = NULL;      //第一帧
      IplImage* pFrame2 = NULL;//第二帧
      IplImage* pFrame3 = NULL;//第三帧
      IplImage* pFrImg = NULL;     //pFrImg为当前帧的灰度图
      IplImage* pBkImg = NULL;     //pBkImg为当前背景的灰度图
      IplImage* pBkImgTran = NULL;//pBkImgTran为当前背景处理过的图像
      IplImage* pFrImgTran = NULL;//pFrImgTran为当前背景处理过的图像
      CvMat* pFrameMat = NULL;     //pFrameMat为当前灰度矩阵
      CvMat* pFrMat = NULL;      //pFrMat为当前前景图矩阵,当前帧减去背景图
      CvMat* bg1 = NULL;
      CvMat* bg2 = NULL;
      CvMat* bg3 = NULL;
      CvMat* pFrMatB = NULL;     //pFrMatB为二值化(0,1)的前景图
      CvMat* pBkMat = NULL;
      CvMat* pZeroMat = NULL;               //用于计算bg1 - bg2 的值
      CvMat* pZeroMatB = NULL;//用于计算 pZeroMat阈值化后来判断有多少个零的临时矩阵
      CvCapture* pCapture = NULL;
      int warningNum = 0;      //检测到有异物入侵的次数
      int nFrmNum = 0;//帧计数
      int status = 0;        //状态标志位
    //创建窗口
      cvNamedWindow("video", 1);
      cvNamedWindow("background",1);//背景
      cvNamedWindow("foreground",1);//前景
    //使窗口有序排列
      cvMoveWindow("video", 30, 0);
      cvMoveWindow("background", 360, 0);
      cvMoveWindow("foreground", 690, 0);
      if ( argc > 2 )
        {
          fprintf(stderr, "Usage: bkgrd [video_file_name]/n");
          return -1;
        }
    //打开摄像头
      if (argc ==1)
        if ( !(pCapture = cvCaptureFromCAM(-1)))
          {
            fprintf(stderr, "Can not open camera./n");
            return -2;
          }
    //打开视频文件
      if (argc == 2)
        if ( !(pCapture = cvCaptureFromFile(argv[1])))
          {
            fprintf(stderr, "Can not open video file %s/n", argv[1]);
            return -2;
          }
    //开始计时
      time_t start,end;
      time(&start);        //time() 返回从1970年1月1号00:00:00开始以来到现在的秒数(有10为数字)。
      printf("%d/n",start);
    //逐帧读取视频
      while (pFrame = cvQueryFrame( pCapture ))
        {
          nFrmNum++;
          //如果是第一帧,需要申请内存,并初始化
          if (nFrmNum == 1)
            {
              pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1);
              pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1);
              pBkImgTran = cvCreateImage(cvSize(pFrame->width,pFrame->height), IPL_DEPTH_8U,1);
              pFrImgTran = cvCreateImage(cvSize(pFrame->width,pFrame->height), IPL_DEPTH_8U,1);
              pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
              pZeroMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
              pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
              pFrMatB = cvCreateMat(pFrame->height, pFrame->width, CV_8UC1);
              pZeroMatB = cvCreateMat(pFrame->height, pFrame->width, CV_8UC1);
              pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
              cvZero(pZeroMat);
              //转化成单通道图像再处理
              cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY);
              //转换为矩阵
              cvConvert(pFrImg, pBkMat);
            }
          else /* 不是第一帧的就这样处理 */
            {
              //pFrImg为当前帧的灰度图
              cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);
              //pFrameMat为当前灰度矩阵
              cvConvert(pFrImg, pFrameMat);
              //pFrMat为前景图矩阵,当前帧减去背景图
              cvAbsDiff(pFrameMat, pBkMat, pFrMat);
              //pFrMatB为二值化(0,1)的前景图
              cvThreshold(pFrMat,pFrMatB, 60, 1, CV_THRESH_BINARY);
              //将图像矩阵转化为图像格式,用以显示
              cvConvert(pBkMat, pBkImgTran);   
              cvConvert(pFrMat, pFrImgTran);   
              //显示图像
              cvShowImage("video", pFrame);
              cvShowImage("background", pBkImgTran); //显示背景
              cvShowImage("foreground", pFrImgTran); //显示前景
              //以上是每抓取一帧都要做的工作,下面进行危险检测
              if (cvCountNonZero(pFrMatB) > 10000 && status == 0) //表示是第一帧的异物大于1W个像数点
                {/* 则需要将当前帧存储为第一帧 */
                  pFrame1 = cvCloneImage(pFrame);
                  bg1 = cvCloneMat(pFrMat);
                  status = 1;      //继续采集第2帧
                }
              else if (cvCountNonZero(pFrMatB) < 10000 && status == 1) // 表示第一帧的异物大于1W个像数点,而第二帧没有,则报警
                {
                  printf("NO.%d warning!!!!/n/n",warningNum++);
                  status = 0;
                }
              else if (cvCountNonZero(pFrMatB) > 10000 && status == 1)// 表示第一帧和第二帧的异物都大于1W个像数点
                {
                  pFrame2 = cvCloneImage(pFrame);
                  bg2 = cvCloneMat(pFrMat);
                  cvAbsDiff(bg1, bg2, pZeroMat);
                  cvThreshold(pZeroMat,pZeroMatB, 20, 1, CV_THRESH_BINARY);
                  if (cvCountNonZero(pZeroMatB) > 3000 ) //表示他们不连续,这样的话要报警
                    {
                      printf("NO.%d warning!!!!/n/n",warningNum++);
                      status = 0;
                    }
                  else
                    {
                      status = 2;                   //继续采集第3帧
                    }
                }
              else if (cvCountNonZero(pFrMatB) < 10000 && status == 2)//表示第一帧和第二帧的异物都大于1W个像数点,而第三帧没有
                {
                  //报警
                  printf("NO.%d warning!!!!/n/n",warningNum++);
                  status = 0;
                }
              else if (cvCountNonZero(pFrMatB) > 10000 && status == 2)//表示连续3帧的异物都大于1W个像数点
                {
                  pFrame3 = cvCloneImage(pFrame);
                  bg3 = cvCloneMat(pFrMat);
                  cvAbsDiff(bg2, bg3, pZeroMat);
                  cvThreshold(pZeroMat,pZeroMatB, 20, 1, CV_THRESH_BINARY);
                  if (cvCountNonZero(pZeroMatB) > 3000 ) //表示他们不连续,这样的话要报警
                    {
                      printf("NO.%d warning!!!!/n/n",warningNum++);
                    }
                  else //表示bg2,bg3连续
                    {
                      cvReleaseMat(&pBkMat);
                      pBkMat = cvCloneMat(pFrameMat); //更新背景
                    }
                    status = 0;                //进入下一次采集过程
                }
              //如果有按键事件,则跳出循环
              //此等待也为cvShowImage函数提供时间完成显示
              //等待时间可以根据CPU速度调整
              if ( cvWaitKey(2) >= 0 )
                break;
            }/* The End of the else */
        }/* The End of th while */
    //销毁窗口
        cvDestroyWindow("video");
        cvDestroyWindow("background");
        cvDestroyWindow("foreground");
    //释放图像和矩阵
        cvReleaseImage(&pFrImg);
        cvReleaseImage(&pBkImg);
        cvReleaseMat(&pFrameMat);
        cvReleaseMat(&pFrMat);
        cvReleaseMat(&pBkMat);
        cvReleaseCapture(&pCapture);
      return 0;
    }

    所研究的运动检测和背景更新方法实现的步骤如下:
    (1)开辟静态内存,对图像进行初始化准备采集;
    (2)采集图像,定义参数k,作为图像序列计数。采集第1幅图像时,则根据第一帧的大小信息进行矩阵、图像的初始化,并且将第一帧图像进行灰度化处理,并转化为矩阵,作为背景图像及矩阵;如果k不等于1则把当前帧进行灰度化处理,并转化为矩阵,作为当前帧的图像及矩阵。用当前帧的图像矩阵和背景帧的图像矩阵做差算出前景图矩阵并对其进行二值化以便计算它与背景帧差别较大的像素个数,也就是二值化后零的个数。
    当第一帧的异物大于1W个像数点则需要将当前帧存储为第一帧,并且将系统的状态转为1——采集第二帧;
    第一帧和第二帧的异物都大于1W个像数点时,将当前帧存储为第二帧,通过判断第一帧和第二帧的差值来确定两帧是否连续,若连续则将系统状态转为2——采集第三帧,若不连续则报警,并把系统状态转为0——采集背景帧;
    当第一帧和第二帧的异物都大于1W个像数点,而第三帧没有时则报警;
    若连续3帧的异物都大于1W个像数点时,将当前帧存储为第三帧,通过判断第二帧和第三帧的差值来确定两帧是否连续,若连续则将更新背景,若不连续则报警。然后把系统状态转为0——采集背景帧。
    注意其中有一个0-1-2-0....的状态机。

    作者:gnuhpc
    出处:http://www.cnblogs.com/gnuhpc/


                   作者:gnuhpc
                   出处:http://www.cnblogs.com/gnuhpc/
                   除非另有声明,本网站采用知识共享“署名 2.5 中国大陆”许可协议授权。


    分享到:

  • 相关阅读:
    win7 64位下 mongodb安装及命令运行
    CYQ.Data 快速开发EasyUI
    面试杂记:三个月的面试回忆录(携程、腾讯等)
    那点你不知道的XHtml(Xml+Html)语法知识(DTD、XSD)
    .NET各大平台数据列表控件绑定原理及比较(WebForm、Winform、WPF)
    CYQ.Data 支持WPF相关的数据控件绑定(2013-08-09)
    CYQ.Data V4系列全面开源(2013-08-04)
    C#与Java对比学习:类型判断、类与接口继承、代码规范与编码习惯、常量定义
    C#与Java对比学习:数据类型、集合类、栈与队列、迭达、可变参数、枚举
    突破瓶颈,对比学习:Eclipse开发环境与VS开发环境的调试对比
  • 原文地址:https://www.cnblogs.com/gnuhpc/p/2802281.html
Copyright © 2011-2022 走看看