人流量检测:(区分正负方向)
通过进行①视频目标检测,并②视频标定线段,利用③目标跨线逻辑,统计不同方向的流量
在视频上标定线段示例:
通过读取JSON格式的配置信息,获取视频内各条线段信息,示例如下:
{
"params":
{
"camera_line":
[
{
"roi": [ [389,624],[477,644]]
},
{
"roi": [ [564,660],[722,697]]
}
]
}
}
读取JSON格式的配置信息,并解析标定的点转为vector。
结构体如下
struct Point
{
uint16_t x;
uint16_t y;
};
struct ConfigLine
{
std::vector<Point> line; // 检测断面对应的两点(通过配置写入数据库)
uint16_t line_id; // 该断面对应的ID
uint64_t line_num =0; // 该断面对应的人流量(总流量)
uint64_t line_num_p =0; // 该断面对应的人流量(正向流量)
uint64_t line_num_n =0; // 该断面对应的人流量(反向流量)
};
struct ConfigInfos
{
std::vector<ConfigLine> con_lines;
uint8_t frames_count;
};
std::map<std::string, ConfigInfos> config_;
读取配置信息的相关代码如下:
string str(data);
Json::Value root;
JSONCPP_STRING errs;
Json::CharReaderBuilder build;
unique_ptr<Json::CharReader> const jsonReader(build.newCharReader());
bool jsonRet = jsonReader->parse(str.c_str(), str.c_str() + str.length(), &root, &errs);
if ((jsonRet != true) || (errs.size() != 0)){
return;
}
if (!root["params"].isObject()){
printf("[%s-%d]", __func__, __LINE__);
return;
}
Json::Value paraObj;
paraObj = root["params"];
if (!paraObj["camera_line"].isArray()) {
printf("[%s-%d]\n", __func__, __LINE__);
return;
}
Json::Value vehicleLineObj = paraObj["camera_line"];
ConfigInfos config;
config.frames_count = 2; //由于做流量统计 frames_count设置为常量2
for (int i = 0; i < vehicleLineObj.size(); i++){
ConfigLine linei;
Json::Value lineiObj = vehicleLineObj[i];
linei.line_id = i;
for (int j = 0; j < lineiObj["roi"].size(); j++){
Json::Value pointObj = lineiObj["roi"][j];
Point point;
point.x = pointObj[0].asInt();
point.y = pointObj[1].asInt();
linei.line.emplace_back(point);
//printf("[%s-%d]x=%d,y=%d\n", __func__, __LINE__, point.x, point.y);
}
config.con_lines.push_back(linei);
}
config_.insert(std::make_pair(camera_src, config));
目标跨线逻辑
函数1:计算两条直线 :返回是否相交 包含计算的交点坐标
// pt0, pt1 为标定线的两端点;pt2, pt3 为目标轨迹的两端点
bool EventPedesVolume::CrossPoint(Point pt0, Point pt1, Point pt2, Point pt3)
{ 代码详见网盘链接 }
函数2:实现两个向量之间的夹角计算:通过计算两个向量的斜率角,然后相减,就得到了夹角
如下为计算 向量P1P0 和 向量P3P2的夹角
float EventPedesVolume::getAngelOfTwoVector(Point pt0, Point pt1, Point pt2, Point pt3)
{ 代码详见网盘链接 }
函数3: 计算一条有方向的线(有顺序的标定断面的两点)与相同id不同帧位置目标的是否相交,以及夹角情况,以此判断计数是否+1
void EventPedesVolume::ComputerPedesVolume(vector<TargetAttribute> &frame1, vector<TargetAttribute> &frame2, vector<ConfigLine> &con_lines)
{
//printf("[%s-%d]frame1[0].tracker_id=%d,frame2[0].tracker_id=%d\n", __FUNCTION__, __LINE__, frame1[0].tracker_id, frame2[0].tracker_id);
{ 代码详见网盘链接 }
// 涉及
//
//{for遍历每一条线段
// {for遍历前一时刻每一个目标
// {for遍历后一时刻每一个目标,且根据逻辑考虑计数是否+1}
// }
//}
}
函数4:其实相当于主函数。
bool EventPedesVolume::Process(vector<TargetAttribute> &frame, ConfigInfos &config)
{ 代码详见网盘链接
//涉及
//在缓存frame_里寻找source相同的两帧图像
//再进行是否计数判断,并给响应流量统计属性赋值。
}
视频目标检测
视频目标检测和追踪。
链接:https://pan.baidu.com/s/16UjFMDUkAJsCHtlO6mzg9w