ReadMe_人流量检测:(区分正负方向)

人流量检测:(区分正负方向)

​ 通过进行①视频目标检测,并②视频标定线段,利用③目标跨线逻辑,统计不同方向的流量

在视频上标定线段示例:

通过读取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

猜你喜欢

转载自blog.csdn.net/qq_42835363/article/details/131166481