应用场景
人流统计主要被广泛应用于一些商场,或者步行街等与人流相关的商业活动场所,这也是以人流来评价一个地方(或者是在一定时间内)的商业价值的一个重要手段。除这个人流统计之外,其实还有一个类似的算法是车流统计,车流统计主要用于高速公路或者马路。但从算法实现、技术角度来讲,这二者其实并没有太大的差别。
补充说明
本算法在OpenCV的自带示例里有完整代码,你完全可以参考该代码进行学习和修改。
全域类别说明
struct Object
{
bool existFlag ; //使用 0 no 1 yes
int missedFrame; //追丢的frame数
int grade; //跟追踪到的物体距离分数
CvPoint mean[200]; //轨迹点
int circleFrame; //在头部有圆形的张数
}
class HumanCounter
{
private:
CvPoint pt0,pt1,pt2,pt3,pt4,pt5; //绘图时使用
IplImage* templ ; //人的pattern
IplImage* hsv ; //当前的frame
IplImage* hsv_head ; //框人的部份
IplImage* newbg_model ; //一开始的背景
IplImage* templ_new ; //scale之后新的pattern
IplImage* backgroundImg ; //更新过后的背景
IplImage* backgroundImgModel ; //背景相减时使用
IplImage* foregroundImg ; //前景 Gray Level
IplImage* result ; //pattern比对的结果
IplImage* trace ; //轨迹
IplImage * regrayImg ; //撷取人的上部
IplImage * reBGRImg ; //前景 BGR
CvSeq * circles ; //记录圆的Sequence
IplImage *mask ; //屏蔽
CvMemStorage* storage ; //记录圆的Memory
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设定完成
bool Circle_on; //使用找人头的功能
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]; //轨迹中有几个转折点
bool circle_ok[10]; //每次框人时是否有圆
public:
struct Object humanObj[10]; //宣告10个物体
HumanCounter(int width, int height,int nChannels,int widthStep ,int t=0);
//将frame的信息传入 , t=1时启用找圆功能
t=0 时关闭找圆功能
//默认值是关闭状态
~HumanCounter();
SetThreshold(float scale,int threshold ); //读取人的大小及背景参数的值
SetRoi(int ra,int ry,int rw,int rh,int sx,int sy,int sw,int sh); //读取设定的ROI范围
loadtempl(); //读取pattern
loadframe(IplImage* tmp_frame); //读取当前frame
loadframe(BYTE* pImageArray); //可读取BYTE* pImageArray
subimage(); //背景相减
FindCircle(); //找圆
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 回传前景 BGR
//Imgnum=3 回传轨迹
releaseimage(); //释放所有内存空间
};
成员函式说明
HumanCounter::HumanCounter(int width, int height,int nChannels,int widthStep,int t){
目的: |
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 | |||
t |
int |
t=1 启用circle 功能,t=0关闭circle 功能 | |||
}
HumanCounter::~HumanCounter(){
目的: 释放宣告的内存空间
}
HumanCounter::SetThreshold(float scale,int threshold){
目的: |
将pattern的大小及背景参数读入 |
方法: |
将pattern的大小读入及背景参数读入,完成后SetThreshold_on设为true |
参数: |
Parameter |
Type |
Description |
scale |
float |
pattern的大小 |
threshold |
int |
背景参数 |
}
HumanCounter::SetRoi(int rx,int ry,int rw,int rh,,int sx,int sy,int sw,int sh){
目的: |
自动产生进出线方程式 | ||||
方法: |
将使用者圈选的innerROI范围(sx,sy,sw,sh)和调整后的outerROI范围(rx,ry,rw,rh)读入,并自动在调整后的ROI产生进出线(距离上面4/5高的地方)及其方程式,完成后SetRoi_on 设为true | ||||
参数: |
|||||
Parameter |
Type |
Description |
|||
rx |
int |
outerROI左上角x坐标 | |||
ry |
int |
outerROI左上角y坐标 | |||
rw |
int |
outerROI的宽 | |||
rh |
int |
outerROI的高 | |||
sx |
int |
innerROI左上角x坐标 | |||
sy |
int |
innerROI左上角y坐标 | |||
sw |
int |
innerROI的宽 | |||
sh |
int |
innerROI的高 | |||
}
HumanCounter::loadtempl(){
目的:读取body pattern
}
HumanCounter:: subimage()
目的: |
建立foreground |
方法: |
直接将hsv、backgroundImg作背景相减,并搭配threshold来产生前景影像,放置于foregroundImg的内存指针区块内 |
}
HumanCounter:FindCircle()
目的: |
寻找有圆的地方 |
方法: |
宣告一个 head_rect大小的范围,将人的框框上部1/5的地方resize成原大小的1/9,并在附近搜寻圆形,若有圆则将circle_ok[CenterNum-10] 设为true |
}
HumanCounter:Template_Match()
目的: |
使用人形模型跟前景比对 |
方法: |
建立新pattern,设定result(pattern比对结果)的大小,regrayImg 当前影像只包括框人的上半1/5,建立ROI后开始比对,将比对结果高的区域框起来后,覆盖掉附近区域并将中心点存入center_x , center_y ,CenterNum++,最后释放result、templ_new、regrayImg |
}
HumanCounter:: loadframe(IplImage* tmp_frame)
目的: |
把video读进来做处理 |
方法: |
1.背景相减得到foreground=> subimage()2.画出进出线3.开始做比对=> Template_Match()
4.判断框框之间的关系,若有物体出现跟先前的物体作比对 5.当物体轨迹存在且missedframe大于5时,判断其轨迹是否进入或离开(计数进出人数),完成后清除轨迹 |
参数: |
Parameter |
Type |
Description |
tmp_frame |
IplImage |
输入来源影像 |
}
HumanCounter:: getInOut(int k){
目的: |
得到进出人数 |
方法: |
当k=1回传in人数;当k=2回传out人数 |
参数: |
Parameter |
Type |
Description |
k |
int |
回传进出人数的判断 |
}
HumanCounter::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 |
读取坐标的选择 |
}
HumanCounter::ResetPoint(){
目的: |
将所有框框坐标归零 |
}
HumanCounter:: resetInOut()
目的: |
进出人数归零 |
}
HumanCounter:: releaseimage()
目的: |
Release variables and storage |
}
IplImage* HumanCounter:: GetImage(int imgnum)
目的: |
回传影像数据 |
方法: |
imgnum=1=>回传当前影像;imgnum=2 =>回传前景 BGR;imgnum=3 =>回传轨迹 |
参数: |
Parameter |
Type |
Description |
imgnum |
int |
判断回传影像数据 |
}
A successful blog needs unique, useful content that interests the readers just like me.
你好,我是opencv的初学者,你这个很不错,能不能共享下源码,让我学习一下,我是菜鸟对视频分析不是很清楚