Commit 0723c89b authored by DESKTOP-73N29FP\12868's avatar DESKTOP-73N29FP\12868

提交事件的源码代码

parent 55e828bf
Pipeline #822 failed with stages
#include <stdio.h>
#include <unistd.h>
#include "EventsRos.h"
#include "http_client_curl.h"
#include "LogBase.h"
#include <sstream>
#include <string>
#include "EventInfo.h"
#include <iostream>
#include <memory>
int EventsRos::loadConfig(ros::NodeHandle& nh)
{
SDK_LOG(SDK_INFO, "EventsRos::loadConfig");
char url[1024] = { 0 };
// 自有平台
snprintf(url, 1023, "http://%s:%d/traffic/uploadParticipants", m_ip.c_str(), m_port);
m_Url = url;
EventsConfig& config = m_jfx_events.m_cfg;
nh.param<std::string>("devNo", m_devNo, "none");
nh.param<std::string>("mecNo", m_mecNo, "none");
//nh.param<int32_t>("threadNum", g_Config->threadNum, 0);
//nh.param<int32_t>("maxTaskNum", g_Config->maxTaskNum, 0);
nh.param<std::string>("server_ip", m_ip, "none");
nh.param<int32_t>("server_port", m_port, 0);
//nh.param<std::string>("tongji_ip", g_Config->tongji_ip, "none");
//nh.param<int32_t>("tongji_port", g_Config->tongji_port, 0);
nh.param<std::string>("project_path", m_folder, "none");
config.pro_path = m_folder;
nh.param<std::string>("pro_dir", config.pro_dir, "none");
nh.param<std::string>("map_cfg", config.map_cfg, "none");
nh.param<int32_t>("high_speed_interval", config.high_speed_interval, 500);
nh.param<int32_t>("low_speed_interval", config.low_speed_interval, 2000);
nh.param<int32_t>("illegal_park_interval", config.illegal_park_interval, 2000);
nh.param<int32_t>("motor_illegal_lane_interval", config.motor_illegal_lane_interval, 1000);
nh.param<int32_t>("nonmotor_illegal_lane_interval", config.nonmotor_illegal_lane_interval, 1000);
nh.param<int32_t>("retrograde_interval", config.retrograde_interval, 2000);
nh.param<float>("max_high_speed", config.max_high_speed, 80);
nh.param<float>("min_low_speed", config.min_low_speed, 10);
nh.param<float>("min_park_speed", config.min_park_speed, 1);
nh.param<int32_t>("traffic_jam_num", config.traffic_jam_num, 10);
nh.param<std::string>("forbidden_park_area", config.forbidden_park_area, "");
nh.param<std::string>("nonmotor_name_list", config.nonmotor_name_list, "");
nh.param<int32_t>("check_park_time", config.check_park_time, 30000);
nh.param<int32_t>("min_retr_speed", config.min_retr_speed, 30000);
nh.param<int32_t>("min_land_speed", config.min_land_speed, 30000);
nh.param<int32_t>("emergence_illegal_lane_interval", config.emergence_illegal_lane_interval, 30000);
nh.param<int32_t>("change_illegal_lane_interval", config.change_illegal_lane_interval, 30000);
nh.param<int32_t>("changes_illegal_lane_interval", config.changes_illegal_lane_interval, 30000);
nh.param<int32_t>("person_illegal_lane_interval", config.person_illegal_lane_interval, 30000);
#ifdef _ROS_XISHAN_
#else
config.max_high_speed *= 0.1;
config.min_low_speed *= 0.1;
config.min_park_speed *= 0.1;
config.min_retr_speed *= 0.1;
config.min_land_speed *= 0.1;
#endif
config.PacketArea();
#ifdef _ROS_XISHAN_
m_pub = nh.advertise<jfx_common_msgs::OutFusionEventObjs>("/FusionEventData", 100);
#endif
return 0;
}
#ifdef _ROS_XISHAN_
void EventsRos::TrackCallBackFunc(const jfx_common_msgs::OutFusionObjsConstPtr& msg)//接受ros发过来的消息
{
if (msg->objs.size() <= 0)
{
return;
}
TrkObjsPtr objsPtr = std::make_shared<TrkObjs>();
for (auto& item : msg->objs)
{
m_devNo = item.dev_no;
m_mecNo = item.mec_no;
TrkObj obj;
obj.dev_no = item.dev_no;
obj.mec_no = item.mec_no;
obj.join_id = item.join_id;
obj.id = item.all_id;//物体id
obj.cross_name = item.cross_name;
obj.inner_pos = item.inner_pos;
obj.is_turn = item.is_turn;
obj.laneId = item.lane;
obj.time = item.time;//时间戳
obj.prob = item.Prob;//置信度
obj.name = item.type;//类型名称,其中包括car truck bus 自行车,行人
obj.licensePlateNumber = item.plate_no;//车牌号,没有就是:NONE
//obj.vehicleColor = item.color_name;//车颜色,没有就是:NONE
obj.objH = item.obj_h;//检测出车的3D框高
obj.objW = item.obj_w;//检测出车的3D框宽
obj.objL = item.obj_l;//检测出车的3D框长
obj.nowX = item.now_x;//检测出车的3D框中心点X
obj.nowY = item.now_y;//检测出车的3D框中心点Y
obj.lat = item.lat;//车所在位置的纬度
obj.lon = item.lon;//车所在位置的经度
obj.heading = item.heading;//车运行的朝向,北为0,顺时针0-360
obj.speed = item.speed;//计算出车的速度
objsPtr->objs.emplace_back(obj);
}
objsPtr->devNo = m_devNo;
objsPtr->mecNo = m_mecNo;
m_jfx_events.PushEventInfos(objsPtr);
}
#else
void EventsRos::TrackCallBackFunc(const jfxrosperceiver::det_tracking_arrayConstPtr& msg)
{
if (msg->array.size() <= 0)
{
return;
}
TrkObjsPtr objsPtr = std::make_shared<TrkObjs>();
objsPtr->devNo = m_devNo;
objsPtr->mecNo = m_mecNo;
for (auto& item : msg->array)
{
TrkObj obj;
obj.time = item.frame;//时间戳
obj.prob = item.score;//置信度
obj.name = item.name;//类型名称,其中包括car truck bus 自行车,行人
obj.type = item.type;//类型值,基本上与上面的类型对应
obj.licensePlateNumber = item.license_plate_number;//车牌号,没有就是:NONE
obj.vehicleColor = item.color_name;//车颜色,没有就是:NONE
obj.objH = item.h;//检测出车的3D框高
obj.objW = item.w;//检测出车的3D框宽
obj.objL = item.l;//检测出车的3D框长
obj.nowX = item.x;//检测出车的3D框中心点X
obj.nowY = item.y;//检测出车的3D框中心点Y
obj.nowZ = item.z;//检测出车的3D框中心点Z
obj.lat = item.Lat;//车所在位置的纬度
obj.lon = item.Long;//车所在位置的经度
obj.heading = item.rot_y;//车运行的朝向,北为0,顺时针0-360
obj.id = item.obj_id;//物体id
obj.speed = sqrt(pow(item.v_x, 2) + pow(item.v_y, 2) + pow(item.v_z, 2));//计算出车的速度
objsPtr->objs.emplace_back(obj);
}
m_jfx_events.PushEventInfos(objsPtr);
}
#endif
int EventsRos::Start()
{
SDK_LOG(SDK_INFO, "EventsRos::Start");
m_jfx_events.SetEventsCallback([=](TrkObjsPtr& outs) {
//SendEventsCb(outs);
SendRosEvents(outs);
});
m_jfx_events.Init();
return 0;
}
void EventsRos::SendRosEvents(TrkObjsPtr& outs)
{
#ifdef _ROS_XISHAN_
jfx_common_msgs::OutFusionEventObjs eventMsgs = {};
for (auto& iter : outs->objs)
{
jfx_common_msgs::OutFusionEventObj msg = {};
msg.dev_no = iter.dev_no;
msg.mec_no = iter.mec_no;
msg.join_id = iter.join_id;
msg.all_id = iter.id;
msg.type = iter.name;
msg.plate_no = iter.licensePlateNumber;
msg.time = iter.time;
msg.Prob = iter.prob;
msg.now_x = iter.nowX;
msg.now_y = iter.nowY;
msg.speed = iter.speed;
msg.lon = iter.lon;
msg.lat = iter.lat;
msg.obj_l = iter.objL;
msg.obj_w = iter.objW;
msg.obj_h = iter.objH;
msg.heading = iter.heading;
msg.lane = iter.laneId;
msg.cross_name = iter.cross_name;
msg.inner_pos = iter.inner_pos;
msg.is_turn = iter.is_turn == 0 ? false : true;
for(auto its : iter.eventList)
{
jfx_common_msgs::OutEvent info = {};
info.event_id = its.eventId;
info.event_type = its.eventType;
info.event_status = its.eventStatus;
msg.event_list.emplace_back(info);
}
eventMsgs.objs.emplace_back(msg);
}
m_pub.publish(eventMsgs);
#endif
}
void EventsRos::SendEventsCb(TrkObjsPtr& outs)
{
std::string response;
std::stringstream ss;
jf_ajson::save_to(ss, *outs);
std::string body = std::move(ss.str());
//SDK_LOG(SDK_INFO, "[GHTTP] send traffic url=%s, objs=%s", m_Url.c_str(), body.c_str());
HttpClientCURL::post_json(m_Url, body, response);
//SDK_LOG(SDK_INFO, "post receive body=%s", response.c_str());
}
#pragma once
#include "LogBase.h"
#include "ros/ros.h"
#include "JfxEvents.h"
#define _ROS_XISHAN_
#ifdef _ROS_XISHAN_
#include "jfx_common_msgs/OutFusionObjs.h"
#include "jfx_common_msgs/OutFusionEventObjs.h"
#else
#include "jfxrosperceiver/det_tracking_array.h"
#endif
/**
* @brief ros系统和event类衔接的类,ros的发送和接受都放到这里
*/
class EventsRos
{
public:
EventsRos() {}
~EventsRos() {}
int loadConfig(ros::NodeHandle& nh);
#ifdef _ROS_XISHAN_
void TrackCallBackFunc(const jfx_common_msgs::OutFusionObjsConstPtr& msg);//接受ros发过来的消息
#else
void TrackCallBackFunc(const jfxrosperceiver::det_tracking_arrayConstPtr& msg);//接受ros发过来的消息
#endif
int Start();
void SendEventsCb(TrkObjsPtr& outs);//发送event事件的函数
void SendRosEvents(TrkObjsPtr& outs);//发送event事件的函数
JfxEvents m_jfx_events;//event处理对象
std::string m_devNo;
std::string m_mecNo;
std::string m_Url;//发送的地址
std::string m_ip;
int m_port;
std::string m_folder;//当前目录
ros::Publisher m_pub;
};
\ No newline at end of file

#include "Component.h"
#include <sys/time.h>
#include <unistd.h>
uint64_t GetCurTime()
{
struct timeval time;
gettimeofday(&time, NULL);
uint64_t seconds = time.tv_sec;
uint64_t ttt = seconds * 1000 * 1000 + time.tv_usec;
return ttt;
}
bool CheckCarLane(jf::LaneType laneType) {
switch (laneType) {
case jf::LaneType::NormalLane: // 普通车道
case jf::LaneType::EnterLane: // 入口车道
case jf::LaneType::ExitLane: // 出口车道
case jf::LaneType::ConnectLane: // 连接车道
case jf::LaneType::EmergencyLane: // 应急车道
case jf::LaneType::EmergencyStopLane: // 紧急停车道
case jf::LaneType::AcceleratingLane: // 加速车道
case jf::LaneType::DeceleratingLane: // 减速车道
case jf::LaneType::HazardLane: // 避险车道
//case jf::LaneType::JunctionLane: // 路口车道
//case jf::LaneType::UTurnLane: // 掉头车道
case jf::LaneType::BusLane: // 公交车道
case jf::LaneType::TidalLane: // 潮汐(可变) 车道
case jf::LaneType::HOVHighLoadLane: // HOV 高承载车道
return true;
default:
break;
}
return false;
}
bool CheckCarLaneAll(jf::LaneType laneType) {
switch (laneType) {
case jf::LaneType::NormalLane: // 普通车道
case jf::LaneType::EnterLane: // 入口车道
case jf::LaneType::ExitLane: // 出口车道
case jf::LaneType::ConnectLane: // 连接车道
case jf::LaneType::EmergencyLane: // 应急车道
case jf::LaneType::EmergencyStopLane: // 紧急停车道
case jf::LaneType::AcceleratingLane: // 加速车道
case jf::LaneType::DeceleratingLane: // 减速车道
case jf::LaneType::HazardLane: // 避险车道
case jf::LaneType::JunctionLane: // 路口车道
case jf::LaneType::UTurnLane: // 掉头车道
case jf::LaneType::BusLane: // 公交车道
case jf::LaneType::TidalLane: // 潮汐(可变) 车道
case jf::LaneType::HOVHighLoadLane: // HOV 高承载车道
return true;
default:
break;
}
return false;
}
\ No newline at end of file
#pragma once
#include <MapInterface.hpp>
uint64_t GetCurTime();
bool CheckCarLane(jf::LaneType laneType);//检查除了路口之外的道路类型
bool CheckCarLaneAll(jf::LaneType laneType);//机动车道路类型
/*
* SafeQueue.hpp
* Copyright (C) 2019 Alfredo Pons Menargues <apons@linucleus.com>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SAFEQUEUE_HPP_
#define SAFEQUEUE_HPP_
#include <queue>
#include <list>
#include <mutex>
#include <thread>
#include <cstdint>
#include <condition_variable>
/** A thread-safe asynchronous queue */
template <class T, class Container = std::list<T>>
class SafeQueue
{
typedef typename Container::value_type value_type;
typedef typename Container::size_type size_type;
typedef Container container_type;
public:
/*! Create safe queue. */
SafeQueue() = default;
SafeQueue (SafeQueue&& sq)
{
m_queue = std::move (sq.m_queue);
}
SafeQueue (const SafeQueue& sq)
{
std::lock_guard<std::mutex> lock (sq.m_mutex);
m_queue = sq.m_queue;
}
/*! Destroy safe queue. */
~SafeQueue()
{
std::lock_guard<std::mutex> lock (m_mutex);
}
/**
* Sets the maximum number of items in the queue. Defaults is 0: No limit
* \param[in] item An item.
*/
void set_max_num_items (unsigned int max_num_items)
{
m_max_num_items = max_num_items;
}
/**
* Pushes the item into the queue.
* \param[in] item An item.
* \return true if an item was pushed into the queue
*/
bool push(const value_type& item)
{
std::lock_guard<std::mutex> lock(m_mutex);
int ret = true;
if (m_max_num_items > 0 && m_queue.size() > m_max_num_items)
{
m_queue.pop();
ret = false;
}
m_queue.push(item);
m_condition.notify_one();
return ret;
}
/**
* Pushes the item into the queue.
* \param[in] item An item.
* \return true if an item was pushed into the queue
*/
bool push(const value_type&& item)
{
std::lock_guard<std::mutex> lock(m_mutex);
int ret = true;
if (m_max_num_items > 0 && m_queue.size() > m_max_num_items)
{
m_queue.pop();
ret = false;
}
m_queue.push(item);
m_condition.notify_one();
return ret;
}
/**
* Pushes the item into the queue.
* \param[in] item An item.
* \return true if an item was pushed into the queue
*/
bool push_ex(const value_type& item, value_type& out)
{
std::lock_guard<std::mutex> lock(m_mutex);
bool ret = true;
if (m_max_num_items > 0 && m_queue.size() > m_max_num_items)
{
//修改为队列里大于这个值,pop出老的,push新的
out = m_queue.front();
m_queue.pop();
ret = false;
}
//return false;
m_queue.push(item);
m_condition.notify_one();
return ret;
}
/**
* Pushes the item into the queue.
* \param[in] item An item.
* \return true if an item was pushed into the queue
*/
bool push_ex(const value_type&& item, value_type& out)
{
std::lock_guard<std::mutex> lock(m_mutex);
bool ret = true;
if (m_max_num_items > 0 && m_queue.size() > m_max_num_items)
{
//修改为队列里大于这个值,pop出老的,push新的
out = m_queue.front();
m_queue.pop();
ret = false;
}
//return false;
m_queue.push(item);
m_condition.notify_one();
return ret;
}
/**
* Pops item from the queue. If queue is empty, this function blocks until item becomes available.
* \param[out] item The item.
*/
void pop (value_type& item)
{
std::unique_lock<std::mutex> lock (m_mutex);
m_condition.wait (lock, [this]() // Lambda funct
{
return !m_queue.empty();
});
item = m_queue.front();
m_queue.pop();
}
/**
* Pops item from the queue using the contained type's move assignment operator, if it has one..
* This method is identical to the pop() method if that type has no move assignment operator.
* If queue is empty, this function blocks until item becomes available.
* \param[out] item The item.
*/
void move_pop (value_type& item)
{
std::unique_lock<std::mutex> lock (m_mutex);
m_condition.wait (lock, [this]() // Lambda funct
{
return !m_queue.empty();
});
item = std::move (m_queue.front());
m_queue.pop();
}
/**
* Tries to pop item from the queue.
* \param[out] item The item.
* \return False is returned if no item is available.
*/
bool try_pop (value_type& item)
{
std::unique_lock<std::mutex> lock (m_mutex);
if (m_queue.empty())
return false;
item = m_queue.front();
m_queue.pop();
return true;
}
/**
* Tries to pop item from the queue using the contained type's move assignment operator, if it has one..
* This method is identical to the try_pop() method if that type has no move assignment operator.
* \param[out] item The item.
* \return False is returned if no item is available.
*/
bool try_move_pop (value_type& item)
{
std::unique_lock<std::mutex> lock (m_mutex);
if (m_queue.empty())
return false;
item = std::move (m_queue.front());
m_queue.pop();
return true;
}
/**
* Pops item from the queue. If the queue is empty, blocks for timeout microseconds, or until item becomes available.
* \param[out] t An item.
* \param[in] timeout The number of microseconds to wait.
* \return true if get an item from the queue, false if no item is received before the timeout.
*/
bool timeout_pop (value_type& item, std::uint64_t timeout)
{
std::unique_lock<std::mutex> lock (m_mutex);
while(m_queue.empty())
{
if (timeout == 0)
return false;
if (m_condition.wait_for (lock, std::chrono::milliseconds (timeout)) == std::cv_status::timeout)
return false;
}
item = m_queue.front();
m_queue.pop();
return true;
}
/**
* Pops item from the queue using the contained type's move assignment operator, if it has one..
* If the queue is empty, blocks for timeout microseconds, or until item becomes available.
* This method is identical to the try_pop() method if that type has no move assignment operator.
* \param[out] t An item.
* \param[in] timeout The number of microseconds to wait.
* \return true if get an item from the queue, false if no item is received before the timeout.
*/
bool timeout_move_pop (value_type& item, std::uint64_t timeout)
{
std::unique_lock<std::mutex> lock (m_mutex);
if (m_queue.empty())
{
if (timeout == 0)
return false;
if (m_condition.wait_for (lock, std::chrono::microseconds (timeout)) == std::cv_status::timeout)
return false;
}
item = std::move (m_queue.front());
m_queue.pop();
return true;
}
/**
* Gets the number of items in the queue.
* \return Number of items in the queue.
*/
size_type size() const
{
std::lock_guard<std::mutex> lock (m_mutex);
return m_queue.size();
}
/**
* Check if the queue is empty.
* \return true if queue is empty.
*/
bool empty() const
{
std::lock_guard<std::mutex> lock (m_mutex);
return m_queue.empty();
}
/**
* Swaps the contents.
* \param[out] sq The SafeQueue to swap with 'this'.
*/
void swap (SafeQueue& sq)
{
if (this != &sq)
{
std::lock_guard<std::mutex> lock1 (m_mutex);
std::lock_guard<std::mutex> lock2 (sq.m_mutex);
m_queue.swap (sq.m_queue);
if (!m_queue.empty())
m_condition.notify_all();
if (!sq.m_queue.empty())
sq.m_condition.notify_all();
}
}
/*! The copy assignment operator */
SafeQueue& operator= (const SafeQueue& sq)
{
if (this != &sq)
{
std::lock_guard<std::mutex> lock1 (m_mutex);
std::lock_guard<std::mutex> lock2 (sq.m_mutex);
std::queue<T, Container> temp {sq.m_queue};
m_queue.swap (temp);
if (!m_queue.empty())
m_condition.notify_all();
}
return *this;
}
/*! The move assignment operator */
SafeQueue& operator= (SafeQueue && sq)
{
std::lock_guard<std::mutex> lock (m_mutex);
m_queue = std::move (sq.m_queue);
if (!m_queue.empty()) m_condition.notify_all();
return *this;
}
private:
std::queue<T, Container> m_queue;
mutable std::mutex m_mutex;
std::condition_variable m_condition;
unsigned int m_max_num_items = 0;
};
/*! Swaps the contents of two SafeQueue objects. */
template <class T, class Container>
void swap (SafeQueue<T, Container>& q1, SafeQueue<T, Container>& q2)
{
q1.swap (q2);
}
#endif /* SAFEQUEUE_HPP_ */
/*
Copyright (C) 2016 - 2019, oscar. rights reserved.
File Name: Singleton.h
description: 单例类的通用头文件
Change History:
Date Version Changed By Changes
2018/4/23 1.0.0.1 oscar Create
*/
#ifndef _SINGLETON_H_
#define _SINGLETON_H_
#include <stdlib.h>
#include <mutex>
/**
* @brief 实现单实例
*
*/
template <typename T>
class Singleton
{
public:
static T *GetInstance()
{
if (0 == s_ins)
{
std::unique_lock<std::mutex> lck(s_mtx);
if (0 == s_ins)
{
s_ins = new (T)();
atexit(Destory);
}
}
return s_ins;
}
Singleton(){}
~Singleton(){}
private:
static void Destory()
{
delete s_ins;
s_ins = 0;
}
private:
static T* volatile s_ins;
static std::mutex s_mtx;
};
template <typename T>
T* volatile Singleton<T>::s_ins = 0;
template <typename T>
std::mutex Singleton<T>::s_mtx;
#endif
This diff is collapsed.
//
// Created by youle on 20-10-26.
//
#include "http_client_curl.h"
//
// Created by youle on 20-10-26.
//
#ifndef EDGE_SERVER_HTTP_CLIENT_CURL_H
#define EDGE_SERVER_HTTP_CLIENT_CURL_H
#define DISABLE_EXPECT
#include <curl/curl.h>
#include <curl/easy.h>
#include <string>
#include <fstream>
#include <string.h>
#include <sys/stat.h>
#include "LogBase.h"
class HttpClientCURL {
public:
struct callback_memory {
int sz = 0;
char* m = nullptr;
~callback_memory(){if(m)free(m);}
};
static int callbackFunc(void *ptr, size_t size, size_t nmemb, void *userp){
callback_memory* memp = static_cast<callback_memory*>(userp);
int res_size = size * nmemb;
memp->m = static_cast<char*>(realloc(memp->m, memp->sz + res_size + 1));
memcpy(memp->m + memp->sz, ptr, res_size);
memp->sz += res_size;
return res_size;
};
static int post_json(
const std::string& url,
const std::string& data,
std::string& response
){
CURLcode res;
CURL* curl = curl_easy_init();
if(!curl){
return CURLE_FAILED_INIT;
}
// form
struct curl_slist* headerlist = nullptr;
headerlist = curl_slist_append(headerlist, "Content-Type:application/json;charset=UTF-8");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.length());
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 1);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 0);
callback_memory callback;
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&callback);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callbackFunc);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); //支持服务器跳转
curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L); // enable TCP keep-alive for this transfer
// perform
res = curl_easy_perform(curl);
// clean
curl_easy_cleanup(curl);
curl_slist_free_all(headerlist);
if(res == CURLE_OK){
response = std::string(callback.m, callback.sz);
}else {
SDK_LOG(SDK_INFO, "---post_json faild, res : %d", res);
curl_easy_strerror(res);
response = "{}";
}
return res;
}
static int post_form_data(
const std::string& url,
const std::string& file_path,
const std::string& data,
std::string& response
){
SDK_LOG(SDK_INFO, "---------post_form_data--------");
SDK_LOG(SDK_INFO, "url=%s", url.c_str());
SDK_LOG(SDK_INFO, "file=%s", file_path.c_str());
SDK_LOG(SDK_INFO, "data=%s", data.c_str());
SDK_LOG(SDK_INFO, "---------post_form_data--------");
CURLcode res;
CURL* curl = curl_easy_init();
if(!curl){
return CURLE_FAILED_INIT;
}
// form
struct curl_httppost* formpost = nullptr;
struct curl_httppost* lastptr = nullptr;
curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "file",
CURLFORM_FILE, file_path.c_str(),
CURLFORM_END);
curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "data",
CURLFORM_COPYCONTENTS, data.c_str(),
CURLFORM_END);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
struct curl_slist* headerlist = nullptr;
headerlist = curl_slist_append(headerlist, "Content-Type:multipart/form-data");
//在使用curl做POST的时候, 当要POST的数据大于1024字节的时候, curl并不会直接就发起POST请求, 而是会分为2个步骤:
// - 发送一个请求, 包含一个Expect:100-continue, 询问Server使用愿意接受数据
// - 接收到Server返回的100-continue应答以后, 才把数据POST给Server
headerlist = curl_slist_append(headerlist, "Expect:");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
callback_memory callback;
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&callback);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callbackFunc);
// perform
res = curl_easy_perform(curl);
// clean
curl_easy_cleanup(curl);
curl_formfree(formpost);
curl_slist_free_all(headerlist);
if(res == CURLE_OK){
SDK_LOG(SDK_INFO, "post_form_data ok");
response = std::string(callback.m,callback.sz);
}else {
SDK_LOG(SDK_INFO, "post_form_data faild, res : %d", res);
curl_easy_strerror(res);
response = "{}";
}
return res;
}
};
#endif //EDGE_SERVER_HTTP_CLIENT_CURL_H
This diff is collapsed.
#pragma once
#include "EventInfo.h"
#include "SafeQueue.hpp"
#include <functional>
#include <thread>
#include <mutex>
#include "MapInterface.hpp"
#include "config.h"
enum class TrackResultType : int32_t //检测结果上报时的类型,和需求对应
{
TRACK_TYPE_NONE = 0,//状态正常
TRACK_HIGH_SPEED = 1,//高速行驶
TRACK_LOW_SPEED = 2,//低速行驶
TRACK_ILLIGAL_PARK = 3,//机动车道非法停车
TRACK_ILLIGAL_AREA_PARK = 4,//非法区域停车
TRACK_MOTOR_ILLEGAL_LANE = 5,//机动车占用非机动车道
TRACK_NONMOTOR_ILLEGAL_LANE = 6,//非机动车占用机动车道
TRACK_RETROGRADE_TYPE = 7,//逆行
TRACK_CROSS_ILLEGAL_TYPE = 8,//异常变道,瞬时事件
TRACK_CROSS_AGAIN_TYPE = 9,//连续变道,瞬时事件
TRACK_EMERGENCY_PARK_TYPE = 10,//应急车道停车
TRACK_PERSON_ILLEGAL_TYPE = 11,//行人闯入
TRACK_TRAFFIC_JAM_TYPE = 12,//交通拥堵
TRACK_DROP_ITEM_TYPE = 13,//道路遗撒
TRACK_ROAD_WORK_TYPE = 14,//道路施工
TRACK_LAND_LIMIT_TYPE = 15,//排队超限
TRACK_TYPE_NUM
};
enum class EventStatus //最终事件产生的时的状态
{
Event_Status_None = -1,//无状态
Event_Status_Begin = 0,//状态开始
Event_Status_Continue = 1,//状态持续
Event_Status_End = 2,//状态结束
Event_Status_disappear = 3//离开跟踪区域
};
enum class track_index_type : int32_t //需要监测的类型,只跟踪几种,速度监测,占道监测,逆行监测
{
SPEED_TYPE = 0,//速度监测
STOP_TYPE = 1,//停车监测
LANE_TYPE = 2,//车道监测,这个是给机动车和非机动车占道的监测
RETROGRADE_TYPE = 3,//逆行监测
LAND_CHANGE_TYPE = 4,//异常变道监测
LAND_CHANGE_AGAIN_TYPE = 5,//车辆连续变道
LAND_EMERGENCY_TYPE = 6,//应急车道检测
TRACK_EVENT_NUM
};
enum class track_event_type : int32_t //监测三种类型中可能存在的几种类型,速度监测包括高速,低速,停车,占道监测包括占非机动车道,占机动车道,逆行监测只包括逆行
{
NONE_TYPE = 0,//不检测
HIGH_SPEED_TYPE = 1,//高速度检测
LOW_SPEED_TYPE = 2,//低速度检测
PARK_SPEED_TYPE = 3,//停车检测
MOTOR_ILLEGAL_LANE_TYPE = 4,//机动车占用非机动车道
NONMOTOR_ILLEGAL_LANE_TYPE = 5,//非机动车占用机动车道
MOTOR_RETROGRADE_TYPE = 6,//检测逆行行驶
PERSON_ILLEGAL_TYPE = 7,//行人闯入事件
EMERGENCY_ILLEGAL_TYPE = 8,//应急车道检测
CHANGE_LAND_TYPE = 9,//异常变道监测
CHANGE_LAND_AGAIN_TYPE = 10,//车辆连续变道
};
enum class track_state : int32_t //监测时的状态
{
STATE_NONE = 0,//无状态,没有监测
STATE_BEGIN = 1,//开始监测
STATE_END = 2,//监测完成
STATE_CONFIRM = 3, //确定状态
};
struct DetectInfo
{
track_state state = track_state::STATE_NONE;//监测状态
track_event_type eventType = track_event_type::NONE_TYPE;//监测可能的事件类型,对应track_event_type
//TrackResultType eventResult = TrackResultType::TRACK_TYPE_NONE;//监测最终结果,对应TrackResultType
//EventStatus eventStatus = EventStatus::Event_Status_None;//记录最终事件的状态。
//int isTrafficJam = 0;//是否是拥堵状态,0是否,1是拥堵
uint64_t startT = 0;//触发监测时间
uint64_t detectT = 0;//检测到的时间
// uint64_t totelT = 0;//累计时间
// int interval = 0;//检测多长时间认为非法,毫秒,如果为0就使用配置里的时间间隔,否则用这个时间
//int nLaneCnt = 0;//车道总数
int curLaneNum = 0;//当前车道序号
int lastLaneNum = 0;//上一个车道序号
int changeLand = 0;//变道类型,1是左,2是右
jf::LaneType nOutLaneType = jf::LaneType::NotInvestigated;//车道类型
double lat = 0.0f;
double lon = 0.0f;
};
struct ObjInfoAll
{
TrkObj obj;
int num = 0;//数据帧号
int isInMap = -1;//是否在地图上
uint64_t appearT = 0;//记录出现的时间
std::vector<int> landCounts;//走过的车道线总数,最上面的是当前车道线总数
std::vector<int> landTypes;//走过的车道类型,最上面的是当前类型
std::vector<int> landNum;//走过的车道线位置。
std::vector<long> roadIds;//走过的车道编号。
int speedLimit = 0;//车道最高限速值,单位是千米每小时
double landAngle = 0.0;//所在车道,车应该的朝向角度,北为0,顺时针旋转360,0-360
jf::Point ptOutFoot;//车道中心线做垂线的点
jf::EdgeCrossType nOutLeftEdgeCrossType;//左车道边缘线的跨越属性,具体看头文件枚举
jf::EdgeCrossType nOutRightEdgeCrossType;//右车道边缘线的跨越属性,具体看头文件枚举
long lastRoadId = 0;//上一帧车道id
int lastLandCount = 0;//上一帧的车道线总数
int lastLandType = 0;//上一帧的车道类型
int lastLandNum = 0;//上一帧的车道位置
std::vector<int> eventList;//要发送的事件
DetectInfo events[static_cast<int32_t>(track_index_type::TRACK_EVENT_NUM)];//添加检测的种类,
};
//道路信息
struct RoadInfo
{
long roadId;
int landCount;
int landType;
int landNum;
jf::EdgeCrossType nOutLeftEdgeCrossType;//左车道边缘线的跨越属性,具体看头文件枚举
jf::EdgeCrossType nOutRightEdgeCrossType;//右车道边缘线的跨越属性,具体看头文件枚举
int nOutSpeedLimit;
double dOutLaneAngle;
int isNextCross = 0;//前方是否为路口
int countNext = 0;//前面的路计算了几个
std::vector<long> vctlOutPreRoadId;
std::vector<long> vctlOutNxtRoadId;
long crossId = 0;//路口Id
};
typedef void (SendEventProcess)(TrkObjsPtr& outs);
typedef std::function<SendEventProcess> SendEventProcessCallback;
struct CrossInfo
{
std::vector<long> roads;//等待路口的所有raodid
int num = 0;//记录车辆个数
int crossNum = 0;//路口第一个道路上的数量
};
/**
* @brief 事件处理类,里面的逻辑和ros框架无关,可以独立出来。
*/
class JfxEvents
{
public:
JfxEvents();
~JfxEvents();
void Init();
void PushEventInfos(TrkObjsPtr& inputs);
void SetEventsCallback(SendEventProcessCallback cb);
void ThreadEventProcess();
void ThreadEventSendProcess();
void CalculateMap(ObjInfoAll& objAll);
void DetectEvents(TrkObjsPtr& objsPtr);
void ProcessSendEvents(TrkObjsPtr& objsPtr);
int GetRoadIdLandNum(long roadId, int landNum, std::map<long, std::map<int, std::vector< int64_t> > >& objs);
void FreshCorssRoad();
int GetTotelNum(long roadId, int landNum, std::map<long, std::map<int, std::vector< int64_t> > >& objs, std::map<long, std::map<int, RoadInfo> >& roadInfo, int& totelNum);
void SetCorssRoadId(long roadId, int landNum, long crossId, std::vector<long>& roads);
int CheckTrafficJam(long crossId, long roadId, int landNum, int& num, int& crossNum);
public:
SafeQueue<TrkObjsPtr> m_Queue;
EventsConfig m_cfg;
int m_frameNum = 0;
std::unique_ptr<jf::MapInterface> m_OfflineMap;
std::mutex m_sendMtx;
SendEventProcessCallback m_sendCb = nullptr;
bool m_isEventRun = false;//记录是否在运行
std::thread m_eventThread;//运行事件线程
SafeQueue<TrkObjsPtr> m_sendQueue;
bool m_isSendRun = false;//记录是否在运行
std::thread m_sendThread;//运行事件线程
std::map<int64_t, ObjInfoAll> m_frameObjs;//记录处理的所有物体
std::map<long, std::map<int, RoadInfo> > m_roadInfos;//道路信息
std::map<long, std::map<int, CrossInfo > > m_crossRoads;//路口道路信息
std::map<int64_t, std::vector<eventInfo> > m_lastEvents;//记录上一帧的所有发送的事件
std::map<uint64_t, std::map<int, uint64_t> > printfInfo;//为了不反复打印,记录打印过的信息
int m_eventFrequence[static_cast<int32_t>(TrackResultType::TRACK_TYPE_NUM)];
int m_eventTotelCount = 0;
int m_eventCount = 0;//事件触发的累计数
};
\ No newline at end of file

#include "config.h"
#include "LogBase.h"
void Split(std::string& input, std::string separator, std::vector<std::string>& out)
{
int begin = 0;
while (begin < input.size())
{
auto idx = input.find_first_of(separator.c_str(), begin);
if (idx == std::string::npos)
idx = input.size();
std::string value = input.substr(begin, idx - begin);
out.emplace_back(value);
begin = idx + 1;
}
}
void EventsConfig::PacketArea()
{
int start = 0;
while (start < forbidden_park_area.size())
{
auto index = forbidden_park_area.find_first_of(';', start);
if (index == std::string::npos)
index = forbidden_park_area.size();
std::string subs = forbidden_park_area.substr(start, index - start);
int begin = 0;
std::vector<double> areas;
while (begin < subs.size())
{
auto idx = subs.find_first_of(',', begin);
if (idx == std::string::npos)
idx = subs.size();
std::string value = subs.substr(begin, idx - begin);
areas.push_back(atof(value.c_str()));
begin = idx + 1;
}
if (areas.size() == 4)
{
ForbiddenArea info;
info.minLat = areas[0];
info.maxLat = areas[1];
info.minLon = areas[2];
info.maxLon = areas[3];
forbiddenAreas.emplace_back(info);
}
start = index + 1;
}
Split(nonmotor_name_list, ";", nonmotorLists);
//max_high_speed *= 0.1;
//min_low_speed *= 0.1;
//min_park_speed *= 0.1;
//min_retr_speed *= 0.1;
//min_land_speed *= 0.1;
//打印参数
SDK_LOG(SDK_INFO, "high_speed_interval = %d", high_speed_interval);
SDK_LOG(SDK_INFO, "low_speed_interval = %d", low_speed_interval);
SDK_LOG(SDK_INFO, "illegal_park_interval = %d", illegal_park_interval);
SDK_LOG(SDK_INFO, "motor_illegal_lane_interval = %d", motor_illegal_lane_interval);
SDK_LOG(SDK_INFO, "nonmotor_illegal_lane_interval = %d", nonmotor_illegal_lane_interval);
SDK_LOG(SDK_INFO, "retrograde_interval = %d", retrograde_interval);
SDK_LOG(SDK_INFO, "max_high_speed = %f", max_high_speed);
SDK_LOG(SDK_INFO, "min_low_speed = %f", min_low_speed);
SDK_LOG(SDK_INFO, "min_park_speed = %f", min_park_speed);
SDK_LOG(SDK_INFO, "traffic_jam_num = %d", traffic_jam_num);
for (auto iter : nonmotorLists)
{
SDK_LOG(SDK_INFO, "load nonmotor name = %s", iter.c_str());
}
}
int EventsConfig::IsInArea(double& lat, double& lon)
{
//检查是否是禁止停车区域
for (auto iter : forbiddenAreas)
{
if (lat > iter.minLat && lat < iter.maxLat &&
lon > iter.minLon && lon < iter.maxLon)
{
return 1;
}
}
return 0;
}
int EventsConfig::IsMotor(std::string& name)
{
for (auto iter : nonmotorLists)
{
if (name == iter)
return 0;
}
return 1;
}
\ No newline at end of file
#pragma once
#include <string>
#include <vector>
struct ForbiddenArea
{
double minLat;
double maxLat;
double minLon;
double maxLon;
};
/**
* @brief 配置信息结构
*/
struct EventsConfig
{
bool daemon;
int32_t threadNum;
int32_t maxTaskNum;
std::string edge_addr;
std::string devNo;
std::string mecNo;
std::string server_ip;
int32_t server_port;
std::string tongji_ip;
int32_t tongji_port;
std::string pro_path;
std::string pro_dir;
std::string map_cfg;
int32_t high_speed_interval;//检测高速行驶的时间间隔,毫秒
int32_t low_speed_interval;//检测低速行驶的时间间隔,毫秒
int32_t illegal_park_interval;//检测非法停车的时间间隔,毫秒
int32_t motor_illegal_lane_interval;//检测机动车占用非机动车的时间间隔,毫秒
int32_t nonmotor_illegal_lane_interval;//检测非机动车占用机动车的时间间隔,毫秒
int32_t retrograde_interval;//检测逆行行驶的时间间隔,毫秒
float max_high_speed;//最高速的值,大于这个值开始检测
float min_low_speed;//最小速度值,小于这个值开始检测
float min_park_speed;//最小停车值,小于这个值开始检测
int32_t traffic_jam_num;//检测多少车处于慢速和停车状态的数量,大于这个值就认为是堵车
std::string forbidden_park_area;//禁止停车区域,(minLat,maxLat,minLon,maxLon;....)
std::string nonmotor_name_list;//非机动车所有类型列表
int32_t check_park_time;//停车之后多长时间认为是非法停车
int min_retr_speed;//逆行检查最小速度
int min_land_speed;//车道检测的最小速度
int emergence_illegal_lane_interval;//应急车道检测时间
int change_illegal_lane_interval;//异常变道检测时间
int changes_illegal_lane_interval;//连续变道检测时间
int person_illegal_lane_interval;//行人闯入检测时间
std::vector<ForbiddenArea> forbiddenAreas;
std::vector<std::string> nonmotorLists;
void PacketArea();
int IsInArea(double& lat, double& lon);
int IsMotor(std::string& name);
};
\ No newline at end of file

#include <glog/logging.h>
#include<sys/time.h>
#include <stdarg.h>
#include <unistd.h>
#include "LogBase.h"
#include "ros/ros.h"
#include <signal.h>
#include <sys/resource.h>
#include "EventsRos.h"
#include <iostream>
#include <string>
#include <memory>
#include "EventInfo.h"
#define LOG_BUFF_LEN 102400
#ifdef _WIN32
__declspec(thread) char g_timeStr[1024] = {};
__declspec(thread) char g_logStr[LOG_BUFF_LEN] = {};
#else
thread_local char g_timeStr[1024] = {};
thread_local char g_logStr[LOG_BUFF_LEN] = {};
#endif
int AddLogFileSys(const char* file, int& fileIdx)
{
return 0;
}
char* GetTimeSys()
{
#if defined(__ANDROID__) || defined(__linux__)
time_t tt = time(NULL);
struct tm* ptr;
ptr = localtime(&tt);
// printf("time: %d \n", tt);
char str[80];
strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", ptr);
//2018-09-19 16:01:37.517
struct timeval tmv;
gettimeofday(&tmv, NULL);
// char buf[128] = {0};
sprintf(g_timeStr, "%s.%03d", str, (int)(tmv.tv_usec / 1000));
return (char*)g_timeStr;
#elif _WIN32
char date[64] = { 0 };
struct timeb tb;
ftime(&tb);
std::tm now = { 0 };
//gmtime_s(&now, &tb.time);
localtime_s(&now, &tb.time);
sprintf_s(g_timeStr, sizeof(g_timeStr), "%04d-%02d-%02d %02d:%02d:%02d.%03d",
now.tm_year + 1900, now.tm_mon + 1, now.tm_mday,
now.tm_hour, now.tm_min, now.tm_sec,
tb.millitm);
return g_timeStr;
#endif
}
int PrintSys(int fileIdx, int logLevel, const char* format, ...)
{
memset(g_logStr, 0, sizeof(g_logStr));
va_list argList;
va_start(argList, format);
#ifdef _WIN32
vsprintf_s(g_logStr, format, argList);
#else
int ret = vsprintf(g_logStr, format, argList);
if (ret < 0)
{
exit(0);
}
#endif
va_end(argList);
//return LogSystem::GetInstance()->Print(fileIdx, logLevel, g_logStr);
if(logLevel == SDK_INFO)
LOG(INFO) << g_logStr;
else if(logLevel == SDK_DEBUG)
LOG(WARNING) << g_logStr;
else if (logLevel == SDK_ERROR)
LOG(ERROR) << g_logStr;
else
LOG(FATAL) << g_logStr;
return 0;
}
void LimitOpenFile() {
struct rlimit limit = { 0 };
if (getrlimit(RLIMIT_FSIZE, &limit) != 0) {
return;
}
limit.rlim_cur = 10240000;
if (0 != setrlimit(RLIMIT_FSIZE, &limit)) {
}
if (getrlimit(RLIMIT_FSIZE, &limit) != 0) {
return;
}
}
void signalHandler(int signum) {
//ROS_INFO("Interrupt signal %d received", signum);
// 清理并关闭
// 终止程序
// g_Run = false;
exit(signum);
}
INIT_SDK_LOG("jfx_event")
SDKLogBase g_log;
int main(int argc, char** argv)
{
// 注册信号 SIGINT 和信号处理程序
signal(SIGINT, signalHandler);
LimitOpenFile();
google::InitGoogleLogging(argv[0]);
FLAGS_stderrthreshold = google::INFO; //输出到stderr的限值,默认为2(ERROR),默认ERORR以下的信息(INFO、WARNING)不打印到终端。
FLAGS_max_log_size = 500; //设置最大日志文件大小(以MB为单位)。
FLAGS_logbufsecs = 0; //设置可以缓冲日志的最大秒数,0指实时输出。
FLAGS_alsologtostderr = true; //是否将日志输出到文件和stderr,如果:true,忽略FLAGS_stderrthreshold的限制,所有信息打印到终端。
FLAGS_log_prefix = true; //设置日志前缀是否应该添加到每行输出。
FLAGS_log_dir = "log";
g_log.AddLogFile = AddLogFileSys;
g_log.GetTime = GetTimeSys;
g_log.Print = PrintSys;
INIT_DEF_LOG_HANDLE(&g_log, nullptr);
SDK_LOG(SDK_INFO, "main function");
ros::init(argc, argv, "jfx_events");
ros::NodeHandle nh("~");
EventsRos jfx_ros;
jfx_ros.loadConfig(nh);
jfx_ros.Start();
//std::shared_ptr<int> foo = std::make_shared<int>(10);
#ifdef _ROS_XISHAN_
ros::Subscriber track_sub = nh.subscribe<jfx_common_msgs::OutFusionObjs>("/FusionData", 1000, &EventsRos::TrackCallBackFunc, &jfx_ros);
#else
ros::Subscriber track_sub = nh.subscribe<jfxrosperceiver::det_tracking_array>("/tracking_res", 1000, &EventsRos::TrackCallBackFunc, &jfx_ros);
#endif
track_sub.getNumPublishers();
ros::spin();
return 0;
}
\ No newline at end of file
This diff is collapsed.
#pragma once
#include <cstdint>
#include <string>
#include <memory>
#include "ajson_c.hpp"
typedef struct _EventInfo {
int32_t eventId;//事件唯一id,为了分清哪个事件
int32_t eventType; // 由于一辆车同时可能有多个违章,所以需要加入事件类型列表,参考TrackResultType类型
int32_t eventStatus;//事件状态,包括开始,持续,结束,消失
}eventInfo;
AJSON(eventInfo,
eventId,
eventType,
eventStatus
)
typedef struct _TrkObj {
std::string dev_no;
std::string mec_no;
uint64_t join_id = 0;
std::string cross_name;
std::string inner_pos;
int32_t is_turn = 0;
int32_t laneId = 0;
int64_t id = 0; // 节点目标id
std::string name; // 目标类型
int32_t type;
double prob = 0.0; // 可信度
uint64_t time = 0; // 时间戳 单位毫秒
double nowX = 0.0; //相对设备 位置 x
double nowY = 0.0; //相对设备 位置 y
double nowZ = 0.0; //相对设备 位置 z
double lon = 0.0; // 经度
double lat = 0.0; // 纬度
double objL = 0.0; //
double objW = 0.0; //
double objH = 0.0; //
double speed = 0.0; // 速度
double heading = 0.0; // 航向角
std::string licensePlateNumber; //车牌号
// std::string vehicleName; //车类型名
std::string vehicleColor; // 车颜色
std::vector<eventInfo> eventList; // 由于一辆车同时可能有多个违章,所以需要加入事件类型列表,参考TrackResultType类型
} TrkObj;
using TrkObjPtr = std::shared_ptr<TrkObj>;
AJSON(TrkObj,
dev_no,
mec_no,
join_id,
cross_name,
inner_pos,
is_turn,
laneId,
id,
name,
type,
time,
prob,
nowX,
nowY,
nowZ,
lon,
lat,
objL,
objW,
objH,
speed,
heading,
licensePlateNumber,
// vehicleName,
vehicleColor,
eventList
)
typedef struct _TrkObjs {
std::string devNo; // 设备相机id
std::string mecNo; // MecNo 工控机id
std::vector<TrkObj> objs;
}TrkObjs;
using TrkObjsPtr = std::shared_ptr<TrkObjs>;
AJSON(TrkObjs,
devNo,
mecNo,
objs
)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment