|
@@ -371,7 +371,7 @@ void SPAServer::compareDeviceAlgorithmInfo(const std::vector<DeviceInfo>& vecNew
|
|
|
/**
|
|
|
* @brief 从Redis获取数据线程函数,这个是摄像机线程
|
|
|
* 一个设备一个线程,这个线程的相关变量只在这个线程中使用
|
|
|
- *
|
|
|
+ * (注意,这个函数未被使用,不从这里获取Redis数据)
|
|
|
* @param info
|
|
|
*/
|
|
|
void SPAServer::threadFromRedis(const CameraThreadInfo& info)
|
|
@@ -773,12 +773,11 @@ void SPAServer::threadRoomCamera()
|
|
|
/* 取出每个房间的所有算法,int是RoomID,string是Action */
|
|
|
// std::multimap<int, std::string> mapCameraActionID;
|
|
|
m_mutexRunRAI.lock();
|
|
|
-
|
|
|
+ m_mutexRunAI.lock();
|
|
|
/* 先清理已经退出的线程所用到的Action或者RoomAction */
|
|
|
m_runListRoomActionInfo.clearStopRoomAction();
|
|
|
m_runListActionInfo.clearStopAction();
|
|
|
|
|
|
- m_mutexRunActionInfo.lock();
|
|
|
/* 将算法信息加入到不同的列表中
|
|
|
* 需要多个摄像机配合的加入到m_runListRoomActionInfo列表
|
|
|
* 不需要多个摄像机配合的加入到m_runListActionInfo列表
|
|
@@ -795,7 +794,7 @@ void SPAServer::threadRoomCamera()
|
|
|
}
|
|
|
}
|
|
|
m_mutexActionInfo.unlock();
|
|
|
- /* 这个容器只用于多个摄像机融合的算法,一个房间的一个算法是一个线程 */
|
|
|
+ /* 这个容器只用于多个摄像机融合的算法,一个功能是一个线程 */
|
|
|
for(const auto& it0 : m_runListRoomActionInfo.getData())
|
|
|
{
|
|
|
/* 人员在岗识别 */
|
|
@@ -815,9 +814,14 @@ void SPAServer::threadRoomCamera()
|
|
|
SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 区域人员检测", it0->RoomID);
|
|
|
if(it0->RunState == RunTimeState::RUN_STATE_INIT)
|
|
|
{
|
|
|
- CPPTP.add_task(&SPAServer::threadActPersonNumber, this, it0);
|
|
|
+ CPPTP.add_task(&SPAServer::threadActRegionalPersonnelDetection, this, it0);
|
|
|
}
|
|
|
}
|
|
|
+ /* 非法入侵 */
|
|
|
+ else if( it0->ActionID == ActIllegalInvasion)
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
}
|
|
|
/* 这个容器用于不关联的算法信息,每个设备上的每个算法是一个线程
|
|
|
* ActionInfo.RunState = RUN_STATE_INIT ,就是新增的算法,需要创建新的线程 */
|
|
@@ -827,9 +831,10 @@ void SPAServer::threadRoomCamera()
|
|
|
if (it0->ActionID == ActContraband)
|
|
|
{
|
|
|
SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 违禁品检测", it0->RoomID);
|
|
|
+ it0->strActionName = "违禁品检测";
|
|
|
if(it0->RunState == RunTimeState::RUN_STATE_INIT)
|
|
|
{
|
|
|
- CPPTP.add_task(&SPAServer::threadActContraband, this, it0);
|
|
|
+ CPPTP.add_task(&SPAServer::threadActNormal, this, it0);
|
|
|
}
|
|
|
}
|
|
|
/* 非法入侵检测,这个也不需要摄像机融合 */
|
|
@@ -844,7 +849,10 @@ void SPAServer::threadRoomCamera()
|
|
|
}
|
|
|
}
|
|
|
m_mutexRunRAI.unlock();
|
|
|
- m_mutexRunActionInfo.unlock();
|
|
|
+ m_mutexRunAI.unlock();
|
|
|
+
|
|
|
+ /* 休眠n秒,默认应该是300秒 */
|
|
|
+ std::this_thread::sleep_for(std::chrono::seconds(g_config.CheckSet));
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -896,7 +904,7 @@ bool SPAServer::updateRoomActionCameraCount(std::shared_ptr<RoomActionInfo> pRAI
|
|
|
bool SPAServer::updateActionCameraID(std::shared_ptr<ActionInfo> pInfo)
|
|
|
{
|
|
|
pInfo->CameraID = -1;
|
|
|
- std::lock_guard<std::mutex> look(m_mutexRunActionInfo);
|
|
|
+ std::lock_guard<std::mutex> look(m_mutexRunAI);
|
|
|
for(auto& it : m_runListActionInfo.getData())
|
|
|
{
|
|
|
if(it->isEqualBaseInfo(*pInfo))
|
|
@@ -911,7 +919,7 @@ bool SPAServer::updateActionCameraID(std::shared_ptr<ActionInfo> pInfo)
|
|
|
/* 设置线程状态 */
|
|
|
void SPAServer::setThreadState(std::shared_ptr<ActionInfo> pInfo, RunTimeState state)
|
|
|
{
|
|
|
- std::lock_guard<std::mutex> look(m_mutexRunActionInfo);
|
|
|
+ std::lock_guard<std::mutex> look(m_mutexRunAI);
|
|
|
for(auto& it : m_runListActionInfo.getData())
|
|
|
{
|
|
|
if(it->isEqualBaseInfo(*pInfo))
|
|
@@ -922,6 +930,20 @@ void SPAServer::setThreadState(std::shared_ptr<ActionInfo> pInfo, RunTimeState s
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/* 设置线程状态 */
|
|
|
+void SPAServer::setThreadState(std::shared_ptr<RoomActionInfo> pInfo, RunTimeState state)
|
|
|
+{
|
|
|
+ std::lock_guard<std::mutex> look(m_mutexRunRAI);
|
|
|
+ for(auto& it : m_runListRoomActionInfo.getData())
|
|
|
+ {
|
|
|
+ if(it->isEqualBaseInfo(*pInfo))
|
|
|
+ {
|
|
|
+ it->RunState = state;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -986,22 +1008,27 @@ void SPAServer::threadActPersonWork(RoomActionInfo* RAInfo)
|
|
|
*
|
|
|
* @param RAInfo 传入的房间ID和算法ID
|
|
|
*/
|
|
|
-void SPAServer::threadActPersonNumber(RoomActionInfo* RAInfo)
|
|
|
+void SPAServer::threadActRegionalPersonnelDetection(RoomActionInfo* RAInfo)
|
|
|
{
|
|
|
SPDLOG_LOGGER_INFO(m_logger, "开启区域人员检测线程,RoomID:{} ,Action:{}", RAInfo->RoomID, RAInfo->ActionID);
|
|
|
/* 创建读取Redis的实例 */
|
|
|
std::shared_ptr<FromRedis> fromRedis = std::make_shared<FromRedis>();
|
|
|
/* 局部变量 */
|
|
|
std::shared_ptr<RoomActionInfo> pRAInfo = std::make_shared<RoomActionInfo>();
|
|
|
+ /* 创建写入数据库实例 */
|
|
|
+ std::shared_ptr<ToEQMDataBase> toEQMDataBase = std::make_shared<ToEQMDataBase>();
|
|
|
*pRAInfo = *RAInfo;
|
|
|
int CameraCount = 0;
|
|
|
- /* 摄像机数目等于0就退出线程 */
|
|
|
+ /* 保存每个摄像机的报警信息 */
|
|
|
+ std::shared_ptr<std::list<AlarmInfo>> pListAlarmInfo = std::make_shared<std::list<AlarmInfo>>();
|
|
|
+
|
|
|
while (m_threadRunning)
|
|
|
{
|
|
|
/* 更新算法关联的摄像机个数 */
|
|
|
pRAInfo->listCameraID.clear();
|
|
|
updateRoomActionCameraCount(pRAInfo);
|
|
|
CameraCount = pRAInfo->listCameraID.size();
|
|
|
+ /* 摄像机数目等于0就退出线程 */
|
|
|
if(CameraCount == 0)
|
|
|
{
|
|
|
break;
|
|
@@ -1015,33 +1042,44 @@ void SPAServer::threadActPersonNumber(RoomActionInfo* RAInfo)
|
|
|
if(!fromRedis->getRedisString(strKey, strRetValue))
|
|
|
{
|
|
|
SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
|
|
|
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
continue;
|
|
|
}
|
|
|
/* 解析数据 */
|
|
|
AlarmInfo alarmInfo;
|
|
|
- parseRedisData(strRetValue, alarmInfo);
|
|
|
+ parseRedisBaseData(strRetValue, alarmInfo);
|
|
|
+ parseRedisBBoxesData(strRetValue, alarmInfo);
|
|
|
}
|
|
|
}
|
|
|
+ setThreadState(pRAInfo, RunTimeState::RUN_STATE_STOP);
|
|
|
+ SPDLOG_LOGGER_INFO(m_logger, "关闭区域人员检测线程,RoomID:{} ,Action:{}", RAInfo->RoomID, RAInfo->ActionID);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * @brief 违禁物品识别
|
|
|
- 报警判断条件:机房内出现摄像头的违禁物品识别算法输出结果包含指定违规内容时,记为报警行为,直接
|
|
|
- 展示报警结果
|
|
|
- 这里应该是不区分违禁物品是什么,只要有违禁物品就报警。如果一个违禁物品消失之前又出现了第二个违禁物品,
|
|
|
- 两个违禁物品都消失后,这次报警才会结束。
|
|
|
+ * @brief 普通任务识别,一个算法只需要一个摄像机,包括 违禁品识别、玩手机检测、老鼠等
|
|
|
+ 1、报警判断条件:机房内出现摄像头的违禁物品识别算法输出结果包含指定违规内容时,记为报警行为,直接
|
|
|
+ 展示报警结果
|
|
|
+ 2、这里应该是不区分违禁物品是什么,只要有违禁物品就报警。如果一个违禁物品消失之前又出现了第二个违禁物品,
|
|
|
+ 两个违禁物品都消失后,这次报警才会结束。
|
|
|
+ 3、一有报警信息就写入到EQM数据库的tAlarmInfo表中,报警开始时间是EventTime
|
|
|
+ 4、如果报警结束时间小于设置的最小间隔,就删除这条数据,超过这个时间,就更新结束时间
|
|
|
+ 5、报警信息要有图片,如果当前没有图片,就使用上一张图片
|
|
|
*
|
|
|
* @param info 线程信息
|
|
|
*/
|
|
|
-void SPAServer::threadActContraband(ActionInfo* info)
|
|
|
+void SPAServer::threadActNormal(ActionInfo* info)
|
|
|
{
|
|
|
- SPDLOG_LOGGER_INFO(m_logger, "开启违禁物品识别线程,RoomID:{} ,Action:{}", info->RoomID, info->ActionID);
|
|
|
+ SPDLOG_LOGGER_INFO(m_logger, "开启 {} 线程,RoomID:{} ,Action:{}",info->strActionName, info->RoomID, info->ActionID);
|
|
|
/* 创建读取Redis的实例 */
|
|
|
std::shared_ptr<FromRedis> fromRedis = std::make_shared<FromRedis>();
|
|
|
+ /* 创建写入EQM数据库实例 */
|
|
|
+ std::shared_ptr<ToEQMDataBase> toEQMDataBase = std::make_shared<ToEQMDataBase>();
|
|
|
/* 局部变量,保存这个线程的信息 */
|
|
|
std::shared_ptr<ActionInfo> pActInfo = std::make_shared<ActionInfo>();
|
|
|
*pActInfo = *info;
|
|
|
- /* 摄像机ID小于0就退出线程 */
|
|
|
+ /* 保存报警数据 */
|
|
|
+ std::shared_ptr<AlarmInfo> pAlarmInfo = std::make_shared<AlarmInfo>();
|
|
|
+
|
|
|
while (m_threadRunning)
|
|
|
{
|
|
|
/* 更新算法关联的摄像机ID */
|
|
@@ -1057,6 +1095,7 @@ void SPAServer::threadActContraband(ActionInfo* info)
|
|
|
if(!fromRedis->getRedisString(strKey, strRetValue))
|
|
|
{
|
|
|
SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
|
|
|
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
continue;
|
|
|
}
|
|
|
/* 解析数据 */
|
|
@@ -1067,14 +1106,65 @@ void SPAServer::threadActContraband(ActionInfo* info)
|
|
|
if(isEventTimeVaild(alarmInfo.EventTime))
|
|
|
{
|
|
|
SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, alarmInfo.EventTime);
|
|
|
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
continue;
|
|
|
}
|
|
|
- /* 判断有无报警记录,写入到EQM数据库 */
|
|
|
+ /* 判断有无报警记录,新的报警就写入到EQM的tAlarmInfo表中,正在报警的记录就判断和更新,
|
|
|
+ * 结束报警就更新tAlarmInfo的报警数据的结束时间,并清空pAlarmInfo */
|
|
|
+ if(pAlarmInfo->Is_Alarm)
|
|
|
+ {
|
|
|
+ /* 正在报警中,检查是否报警结束 */
|
|
|
+ if(alarmInfo.Is_Alarm)
|
|
|
+ {
|
|
|
+ /* 更新图片信息 */
|
|
|
+ if(!alarmInfo.ImageInfo.empty())
|
|
|
+ {
|
|
|
+ pAlarmInfo->ImageInfo = alarmInfo.ImageInfo;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* 报警结束,判断时长,更新数据库结束时间,结束时间是此时电脑时间 */
|
|
|
+ if(timeDiffWithNow(pAlarmInfo->EventTime) > g_config.Contraband)
|
|
|
+ {
|
|
|
+ pAlarmInfo->EndTime = chronoToStrTime(std::chrono::system_clock::now());
|
|
|
+ toEQMDataBase->updateAlarmEndTime(*pAlarmInfo);
|
|
|
+ }else {
|
|
|
+ /* 不够报警时间,目前不做任何处理,不删除EQM报警记录 */
|
|
|
+ }
|
|
|
|
|
|
+ /* 清空报警信息 */
|
|
|
+ pAlarmInfo->reInit();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ /* 是新的报警 */
|
|
|
+ if(alarmInfo.Is_Alarm)
|
|
|
+ {
|
|
|
+ /* 布片不能是空,如果是空的,就不写入数据库 */
|
|
|
+ if(!alarmInfo.ImageInfo.empty())
|
|
|
+ {
|
|
|
+ /* 违禁品检测,开始时间是事件时间 */
|
|
|
+ alarmInfo.StartTime = alarmInfo.EventTime;
|
|
|
+ alarmInfo.EndTime = "";
|
|
|
+ if(toEQMDataBase->insertAlarmInfo(alarmInfo))
|
|
|
+ {
|
|
|
+ /* 保存新的报警记录 */
|
|
|
+ *pAlarmInfo = alarmInfo;
|
|
|
+ }else {
|
|
|
+ SPDLOG_LOGGER_ERROR(m_logger, "写入tAlarmInfo报警数据失败, Key: {}", strKey);
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ SPDLOG_LOGGER_ERROR(m_logger, "频道:{}, 房间:{}, 摄像机:{}, 算法:{}, 有报警区域, 但是没有图片信息", pActInfo->ChannelID, pActInfo->RoomID, pActInfo->CameraID, pActInfo->ActionID);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 休眠设置的时间 */
|
|
|
+ std::this_thread::sleep_for(std::chrono::seconds(g_config.ThreadSleepMS));
|
|
|
}
|
|
|
/* 设置线程退出的状态 */
|
|
|
setThreadState(pActInfo, RunTimeState::RUN_STATE_STOP);
|
|
|
- SPDLOG_LOGGER_INFO(m_logger, "违禁物品识别线程退出,RoomID:{} ,CameraID, Action:{}", pActInfo->RoomID, pActInfo->CameraID, pActInfo->ActionID);
|
|
|
+ SPDLOG_LOGGER_INFO(m_logger, "{} 线程退出,RoomID:{} ,CameraID, Action:{}",pActInfo->strActionName, pActInfo->RoomID, pActInfo->CameraID, pActInfo->ActionID);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1128,3 +1218,35 @@ void SPAServer::threadActIllegalInvasion(ActionInfo* info)
|
|
|
SPDLOG_LOGGER_INFO(m_logger, "非法入侵检测线程退出,RoomID:{} ,CameraID:{}, Action:{}", pActInfo->RoomID, pActInfo->CameraID, pActInfo->ActionID);
|
|
|
}
|
|
|
|
|
|
+/* 计算与当前时间的时间差,返回秒 */
|
|
|
+int SPAServer::timeDiffWithNow(const std::string& strTime)
|
|
|
+{
|
|
|
+ auto now = std::chrono::system_clock::now();
|
|
|
+
|
|
|
+ auto eventTime = strTimeToChrono(strTime);
|
|
|
+ std::chrono::duration<double> diff = now - eventTime;
|
|
|
+
|
|
|
+ return diff.count();
|
|
|
+}
|
|
|
+
|
|
|
+/* 字符串时间转换成std::chrono时间点 */
|
|
|
+std::chrono::system_clock::time_point SPAServer::strTimeToChrono(const std::string& strTime)
|
|
|
+{
|
|
|
+ std::istringstream iss(strTime);
|
|
|
+ std::tm tmEvent = {};
|
|
|
+ iss >> std::get_time(&tmEvent, "%Y-%m-%d %H:%M:%S");
|
|
|
+
|
|
|
+ return std::chrono::system_clock::from_time_t(std::mktime(&tmEvent));
|
|
|
+}
|
|
|
+
|
|
|
+/* 时间点转换成字符串 */
|
|
|
+std::string SPAServer::chronoToStrTime(const std::chrono::system_clock::time_point& timePoint)
|
|
|
+{
|
|
|
+ std::time_t time = std::chrono::system_clock::to_time_t(timePoint);
|
|
|
+ std::tm tmEvent = *std::localtime(&time);
|
|
|
+ char buf[64] = {0};
|
|
|
+ std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tmEvent);
|
|
|
+
|
|
|
+ return std::string(buf);
|
|
|
+}
|
|
|
+
|