首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

视频移动侦测区域报警的原理、实现与应用

视频移动侦测区域报警的原理、实现与应用

视频移动侦测区域报警的原理、实现与应用

  简介
  ======
此项目用于前端摄像头的视频移动侦测报警。
之前已经发布了一个版本,功能比较简单,现在在以前版本的基础上增加了区域报警的功能。
所谓区域报警,就是在摄像头的视角范围定义出一些区域,当此区域的出现非法入侵的时候就产生报警。
通过这种方式可以有效的对重点区域进行监控而忽略其它的一些非重点区域。

  功能要求
  ============
- 以矩形区域来表征目标
- 支持多区域报警
- 支持多级别报警

  原理与实现
  ===============

        移动侦测
        ============
通过分析目标区域的图片灰度值的变化来判断。
继承第一版本的算法(详情参考相关文档),采用二次差分的方式来对目标区域进行检测。
首先,在不考虑分区域报警的情形下,分析一下其算法实现。具体步骤如下:
1. 采集第一帧图片,计算出灰度值,并保存该灰度值。
2. 采集第二帧图片,计算出灰度值,并与前一次保存的灰度值进行比较,计算出灰度变化方向,并保存该变化方向,其包含三种情形:
- 灰度不变
- 灰度变大
- 灰度变小

用本次计算出来的灰度值覆盖上一次计算出的灰度值。
3. 采集第三帧图片, 计算出灰度值,并与前一次保存的灰度值进行比较,计算出灰度变化方向,并结合前一次的灰度变化方向来做判断,
  若本次的灰度变化方向与前一次的灰度变化方向相异,则表明目标区域出现了变化,应该产生报警。即:
- 本次灰度变小,前一次灰度变大,产生报警。
- 本次灰度变大,前一次灰度变小,产生报警。
- 本次灰度不变,不动作。
- 前一次灰度不变,不动作。

用本次计算出来的灰度值覆盖上一次计算出的灰度值。
用本次计算出来的灰度变化方向覆盖上一次计算出来的灰度变化方向。
4. 继续采集图片,并以上一步的算法来分析。此时进入稳定的循环检测期。

        区域报警
        ============
使用区域报警,其原理和上述小节描述的是完全一样的,
只是为了支持区域报警,程序中使用了特定的数据结构来描述这个增强功能。
- 灰度数组
使用数组 last_y[] 来存储上一帧jpeg图片的各个block的灰度值。
数组长度为 (IMG_WIDTH_MAX / JPEG_BLOCK_DIM) * (IMG_HEIGHT_MAX / JPEG_BLOCK_DIM)
当前帧的灰度值存储在 crt_y[]数组中。
- 灰度变化方向数组
使用二维数组 last_y_direction[][] 存储上一帧jpeg图片的灰度变化方向。
定义了三个宏来标示:
- #define BLK_Y_NO_CHANGE 0
- #define BLK_Y_INCREASED 1
- #define BLK_Y_DECREASED 2

数组的第一维长度是 ALARM_SENSITY_LEVEL_MAX, 由于需要支持多级别报警,所以需要记录每一个级别的灰度变化方向。
数组的第二维长度是 (IMG_WIDTH_MAX / JPEG_BLOCK_DIM) * (IMG_HEIGHT_MAX / JPEG_BLOCK_DIM) / 4,
为了节约内存资源,每个字节存储了4组变化方向。
- 报警数组
使用数组 alarm_tbl[] 存储目前的报警状态,为了节约内存资源,每一位代表一个block。
- 已注册报警区域
使用数组 alarm_zone_tbl[] 来存储已注册的报警区域,最大报警区域数可配置。
- 程序流程
程序流程和之前的描述是一致的,总体比较简单,看代码即可,不在赘述。

        灰度计算
        ============
使用第三方代码,具体原理超出本文档的范围。

  应用步骤
  ============
1. 初始化系统。如果在主程序的启动代码里有对全局变量进行清零操作,则这一步可以省略。
  reset_motion_detect();
2. 设置视频分辨率。参数不要超过范围,否则会返回错误。每次改变摄像头的分辨率之后都需要调用此函数重新初始化系统。
  set_img_dim(640, 480);
3. 注册报警区域。
  参数1:矩形区域的坐标采用比例数来设置,因此当摄像头的分辨率改变之后不会影响系统的工作。
  矩形结构体的各个元素的取值范围是[0 ~ 999] ,代表[0.000 ~ 0.999] , 注意是闭区间。
  参数2:ID号不能重复。
  参数3:报警级别使用头文件定义的宏来表示,不要采用数字。
  Rect alarm_zone = {400, 600, 400, 600};  /* 中间区域 */
  
  if (!add_alarm_zone(&alarm_zone, 1, ALARM_SENSITY_LV3)) {
      /* 添加报警区域成功 */
  } else {
      /* 出错了! */
  }
  可以添加多个报警区域,区域坐标可以交叉重叠。
4. 开始移动侦测。
  Image img;
  AlarmInfoArray alarm_info;
  int alarm_count;
  int i;
  
  img.pbuf = jpeg_buf;
  img.len = jpeg_len;
  
  if (!motion_detect(&img, &alarm_info, &alarm_count)) {
      for (i = 0; i < alarm_count; i++) {
          /*
          业务逻辑在这里处理
          printf("Alarm->  id:%d, level:%d, zone%d, %d) (%d, %d) \n",
              (int)alarm_info.id, (int)alarm_info.alarm_level,
              (int)alarm_info.zone.left, (int)alarm_info.zone.top,
              (int)alarm_info.zone.right, (int)alarm_info.zone.bottom);
          */
      }
  } else {
      /* 出错或者未就绪 */
  }
  以上代码需要以一定的间隔(比如0.5秒)循环调用,图片帧存在jpeg_buf里,帧长度存在jpeg_len里。
5. 移除报警区域。
  移除以上注册的ID号为1的报警区域。
  if (!rm_alarm_zone(1)) {
      /* 成功移除 */;
  } else {
      /* 出错 */
  }

6. 更改配置信息

- ALARM_ZONE_MAX
用于定义总的报警区域数,可以根据需要配置。
/* How many zones which are being monitored */
#define ALARM_ZONE_MAX 20
- ALARM_SENSITY_LEVEL_MAX
用于定义报警级别数,最大限制在5。
/* Don't be great than 5 */
#define ALARM_SENSITY_LEVEL_MAX 5
- ALARM_SENSITY_START_VAL
用于定义报警的门槛值,小于该值系统认为没有变化。
/* The start threshold */
#define ALARM_SENSITY_START_VAL 5
- ALARM_SENSITY_STEP_VAL
用于定义报警级别的步进值。
/* The stepping value of each sensity level */
#define ALARM_SENSITY_STEP_VAL 10
返回列表