做者 原野之狼 日期 2012-7-26 11:43:00
视频移动侦测区域报警的原理、实现与应用 简介 ====== 此项目用于前端摄像头的视频移动侦测报警。 以前已经发布了一个版本,功能比较简单,如今在之前版本的基础上增长了区域报警的功能。 所谓区域报警,就是在摄像头的视角范围定义出一些区域,当此区域的出现非法入侵的时候就产生报警。 经过这种方式能够有效的对重点区域进行监控而忽略其它的一些非重点区域。 功能要求 ============ - 以矩形区域来表征目标 - 支持多区域报警 - 支持多级别报警 原理与实现 =============== 移动侦测 ============ 经过分析目标区域的图片灰度值的变化来判断。 继承初版本的算法(详情参考相关文档),采用二次差分的方式来对目标区域进行检测。 首先,在不考虑分区域报警的情形下,分析一下其算法实现。具体步骤以下: 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 联系我 ========= Author: Hugui E-Mail: y_y_z_l AT 163.com Date: 2012.7.6