应用场景
入侵侦测通常可被广泛用于诸如禁行区域的非法进入,如:私家住宅、限制区域、军事区的非法进入等情景。检测对象为人物。
工作原理
预先设置一条线性区域,然后在该区域内检测移动人物,看是否有人物穿越。
补充说明
本算法容易受到穿越人物大小及穿越角度的影响,人体大小参数可设,但若是设置过大容易检测不到小物体,设置过小,则容易误报。通常需配合警报录像来工作,以实现实时的检测和事后的排查及过滤。注意:镜头视野(焦距)的大小也会影响检测的准确度。
使用者操作:
1.在视窗点选实体围墙的上面两角(顺序:左→右)
2.调整Threshold的大小:如果产生的FG杂讯太多,此时可以试着调高Threshold
3.调整pattern的大小:尽量让蓝色框包含整个人形
影片场景预设:
1.实体围墙,墙高至少要到成年人肩膀以上
2.摄影机的拍摄角度和围墙的法向量夹角不能超过45度以上
3.摄影机架设的高度约2.5公尺至3.5公尺左右
4.调整实体围墙分隔线最好是在画面1/2处左右
以下是接口说明。
全域类别说明:
struct Object
{
bool existFlag ; //使用 0 no 1 yes
int missedFrame; //追丢的frame数
int grade; //跟追踪到的物体距离分数
CvPoint mean[200]; //轨迹点
}
class IntruderDetect
{
private:
CvPoint pt0,pt1,pt2,pt3; //绘图时使用
IplImage* templ ; //人的pattern
IplImage* hsv ; //当前的frame
IplImage* newbg_model ; //一开始的背景
IplImage* templ_new ; //scale之后新的pattern
IplImage* backgroundImg ; //更新过后的背景
IplImage* backgroundImgModel ; //背景相减时使用
IplImage* foregroundImg ; //前景 Gray Level
IplImage* result ; //pattern比对的结果
IplImage* trace ; //轨迹
IplImage * reBGRImg ; //前景 BGR
IplImage *mask ; //屏蔽
int a,b,FrameNum; //in 人数 , out 人数 ,第几张frame
int p,i,j,tmpCounte,; // 用于回圈
int nWidth,nHeight,chnal,nWidthStep; //读入影像的宽.高.频道
int x1, y1, x2, y2; //定义的line
double nA,nB; //y=nA*x+nB
CvRect nrect; //set ROI
bool system_on; //开始数人数
bool SetThreshold_on; //人的大小,背景参数设定完成
bool SetRoi_on; //ROI设定完成
int block_x1[10],block_y1[10],block_x2[10],block_y2[10];
//存框框左上及右下坐标
float nscale; //pattern scale的大小
int nthreshold; //背景相减的threshold
int center_x[1000],center_y[1000], CenterNum;
//每个pattern比对到的中心 以及个数
int ptr[10]; //轨迹中有几个转折点
public:
struct Object humanObj[10]; //宣告10个物体
IntruderDetect(int width, int height,int nChannels,int widthStep);
~IntruderDetect();
SetThreshold(float scale,int threshold ); //读取人的大小及背景参数的值
SetRoi(int rx,int ry,int rw,int rh); //读取设定的ROI范围
SetRoad(int p_x0,int p_y0,int p_x1,int p_y1,int p_x2,int p_y2,int p_x3,int p_y3);
loadtempl(); //读取pattern
loadframe(IplImage* tmp_frame); //读取当前frame
subimage(); //背景相减
Template_Match(); //比对人型样板
GetPoint(int t,int k); //读取框人的坐标 可以不读取
//t从0到10代表每张frame画框的次数,最多10个
//K=1时读取左上x坐标
//K=2时读取左上y坐标
//K=3时读取右下x坐标
//K=4时读取右下y坐标
ResetPoint(); //reset框人的坐标
//使用GetPoint(int t,int k) 时一定要用
getInOut(int k); // k=1取得in 人数 , k=2取得out 人数
resetInOut(); //人数归零
IplImage* GetImage(int imgnum); //回传最后结果
//Imgnum=1 回传当前frame
//Imgnum=2 回传前景
//Imgnum=3 回传轨迹
releaseimage(); //释放所有内存空间
};
成员函式说明
IntruderDetect::IntruderDetect(int width, int height,int nChannels,int widthStep){
目的: |
initial all variables we’ll use the program | ||||
方法: |
set all variable will use | ||||
参数: |
|||||
Parameter |
Type |
Description |
|||
width |
int |
frame的宽 | |||
height |
int |
frame的高 | |||
nChannels |
int |
frame的channels | |||
widthStep |
int |
输入影像widthStep | |||
}
IntruderDetect::~IntruderDetect(){
目的: 释放宣告的内存空间
}
IntruderDetect::SetThreshold(float scale,int threshold){
目的: |
将pattern的大小及背景参数读入 |
方法: |
将pattern的大小读入及背景参数读入,完成后SetThreshold_on设为true |
参数: |
Parameter |
Type |
Description |
scale |
float |
pattern的大小 |
threshold |
int |
背景参数 |
}
IntruderDetect::SetRoi(int rx,int ry,int rw,int rh){
目的: |
产生搜索人的region | ||||
方法: |
针对围墙内部范围的移动物体做侦测,完成后SetRoi_on 设为true | ||||
参数: |
|||||
Parameter |
Type |
Description |
|||
rx |
int |
ROI左上角x坐标 | |||
ry |
int |
ROI左上角y坐标 | |||
rw |
int |
ROI的宽 | |||
rh |
int |
ROI的高 | |||
}
IntruderDetect::SetRoad(int p_x0,int p_y0,int p_x1,int p_y1,int p_x2,int p_y2,int p_x3,int p_y3){
目的: |
获得分界线斜率信息 | ||||
方法: |
取得围墙的四个点的信息,由左上和右上两点得到这两点连乘一线的斜率,完成后SetRoad_on 设为true | ||||
参数: |
|||||
Parameter |
Type |
Description |
|||
p_x0 |
int |
围墙左上角x坐标 | |||
p_y0 |
int |
围墙左上角y坐标 | |||
p_x1 |
int |
围墙右上角x坐标 | |||
p_y1 |
int |
围墙右上角y坐标 | |||
p_x2 |
int |
围墙右下角x坐标 | |||
p_y2 |
int |
围墙右下角y坐标 | |||
p_x3 |
int |
围墙左下角x坐标 | |||
p_x3 |
int |
围墙左下角y坐标 | |||
}
IntruderDetect::loadtempl(){
目的:读取body pattern
}
IntruderDetect:: subimage()
目的: |
建立foreground |
方法: |
直接将hsv、backgroundImg作背景相减,并搭配threshold来产生前景影像,放置于foregroundImg的内存指针区块内 |
}
IntruderDetect:Template_Match()
目的: |
利用人形模型跟前景比对,当入侵者在翻墙时产生形变时,这成为我们判定是否爬墙的依据之一 |
方法: |
建立新pattern,设定result(pattern比对结果)的大小,建立ROI后开始比对,将比对结果高的区域框起来后,覆盖掉附近区域并将中心点存入center_x , center_y ,CenterNum++,最后释放result、templ_new |
}
IntruderDetect:: loadframe(IplImage* tmp_frame)
目的: |
把video读进来做处理 |
方法: |
1.背景相减得到foreground=> subimage()
2.开始做比对=> Template_Match() 3.判断框框之间的关系,若有物体出现跟先前的物体作比对 4.当物体轨迹存在且missedframe大于7时,判断其轨迹是否进入或离开(计数进出人数),完成后清除轨迹 |
参数: |
Parameter |
Type |
Description |
tmp_frame |
IplImage |
输入来源影像 |
}
IntruderDetect:: getInOut(int k){
目的: |
得到穿越围墙进出人数 |
方法: |
当k=1回传穿越围墙进来人数;当k=2回传穿越围墙出去人数 |
参数: |
Parameter |
Type |
Description |
k |
int |
回传穿越围墙进出人数的判断 |
}
IntruderDetect::GetPoint(int t,int k){
目的: |
得到画框的点坐标 |
方法: |
k=1时读取左上x坐标;k=2时读取左上y坐标;k=3时读取右下x坐标;k=4时读取右下y坐标 |
参数: |
Parameter |
Type |
Description |
t |
int |
从0到10代表每张frame画框的次数,最多10个 |
k |
int |
读取坐标的选择 |
}
IntruderDetect::ResetPoint(){
目的: |
将所有框框坐标归零 |
}
IntruderDetect:: resetInOut()
目的: |
入侵人数归零 |
}
IntruderDetect:: releaseimage()
目的: |
Release variables and storage |
}
IplImage* IntruderDetect:: GetImage(int imgnum)
目的: |
回传影像数据 |
方法: |
imgnum=1=>回传当前影像;imgnum=2 =>回传前景;imgnum=3 =>回传轨迹 |
参数: |
Parameter |
Type |
Description |
imgnum |
int |
判断回传影像数据 |
}
测试程序及序列
测试程序: http://rg4.net/p/easyiv/libintruderdetect_test.7z
测试视频序列:http://rg4.net/p/easyiv/libintruderdetect_sample.avi
测试程序说明:
- 指定测试视频:libintruderdetect_test.exe 111.avi,这个111.avi是你输入的视频文件。若不指定则默认打开当前目录下的libintruderdetect_sample.avi文件,若这个文件不存在则打开电脑上的摄像头。
- 开始后请先通过鼠标拖拉点选设置警戒线。具体如下图。
- 附带文件:man.bmp,请将其与程序放在同一目录下使用。
- 测试程序快捷键:按r重新设定ROI检测区域,按p暂停处理,按t or ESC键中止。
韦老师:
您好!我是山东大学控制科学与工程学院一名研一的学生,我的导师是常发亮教授,我的研究方向是模式识别与智能系统,目前研究视频监控,现在正在完善入侵侦测这一功能,我对您在这方面的工作非常感兴趣,可以把您关于入侵侦测的源代码供我参考一下吗?
谢谢!
彭志勇
山东大学模式识别实验室
彭志勇,你好,入侵侦测的实现原理其实很简单,而且其基础源代码在opencv的示例程序下就有提供,建议你好好看看opencv的示例程序的代码,相信会对你的研究和学习会有很大帮助的。