视频移动侦测VMD的实现
视频移动侦测区域报警的原理、实现与应用
简介
======
此项目用于前端摄像头的视频移动侦测报警。
之前已经发布了一个版本,功能比较简单,现在在以前版本的基础上增加了区域报警的功能。
所谓区域报警,就是在摄像头的视角范围定义出一些区域,当此区域的出现非法入侵的时候就产生报警。
通过这种方式可以有效的对重点区域进行监控而忽略其它的一些非重点区域。
功能要求
============
- 以矩形区域来表征目标
- 支持多区域报警
- 支持多级别报警
原理与实现
===============
移动侦测
============
通过分析目标区域的图片灰度值的变化来判断。
继承第一版本的算法(详情参考相关文档),采用二次差分的方式来对目标区域进行检测。
首先,在不考虑分区域报警的情形下,分析一下其算法实现。具体步骤如下:
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
/** Motion detecting ** File: motion_detect.h** Author: Hugui * E-Mail: y_y_z_l @ 163.com* Date: 2012.7.6** Changing Log:**//** Coordinate system of jpeg blocks.* * +---------------> x* |* |* |* |* V* y*/---> JPEG BLOCK / / / / / / | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 0 | 1 | 2 | | | | | | | 7 | ... | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
-----------------------------------------------------------------------------------------| | | | | | | | | | | | | | | | | | | | | | ####################################################### | | | # | | | | | | | # | | | # | | | | | | | # | | | # | | | | | | | # | | | # | | | | | | | # |
-------------------#-----------------------------------------------------#---------------| | # | | | | | | | # | | | # | | | | | | | # | | | # | | | | | | | # | /--> Selected zone 1#| | # | | | | | | | # | / | | # | | | | | | ---------------/ | | # | ########################################### | # | | | # | # | | | | | # | # |
-------------------#-----#-----------------------------------------#-----#---------------| | # | # | | | | | # | # | | | # | # | | | | | # | # | | | ####################################################### | | | | # | | | | | # | | | | | # | | | | | # | | | | | # | | | ######################### | | | | # | | | # | | # | # |
-------------------------#--------------------------#--------------#--------#------------| | | # | | | # | | # | # | | | | # | | | # | | # | # | | ########################## | | # | | # | # | /--> Selected zone 2#| # | | # | # | | # | | # | # | / | # | | # | # | | # | | # | ---------/ | # | | # | # | | | # | | # | # | | # | | # | # | | | # | | # | # |
---------#---------------#--------#--------|--------#--------------#--------#------------| # | | # | # | | | # | | # | # | | # | | ##################|######################## | # | . | # | | | # | | | # | | | # | . | # | | | | # | | | ######################### | . | # | | | | # | | | | | | | | ##########|############### | | | | | | | | | | | | | | | | | | | | \. \ \---> Selected zone 4# \--> Selected zone 3#
*//* * Coordinate system of alarm zone.** +--------------------------> x* | (left, top)* | +---------------------+* | | |* | | .p1(x1,y1) |* | | .p2(x2,y2) |* | | |* | +---------------------+ (right, bottom)* |* V* y* * p1(250,300) --> (0.250 * img_width, 0.3 * img_height)* p2(350,600) --> (0.350 * img_width, 0.6 * img_height)** Coordinate by thousandths. * Example:* value | actual coordinate * ------+---------------------------------* 100 | 0.1 * img_width(img_height)* 50 | 0.05 * img_width(img_height)* 500 | 0.5 * img_width(img_height)* 1 | 0.001 * img_width(img_height)*/#ifndef _H_MOTION_DETECT_H_#define _H_MOTION_DETECT_H_
#endif#ifdef __cplusplus
extern "C" {
#endif/* The maximum length of image */
#define IMG_WIDTH_MAX 640
#define IMG_HEIGHT_MAX 480/* The minimum length of image */
#define IMG_WIDTH_MIN 160
#define IMG_HEIGHT_MIN 120/* JPEG image block dimention: 8pixels * 8pixels */
#define JPEG_BLOCK_DIM 8/* Indicating whether the pointer parameter is INPUT or OUTPUT */
#define __INPUT__
#define __OUTPUT__/* How many zones which are being monitored */
#define ALARM_ZONE_MAX 20/* Don't be great than 5 */
#define ALARM_SENSITY_LEVEL_MAX 5/* * ----------------------- level 5 The least sensitive * * ----------------------- level 4* * ----------------------- level 3* | ALARM_SENSITY_STEP_VAL * ----------------------- level 2* * ----------------------- ALARM_SENSITY_START_VAL, start threshold, * level 1, The most sensitive** ----------------------- zero, means no changing.*//* The start threshold */
#define ALARM_SENSITY_START_VAL 5
/* The stepping value of each sensity level */
#define ALARM_SENSITY_STEP_VAL 10/* Each level */
#if ALARM_SENSITY_LEVEL_MAX > 5#error "ALARM_SENSITY_LEVEL_MAX is not allowed to be great than 5"
#elif ALARM_SENSITY_LEVEL_MAX < 1#error "ALARM_SENSITY_LEVEL_MAX is not allowed to be less than 1"
#else#if ALARM_SENSITY_LEVEL_MAX >= 1#define ALARM_SENSITY_LV1 1 #define ALARM_SENSITY_VAL_LV1 ALARM_SENSITY_START_VAL#define USING_ALARM_LV1#endif#if ALARM_SENSITY_LEVEL_MAX >= 2#define ALARM_SENSITY_LV2 2 #define ALARM_SENSITY_VAL_LV2 (ALARM_SENSITY_START_VAL + \ALARM_SENSITY_STEP_VAL * (ALARM_SENSITY_LV2 - 1))#define USING_ALARM_LV2#endif#if ALARM_SENSITY_LEVEL_MAX >= 3#define ALARM_SENSITY_LV3 3 #define ALARM_SENSITY_VAL_LV3 (ALARM_SENSITY_START_VAL + \ALARM_SENSITY_STEP_VAL * (ALARM_SENSITY_LV3 - 1))#define USING_ALARM_LV3#endif#if ALARM_SENSITY_LEVEL_MAX >= 4#define ALARM_SENSITY_LV4 4 #define ALARM_SENSITY_VAL_LV4 (ALARM_SENSITY_START_VAL + \ALARM_SENSITY_STEP_VAL * (ALARM_SENSITY_LV4 - 1))#define USING_ALARM_LV4#endif#if ALARM_SENSITY_LEVEL_MAX >= 5#define ALARM_SENSITY_LV5 5 #define ALARM_SENSITY_VAL_LV5 (ALARM_SENSITY_START_VAL + \ALARM_SENSITY_STEP_VAL * (ALARM_SENSITY_LV5 - 1))#define USING_ALARM_LV5#endif
#endif/* Error code */
#define EC_MEM 1 /* No memery */
#define EC_ID 2 /* ID error */
#define EC_NO_SLOT 3 /* Alarm table full */
#define EC_FRAM1 4 /* Not ready */
#define EC_FRAM2 5 /* Not ready */
#define EC_STATE 6 /* Error state */
#define EC_DIM 7 /* Dimention Error */
#define EC_DIM_CHANG 8 /* Dimention changed but no notify *//* * Bits operation ** dat: the target byte.* pos: the position you want to operate.* len: the width of bits.* val: the value you want to set or test.** Example:* dat | operation | result* ---------+-------------------------------+---------- * 11010001 | SET_BYTE_BITS(dat, 2, 2, 3) | 11011101* 11010001 | SET_BYTE_BITS(dat, 4, 2, 3) | 11110001* 10110111 | TEST_BYTE_BITS(dat, 3, 2, 1) | flase* 10110111 | TEST_BYTE_BITS(dat, 3, 2, 2) | true*/
#define SET_BYTE_BITS(dat, pos, len, val) do { \(dat) &= ~( (~(0xFF<<(len))) << (pos) ); /* Set to zero */ \(dat) |= ( ((val)&(~(0xFF<<(len)))) << (pos) ); /* Set val */ \} while (0)
#define TEST_BYTE_BITS(dat, pos, len, val) \( (((val)&(~(0xFF<<(len)))) << (pos)) == \( (dat) & ( (~(0xFF<<(len))) << (pos) ) ) ) /* Rectangle define */
typedef struct _tag_rect {unsigned short left;unsigned short right;unsigned short top;unsigned short bottom;
} Rect, *PRect;/* Image define */
typedef struct _tag_image {unsigned char * pbuf;int len;
} Image, *PImage;/* Define the alarm zone */
typedef struct _tag_alarm_zone {int id;Rect zone;unsigned char alarm_level;
} AlarmZone, *PAlarmZone;/* * Return the alarm info into an array whose type is AlarmInfoArray when * invoke motion_detect()*/
typedef AlarmZone AlarmInfoArray[ALARM_ZONE_MAX];/* * ------ Interface -------*//* Initial or reset the motion detecting system. */
int reset_motion_detect(void);/* * Set dimention of image * When the dimention of image has changed, you should call this function.* Default setting: 320 * 240*/
int set_img_dim(unsigned short width, unsigned short height);/* Add & remove alarm zone. Zone Cross or Zone Overlapping is OK */
int add_alarm_zone(Rect* zone, int id, unsigned char alarm_level);
int rm_alarm_zone(int id);
int rm_all_alarm(void);/* Invoke this at every image frame */
int motion_detect(Image* __INPUT__ img, AlarmInfoArray* __OUTPUT__ alarm_info, int* __OUTPUT__ alarm_count);/* * ------ Internal function --------*//* Caculate the alarm level by y. */
unsigned char whichlevel(int delta_y);/* Update the changed direction of y. */
void update_y_direction(int block_index, int delta_y);/* Update the alarm table. */
void update_alarm_tbl(int block_index, int delta_y);/* Scan the alarm table */
void generate_alarm(AlarmInfoArray* __OUTPUT__ alarm_info, int* __OUTPUT__ alarm_count);/* Check whether the selected block zone contains valid alarm. */
bool is_alarm(Rect* blk_zone, unsigned char alarm_level);/* * Transfer the rectangle from image view coordinate system * to jpeg block coordinate system.*/
void coordinate_transfer(Rect* alarm_zone, Rect* __OUTPUT__ blk_zone);#ifdef __cplusplus
}
#endif
/** Motion detecting ** File: motion_detect.c** Author: Hugui * E-Mail: y_y_z_l @ 163.com* Date: 2012.7.6** Changing Log:**/#include <string.h>
#include <malloc.h>
#include "motion_detect.h"extern int decode_y(unsigned char * jpeg, int jpeglen, int * y);/** The last changing direction of Y.* 00: grayscale no changed.* 01: grayscale increased.* 10: grayscale decreased.** last_y_direction[0][]* byte0 byte1 byte2* 01 00 10 01 10 10 00 01 10 10 00 01 ...* |* |* V* Start from here,This is the first block.* last_y_direction[1][]* ...**/
#define BLK_Y_NO_CHANGE 0
#define BLK_Y_INCREASED 1
#define BLK_Y_DECREASED 2
unsigned char last_y_direction[ALARM_SENSITY_LEVEL_MAX][ \(IMG_WIDTH_MAX / JPEG_BLOCK_DIM) * \(IMG_HEIGHT_MAX / JPEG_BLOCK_DIM) / 4];/* Last grayscale */
int last_y[(IMG_WIDTH_MAX / JPEG_BLOCK_DIM) * (IMG_HEIGHT_MAX / JPEG_BLOCK_DIM)];
int last_y_len;/* Current graysacle, this variable is for temperary using. */
int crt_y[(IMG_WIDTH_MAX / JPEG_BLOCK_DIM) * (IMG_HEIGHT_MAX / JPEG_BLOCK_DIM)];/** Alarm table.** 0: no alarm.* 1: ALARM !!!** alarm_tbl[0][]* byte0 byte1 byte2* 01001001 10100001 10100001 ...* |* |* V* Start from here,This is the first block.* alarm_tbl[1][]* ...**/
unsigned char alarm_tbl[ALARM_SENSITY_LEVEL_MAX][ \(IMG_WIDTH_MAX / JPEG_BLOCK_DIM) * \(IMG_HEIGHT_MAX / JPEG_BLOCK_DIM) / 8];/* The current width & height of image */
unsigned short img_width = 320;
unsigned short img_height = 240;/* State of motion detecting process */
#define MD_STATE_FRAM1 1
#define MD_STATE_FRAM2 2
#define MD_STATE_FRAM3 3
unsigned char motion_detect_state = MD_STATE_FRAM1;/* Registered alarm zone */
PAlarmZone alarm_zone_tbl[ALARM_ZONE_MAX];/* * Initial or reset the motion detecting system. * * @return: 0 for OK*/
int reset_motion_detect(void)
{motion_detect_state = MD_STATE_FRAM1;memset(last_y_direction, 0x00, sizeof(last_y_direction));return 0;
}/* * Set dimention of image * When the dimention of image has changed, you should call this function.* Default setting: 320 * 240** @width: width of image, unit by pixel* @height: height* * @return: 0 for OK*/
int set_img_dim(unsigned short width, unsigned short height)
{if (width > IMG_WIDTH_MAX ||height > IMG_HEIGHT_MAX )return EC_DIM;if (width < IMG_WIDTH_MIN ||height < IMG_HEIGHT_MIN )return EC_DIM;img_width = width;img_height = height;reset_motion_detect();return 0;
}/* * Add alarm zone.** @zone: selected alarm zone, a rectangle(check header file for details). * @id: Registered id.* @alarm_level: use macro defined in the header file.* * @return: 0 for OK.*/
int add_alarm_zone(Rect* zone, int id, unsigned char alarm_level)
{PAlarmZone p;int i;/* Check the zone id, no repeated */for (i = 0; i < ALARM_ZONE_MAX; i++) {if (alarm_zone_tbl[i]) {if (alarm_zone_tbl[i]->id == id)return EC_ID;}}/* Find an empty slot */for (i = 0; i < ALARM_ZONE_MAX; i++) {if (!alarm_zone_tbl[i])break;}/* No empty slot */if (i == ALARM_ZONE_MAX)return EC_NO_SLOT;/* Get memory */p = (PAlarmZone )malloc(sizeof(AlarmZone));if (!p) {return EC_MEM;}/* Check the range of rectangle */if (zone->left > 999) zone->left = 999;if (zone->right > 999) zone->right = 999;if (zone->top > 999) zone->top = 999;if (zone->bottom > 999) zone->bottom = 999;/* Initialize */p->id = id;p->alarm_level = alarm_level;memcpy(&p->zone, zone, sizeof(Rect));/* Insert to one empty slot */alarm_zone_tbl[i] = p;return 0;
}/** Remove alarm zone by id.** @id: id of alarm zone.** @return: 0 for OK*/
int rm_alarm_zone(int id)
{int i;for (i = 0; i < ALARM_ZONE_MAX; i++) {if (alarm_zone_tbl[i]) { if (alarm_zone_tbl[i]->id == id) {free(alarm_zone_tbl[i]);alarm_zone_tbl[i] = NULL;return 0;}}}return EC_ID;
}/** Remove all alarm zone .** @return: 0 for OK*/
int rm_all_alarm(void)
{memset(alarm_zone_tbl, 0x00, sizeof(alarm_zone_tbl));return 0;
}/** Invoke this at every image frame ** @img: An image object pointer. Contains buffer and length.* @alarm_info: Alarm info, this is an array.* @alarm_count: The valid length of @alarm_info array. ** @return: 0 for OK. The output parameters are valid only when return 0.*/
int motion_detect(Image* __INPUT__ img, AlarmInfoArray* __OUTPUT__ alarm_info, int* __OUTPUT__ alarm_count)
{int blocks;int i;int delta_y; /* Decode grayscale */blocks = decode_y(img->pbuf, img->len, crt_y);switch (motion_detect_state) {/* Not ready, only one frame. */case MD_STATE_FRAM1: last_y_len = blocks;memcpy(last_y, crt_y, sizeof(crt_y));motion_detect_state = MD_STATE_FRAM2;return EC_FRAM1;/* Not ready, only two frames. */case MD_STATE_FRAM2: /* Dimention of image has changed but didn't invoke set_img_dim() */if (blocks != last_y_len) {reset_motion_detect();return EC_DIM_CHANG;}for (i = 0; i < blocks; i++) {delta_y = crt_y[i] - last_y[i];update_y_direction(i, delta_y);}last_y_len = blocks;memcpy(last_y, crt_y, sizeof(crt_y));motion_detect_state = MD_STATE_FRAM3;return EC_FRAM2;/* YES! Loops in this case */case MD_STATE_FRAM3:/* Dimention of image has changed but didn't invoke set_img_dim() */if (blocks != last_y_len) {reset_motion_detect();return EC_DIM_CHANG;}for (i = 0; i < blocks; i++) {delta_y = crt_y[i] - last_y[i];update_alarm_tbl(i, delta_y);}last_y_len = blocks;memcpy(last_y, crt_y, sizeof(crt_y));generate_alarm(alarm_info, alarm_count); return 0;/* NOT expected */default:return EC_STATE;}
}/* * Caculate the alarm level by y.** @delta_y: grayscale changed.* * @return: Alarm level. Check the header file for details.*/
unsigned char whichlevel(int delta_y)
{if (delta_y < 0)delta_y = -delta_y;#if ALARM_SENSITY_LEVEL_MAX >= 5if (delta_y >= ALARM_SENSITY_VAL_LV5) return ALARM_SENSITY_LV5;else
#endif
#if ALARM_SENSITY_LEVEL_MAX >= 4if (delta_y >= ALARM_SENSITY_VAL_LV4)return ALARM_SENSITY_LV4;else
#if ALARM_SENSITY_LEVEL_MAX >= 3
#endifif (delta_y >= ALARM_SENSITY_VAL_LV3)return ALARM_SENSITY_LV3;else
#if ALARM_SENSITY_LEVEL_MAX >= 2
#endifif (delta_y >= ALARM_SENSITY_VAL_LV2)return ALARM_SENSITY_LV2;else
#endif
#if ALARM_SENSITY_LEVEL_MAX >= 1if (delta_y >= ALARM_SENSITY_VAL_LV1)return ALARM_SENSITY_LV1;else
#endifreturn 0; /* NO changing */
}/** Update the changed direction of y.* There are 4 blocks in one byte,each block own 2 bits.** @block_index: which jepg block?* @delta_y: y changed.*/
void update_y_direction(int block_index, int delta_y)
{int i;unsigned char level;level = whichlevel(delta_y);switch (level) {case 0:/* NO changing. Update all of the table */for (i = 0; i < ALARM_SENSITY_LEVEL_MAX; i++) {SET_BYTE_BITS(last_y_direction[i][block_index / 4], (block_index % 4) << 1, 2, BLK_Y_NO_CHANGE);}break;#ifdef USING_ALARM_LV5case ALARM_SENSITY_LV5:SET_BYTE_BITS(last_y_direction[ALARM_SENSITY_LV5 - 1][block_index / 4], (block_index % 4) << 1, 2, delta_y > 0 ? BLK_Y_INCREASED : BLK_Y_DECREASED);
#endif#ifdef USING_ALARM_LV4case ALARM_SENSITY_LV4:SET_BYTE_BITS(last_y_direction[ALARM_SENSITY_LV4 - 1][block_index / 4], (block_index % 4) << 1, 2, delta_y > 0 ? BLK_Y_INCREASED : BLK_Y_DECREASED);
#endif#ifdef USING_ALARM_LV3case ALARM_SENSITY_LV3:SET_BYTE_BITS(last_y_direction[ALARM_SENSITY_LV3 - 1][block_index / 4], (block_index % 4) << 1, 2, delta_y > 0 ? BLK_Y_INCREASED : BLK_Y_DECREASED);
#endif#ifdef USING_ALARM_LV2case ALARM_SENSITY_LV2:SET_BYTE_BITS(last_y_direction[ALARM_SENSITY_LV2 - 1][block_index / 4], (block_index % 4) << 1, 2, delta_y > 0 ? BLK_Y_INCREASED : BLK_Y_DECREASED);
#endif#ifdef USING_ALARM_LV1case ALARM_SENSITY_LV1:SET_BYTE_BITS(last_y_direction[ALARM_SENSITY_LV1 - 1][block_index / 4], (block_index % 4) << 1, 2, delta_y > 0 ? BLK_Y_INCREASED : BLK_Y_DECREASED);
#endifbreak;default:; /* WARNING! */ }
}/** Update the alarm table.** @block_index: which jepg block?* @delta_y: y changed.*/
void update_alarm_tbl(int block_index, int delta_y)
{unsigned char level;level = whichlevel(delta_y);switch (level) {
#ifdef USING_ALARM_LV5case ALARM_SENSITY_LV5:if ( /* Bright -> Dark -> Bright */(delta_y > 0 && TEST_BYTE_BITS(last_y_direction[ALARM_SENSITY_LV5 - 1][block_index / 4],(block_index % 4) << 1, 2, BLK_Y_DECREASED)) || /* Dark -> Bright -> Dark */(delta_y < 0 && TEST_BYTE_BITS(last_y_direction[ALARM_SENSITY_LV5 - 1][block_index / 4],(block_index % 4) << 1, 2, BLK_Y_INCREASED)) ) {alarm_tbl[ALARM_SENSITY_LV5 - 1][block_index / 8] |= 0x01 << (block_index % 8);}
#endif#ifdef USING_ALARM_LV4case ALARM_SENSITY_LV4:if ( /* Bright -> Dark -> Bright */(delta_y > 0 && TEST_BYTE_BITS(last_y_direction[ALARM_SENSITY_LV4 - 1][block_index / 4],(block_index % 4) << 1, 2, BLK_Y_DECREASED)) || /* Dark -> Bright -> Dark */(delta_y < 0 && TEST_BYTE_BITS(last_y_direction[ALARM_SENSITY_LV4 - 1][block_index / 4],(block_index % 4) << 1, 2, BLK_Y_INCREASED)) ) {alarm_tbl[ALARM_SENSITY_LV4 - 1][block_index / 8] |= 0x01 << (block_index % 8);}
#endif#ifdef USING_ALARM_LV3case ALARM_SENSITY_LV3:if ( /* Bright -> Dark -> Bright */(delta_y > 0 && TEST_BYTE_BITS(last_y_direction[ALARM_SENSITY_LV3 - 1][block_index / 4],(block_index % 4) << 1, 2, BLK_Y_DECREASED)) || /* Dark -> Bright -> Dark */(delta_y < 0 && TEST_BYTE_BITS(last_y_direction[ALARM_SENSITY_LV3 - 1][block_index / 4],(block_index % 4) << 1, 2, BLK_Y_INCREASED)) ) {alarm_tbl[ALARM_SENSITY_LV3 - 1][block_index / 8] |= 0x01 << (block_index % 8);}
#endif#ifdef USING_ALARM_LV2case ALARM_SENSITY_LV2:if ( /* Bright -> Dark -> Bright */(delta_y > 0 && TEST_BYTE_BITS(last_y_direction[ALARM_SENSITY_LV2 - 1][block_index / 4],(block_index % 4) << 1, 2, BLK_Y_DECREASED)) || /* Dark -> Bright -> Dark */(delta_y < 0 && TEST_BYTE_BITS(last_y_direction[ALARM_SENSITY_LV2 - 1][block_index / 4],(block_index % 4) << 1, 2, BLK_Y_INCREASED)) ) {alarm_tbl[ALARM_SENSITY_LV2 - 1][block_index / 8] |= 0x01 << (block_index % 8);}
#endif#ifdef USING_ALARM_LV1case ALARM_SENSITY_LV1:if ( /* Bright -> Dark -> Bright */(delta_y > 0 && TEST_BYTE_BITS(last_y_direction[ALARM_SENSITY_LV1 - 1][block_index / 4],(block_index % 4) << 1, 2, BLK_Y_DECREASED)) || /* Dark -> Bright -> Dark */(delta_y < 0 && TEST_BYTE_BITS(last_y_direction[ALARM_SENSITY_LV1 - 1][block_index / 4],(block_index % 4) << 1, 2, BLK_Y_INCREASED)) ) {alarm_tbl[ALARM_SENSITY_LV1 - 1][block_index / 8] |= 0x01 << (block_index % 8);}
#endifbreak;default:; /* WARNING! */ }/* Cover the old table */update_y_direction(block_index, delta_y);
}/** Scan the alarm table, when valid and the corresponding area * is registered, return alarm info.** @alarm_info: Alarm info, this is an array.* @alarm_count: The valid length of @alarm_info array. */
void generate_alarm(AlarmInfoArray* __OUTPUT__ alarm_info, int* __OUTPUT__ alarm_count)
{int i;Rect blk_zone;int index = 0;/* Reset the count */*alarm_count = 0;for (i = 0; i < ALARM_ZONE_MAX; i++) {if (alarm_zone_tbl[i]) {coordinate_transfer(&(alarm_zone_tbl[i]->zone), &blk_zone);if (is_alarm(&blk_zone, alarm_zone_tbl[i]->alarm_level)) {memcpy(&(*alarm_info)[index], alarm_zone_tbl[i], sizeof(AlarmZone));index++; }}}*alarm_count = index;/* Reset alarm_tbl. This is very IMPORTANT! */memset(alarm_tbl, 0x00, sizeof(alarm_tbl));
}/* * Check whether the selected block zone contains valid alarm.** @blk_zone: Rectangle descripted by jpeg block coordinate system.* @alarm_level: which alarm level do you want to check?** @return: true for ALARM and false for NO alarm.*/
bool is_alarm(Rect* blk_zone, unsigned char alarm_level)
{int row, col;int blk_index;for (row = blk_zone->top; row <= blk_zone->bottom; row++) {for (col = blk_zone->left; col <= blk_zone->right; col++) {blk_index = img_width / JPEG_BLOCK_DIM * row + col;if (alarm_tbl[alarm_level - 1][blk_index / 8] & (0x01 << (blk_index % 8))) {return true;}}}return false;
}/** Transfer the rectangle from image view coordinate system to jpeg block coordinate system.** @alarm_zone: Selected alarm zone.* @blk_zone: jpeg block coordinate system. See header file for details.*/
void coordinate_transfer(Rect* alarm_zone, Rect* __OUTPUT__ blk_zone)
{blk_zone->left = img_width / JPEG_BLOCK_DIM * alarm_zone->left / 1000;blk_zone->right = img_width / JPEG_BLOCK_DIM * alarm_zone->right / 1000;blk_zone->top = img_height / JPEG_BLOCK_DIM * alarm_zone->top / 1000;blk_zone->bottom = img_height / JPEG_BLOCK_DIM * alarm_zone->bottom / 1000;
}
这是一次识别的算法,能够滤除背景光变化。
在服务器端还有肤色识别以及轮廓识别甚至轨迹判断等算法。
参见:http://bbs.21ic.com/icview-359290-1-1.html
视频移动侦测VMD的实现相关推荐
- 【OpenCV图像处理入门学习教程五】基于背景差分法的视频目标运动侦测
OpenCV图像处理入门学习教程系列,上一篇第四篇:基于LoG算子的图像边缘检测 运动目标检测 关于运动目标检测的方法总结,目前能够实现运动物体检测的方法主要有以下几种: 1)背景差分法:能完整快速地 ...
- 网络摄像机编码标准及传输协议简析
视频监控系统从第一代模拟系统(VCR)到第二代部分数字化系统(DVR/NVR),再到第三代完全数字化系统(网络摄像机,网络视频服务器),三个阶段的发展演变预示着全数字化视频监控系统不久将成为安防市场的 ...
- 视频监控系统 摄像头与网络存储服务器兼容,网络视频监控系统技术要点
1 高清视频监控的主流技术 宽动态 数字宽动态并没有达到真正意义上的扩大成像动态范围的目的,而是通过软件的图像后处理算法提高了局部区域的对比度,一般由摄像机ISP模组实现.我们肉眼可辨别的灰阶范围十分 ...
- 视频监控系统及系统各节点设备理解和监控系统发展简介
从这几个层面理解视频监控系统中的设备:作用.分类.软件功能.组成部件.搭配使用(上一节点.下一节点.配合设备),本文从底层向上层介绍. 整个视频监控系统分为前端视频采集设备.中端传输处理设备.后端显示 ...
- 网络视频服务器与数字硬盘录像机的区别
在目前的视频监控领域内,除了模拟摄像机.模拟监视器等传统CCTV监控设备之外,网络摄像机(NetworkCamera).视频服务器(VideoServer)以及DVR是近年出现的三个炙手可热的名词.对 ...
- IVS:引领视频监控进入智能化初级阶段
IVS和Object Video 在平安城市建设中,随着安全监控系统迅速迈向数字化.网络化,系统的开放性.集成性.灵活性以及智能程度正在被更多的使用者所关注,安防产业面临着一个新兴的.机遇与挑战并存的 ...
- 视频智能分析的应用与前景
2007年8月,北京地铁13号线全段安装了"智能视频分析技术"系统后,一周内便成功地抓获了两伙窃贼,有媒体在报道中还曾这样绘声绘色的描述:屏幕上是几幅由摄像头传回的画面,一个画面中 ...
- 海康威视浅淡智能视频分析技术及产品的应用 智能视频分析技术的应用与发展
近年来,随着网络带宽.计算机处理能力和存储容量的迅速提高,以及各种视频信息处理技术的出现,全程数字化.网络化的视频监控系统优势愈发明显,其高度的开放性.灵活性为视频监控系统和设备的整体性能提升创造了必 ...
- 【转】何谓智能视频监控技术与应用
智能视频监控系统是采用图像处理.模式识别和计算机视觉技术,通过在监控系统中增加智能视频分析模块,借助计算机强大的数据处理能力过滤掉视频画面无用的或干扰信息.自动识别不同物体,分析抽取视频源中关键有用信 ...
最新文章
- 算法导论之NP完全性和近似算法
- java集合框架LinkedList类的方法理解
- AgileEAS.NET之ORM访问器
- 空间统计分析_空间汇总统计分析的小技巧:构造单调函数
- java异常练习:要求用户输入数字,捕获并处理用户输入错误的异常,给用户进行提示
- python常用模块一
- Onvif学习笔记(1)ONVIF Test Tool 的使用
- 北京大学计算机学硕考研分数线,2020北京大学研究生分数线汇总(含2016-2020历年复试)...
- Transformer---RNN网络
- 卢卡斯定理扩展卢卡斯
- 考过证券从业资格证的朋友们用的什么APP呢?
- 海康威视网络摄像头配置本地存储服务器(远程连接查看回放)
- 星起航跨境—亚马逊发展现状及未来趋势分析
- 基于Go语言星座查询~
- 数据库SQL Server中数据的模糊查询
- 设计模式--桥接模式(Bridge)
- java获取项目在tomcat中路径_java获取项目地址或tomcat绝对地址
- 一阶逻辑中的“一阶”原来这样理解
- 联想电脑重装后无摄像头图标,驱动已更新
- java版井字棋的设计与实现_JAVA版井字棋的设计与实现.doc
热门文章
- 深度学习在医疗方面的应用 精准医学受追捧
- 并发框架Disruptor
- wampserver服务器无法启动(图标颜色不对)
- DNS(BIND) 正向解析 反向解析 基本服务的搭建
- How to Fix Git Push Time Consuming Issue in a Big Team?
- Android短信彩信收发流程(应用层)
- 【IPC通信】匿名管道
- 如何使用数据库可移植性将邮箱数据库还原到新服务器
- VBoxManage: error: Failed to create the host-only
- 走近webpack(1)--多入口及devServer的使用