|
@@ -81,9 +81,9 @@ void SPAServer::threadFromSuperBrain()
|
|
|
|
|
|
vecAlgNewInfo.clear();
|
|
|
vecDevNewInfo.clear();
|
|
|
- /* 更新关联关系 */
|
|
|
+ /* 更新算法详细信息 */
|
|
|
m_mutexCameraActionID.lock();
|
|
|
- m_toEQMDataBase.getDeviceAlgorithmInfo(m_mapCameraActionID);
|
|
|
+ m_toEQMDataBase.getActionInfo(m_listActionInfo);
|
|
|
m_mutexCameraActionID.unlock();
|
|
|
std::this_thread::sleep_for(std::chrono::seconds(10));
|
|
|
}
|
|
@@ -562,7 +562,7 @@ bool SPAServer::isEventTimeVaild(const std::string& strTime)
|
|
|
|
|
|
|
|
|
/**
|
|
|
- * @brief 刷新房间和摄像机关联的线程
|
|
|
+ * @brief 分派任务的线程
|
|
|
* 线程定时刷新房间和摄像机的管理关系,以及和算法Action的关联关系
|
|
|
*/
|
|
|
void SPAServer::threadRoomCamera()
|
|
@@ -575,113 +575,209 @@ void SPAServer::threadRoomCamera()
|
|
|
while (m_threadRunning)
|
|
|
{
|
|
|
/* 先获取EQM数据库信息,取出房间和摄像机关联信息 */
|
|
|
- toEQMDataBase->getRoomCameraInfo(listRC);
|
|
|
+
|
|
|
/* 取出每个房间的所有算法,int是RoomID,string是Action */
|
|
|
std::multimap<int, std::string> mapCameraActionID;
|
|
|
+ m_mutexRoomActionInfo.lock();
|
|
|
m_mutexCameraActionID.lock();
|
|
|
- for(const auto& it0 : listRC)
|
|
|
+ /* 将算法信息根据房间分类,并找到其需要的摄像机 */
|
|
|
+ m_listRoomActionInfo.clear();
|
|
|
+ for(const auto& it : m_listActionInfo.getData())
|
|
|
+ {
|
|
|
+ m_listRoomActionInfo.addActionInfo(*it);
|
|
|
+ }
|
|
|
+ /* 根据每个房间的算法功能,创建线程 */
|
|
|
+ for(const auto& it0 : m_listRoomActionInfo.getData())
|
|
|
{
|
|
|
- /* 根据房间内的摄像机的ID寻找对应的算法 */
|
|
|
- for(const auto& it1 : it0.listCameraID)
|
|
|
+ /* 人员在岗识别,这个算法需要多个摄像机配合 */
|
|
|
+ if(it0->ActionID == ActPersonWork)
|
|
|
{
|
|
|
- for(const auto& it2 : m_mapCameraActionID)
|
|
|
- {
|
|
|
- if(it1 == it2.first)
|
|
|
- {
|
|
|
- }
|
|
|
- }
|
|
|
+ SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 人员在岗识别", it0->RoomID);
|
|
|
+
|
|
|
+ }
|
|
|
+ /* 区域人员检测,这个需要融合检测 */
|
|
|
+ else if (it0->ActionID == ActPersonNumber)
|
|
|
+ {
|
|
|
+ SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 区域人员检测", it0->RoomID);
|
|
|
+
|
|
|
}
|
|
|
+ /* 违禁物品识别,不需要多个摄像机融合判断,多少个报警都直接上报 */
|
|
|
+ else if (it0->ActionID == ActContraband)
|
|
|
+ {
|
|
|
+ SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 违禁品检测", it0->RoomID);
|
|
|
+
|
|
|
+ }
|
|
|
+ /* 非法入侵检测,这个也不需要摄像机融合 */
|
|
|
+ else if (it0->ActionID == ActIllegalInvasion)
|
|
|
+ {
|
|
|
+ SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 非法入侵检测", it0->RoomID);
|
|
|
+
|
|
|
+ }
|
|
|
+ /* 疲劳检测,不需要摄像机融合检测,直接上报 */
|
|
|
+ else if (it0->ActionID == ActFatigueDetection)
|
|
|
+ {
|
|
|
+ SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 疲劳检测", it0->RoomID);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
m_mutexCameraActionID.unlock();
|
|
|
- /* 根据每个房间的算法功能,匹配其对应的摄像机 */
|
|
|
- m_mutexRoomCameraInfo.lock();
|
|
|
- /* 循环查找每个房间的算法ID与之关联的设备 */
|
|
|
- for(const auto& it0 : mapCameraActionID)
|
|
|
+ m_mutexRoomActionInfo.unlock();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* 判断相机是否有这个算法 */
|
|
|
+bool SPAServer::isCameraHasAction(const int CameraID, const std::string& strActionID)
|
|
|
+{
|
|
|
+ for(const auto& it : m_mapCameraActionID)
|
|
|
+ {
|
|
|
+ if(it.first == CameraID)
|
|
|
{
|
|
|
- /* 人员在岗识别 */
|
|
|
- if(it0.second == ActPersonWork)
|
|
|
+ if(it.second == strActionID)
|
|
|
{
|
|
|
- SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 人员在岗识别", it0.first);
|
|
|
- /* 先查找这个算法ID是否已在列表中 */
|
|
|
- if(findActionIDInList(it0.first, it0.second) == nullptr)
|
|
|
- {
|
|
|
- /* 不在列表中就创建一个 */
|
|
|
- RoomActionInfo* roomActionInfo = new RoomActionInfo;
|
|
|
- roomActionInfo->RoomID = it0.first;
|
|
|
- roomActionInfo->ActionID = it0.second;
|
|
|
- /* 将这个算法相关联的在这个房间内的相机加入其中 */
|
|
|
- for(const auto& it1 : listRC)
|
|
|
- {
|
|
|
- if(it1.RoomID == it0.first)
|
|
|
- {
|
|
|
- /* 判断这些相机哪些有这个算法 */
|
|
|
- for(const auto& it2 : it1.listCameraID)
|
|
|
- {
|
|
|
- if(isCameraHasAction(it2, it0.second))
|
|
|
- {
|
|
|
- roomActionInfo->listCameraID.push_back(it2);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- m_listRoomCameraInfo.push_back(roomActionInfo);
|
|
|
- } else
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+/* 将该算法对应的摄像机放入摄像机列表 */
|
|
|
+bool SPAServer::insertCameraToAction(RoomActionInfo* pRAInfo, std::list<RoomCameraInfo>& listRC, std::multimap<int, std::string>& mapCameraActionID)
|
|
|
+{
|
|
|
+ for(const auto& rci : listRC)
|
|
|
+ {
|
|
|
+ if(rci.RoomID == pRAInfo->RoomID)
|
|
|
+ {
|
|
|
+ /* 这个摄像机在这个房间内,再判断这个摄像机有没有这个算法 */
|
|
|
+ for(const auto& camID : rci.listCameraID)
|
|
|
+ {
|
|
|
+ for(const auto& cai : mapCameraActionID)
|
|
|
{
|
|
|
- /* 算法在列表中,清空算法的摄像机列表,重新加入列表中 */
|
|
|
- RoomActionInfo* roomActionInfo = findActionIDInList(it0.first, it0.second);
|
|
|
- roomActionInfo->listCameraID.clear();
|
|
|
- /* 将这个算法相关联的在这个房间内的相机加入其中 */
|
|
|
- for(const auto& it1 : listRC)
|
|
|
+ if(camID == cai.first)
|
|
|
{
|
|
|
- if(it1.RoomID == it0.first)
|
|
|
+ /* 再判断这个摄像机的算法是否是当前需要的 */
|
|
|
+ if(cai.second == pRAInfo->ActionID)
|
|
|
{
|
|
|
- /* 判断这些相机哪些有这个算法 */
|
|
|
- for(const auto& it2 : it1.listCameraID)
|
|
|
- {
|
|
|
- if(isCameraHasAction(it2, it0.second))
|
|
|
- {
|
|
|
- roomActionInfo->listCameraID.push_back(it2);
|
|
|
- }
|
|
|
- }
|
|
|
+ pRAInfo->listCameraID.push_back(camID);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- /* 违禁物品识别 */
|
|
|
}
|
|
|
}
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+/* 更新房间、算法需要的摄像机个数 */
|
|
|
+bool SPAServer::updateRoomActionCameraCount(std::shared_ptr<RoomActionInfo> pRAInfo)
|
|
|
+{
|
|
|
+ std::lock_guard<std::mutex> look(m_mutexRoomActionInfo);
|
|
|
+ for(auto& it : m_listRoomActionInfo.getData())
|
|
|
+ {
|
|
|
+ if((it->RoomID == pRAInfo->RoomID) && (it->ActionID == pRAInfo->ActionID))
|
|
|
+ {
|
|
|
+ it->listCameraID = pRAInfo->listCameraID;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
|
|
|
-/* 查找算法ID是否已在列表中 */
|
|
|
-RoomActionInfo* SPAServer::findActionIDInList(const int RoomID, const std::string& strActionID)
|
|
|
+
|
|
|
+/**
|
|
|
+ * @brief 人员在岗识别线程,应该是人脸识别线程,这个需要房间内多个摄像机共同识别
|
|
|
+ 1、离岗判断条件:直播间无人算离岗(直播间所有摄像头的区域人员检测算法输出结果都为0时记为离岗开始,
|
|
|
+ 当结果存在非0时记为离岗结束)
|
|
|
+ 2、离岗输出结果:当判断出离岗行为时,依据人脸识别结果,找到离岗时间点前有人的最近一帧画面中的人员,
|
|
|
+ 判断为离岗人员,并计算离岗时长,形成离岗记录(频率、机房、离岗人员、离岗开始时间、离岗结束时间、离
|
|
|
+ 岗持续时长)
|
|
|
+ 3、在岗时长计算方式:每天00:00:00-23:59:59人脸识别结果中所有人员名称的出现次数✖抽帧频率(如5秒抽
|
|
|
+ 取1帧,则出现200次人名表示在岗1000秒时长),形成每日的人员在岗时长记录
|
|
|
+ 4、报警判断条件:依据离岗次数和单次离岗时长进行报警,展示报警结果
|
|
|
+ *
|
|
|
+ * @param pRAInfo 传入房间ID和算法ID
|
|
|
+ */
|
|
|
+void SPAServer::threadActPersonWork(RoomActionInfo* RAInfo)
|
|
|
{
|
|
|
- for(const auto& it0 : m_listRoomCameraInfo)
|
|
|
+ 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>();
|
|
|
+ *pRAInfo = *RAInfo;
|
|
|
+ int CameraCount = pRAInfo->listCameraID.size();
|
|
|
+ /* 摄像机数目小于0就退出线程 */
|
|
|
+ while (CameraCount > 0)
|
|
|
{
|
|
|
- if(it0->RoomID == RoomID)
|
|
|
+ /* 更新算法关联的摄像机个数 */
|
|
|
+ pRAInfo->listCameraID.clear();
|
|
|
+ updateRoomActionCameraCount(pRAInfo);
|
|
|
+ CameraCount = pRAInfo->listCameraID.size();
|
|
|
+
|
|
|
+ /* 读取Redis数据 */
|
|
|
+ for(const auto& camID : pRAInfo->listCameraID)
|
|
|
{
|
|
|
- if(it0->ActionID == strActionID)
|
|
|
+ std::string strKey = std::to_string(camID) + ":" + pRAInfo->ActionID;
|
|
|
+ std::string strRetValue;
|
|
|
+ if(!fromRedis->getRedisString(strKey, strRetValue))
|
|
|
{
|
|
|
- return it0;
|
|
|
+ SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
|
|
|
+ continue;
|
|
|
}
|
|
|
+ /* 解析数据 */
|
|
|
+ AlarmInfo alarmInfo;
|
|
|
+ parseRedisData(strRetValue, alarmInfo);
|
|
|
}
|
|
|
}
|
|
|
- return nullptr;
|
|
|
}
|
|
|
|
|
|
-/* 判断相机是否有这个算法 */
|
|
|
-bool SPAServer::isCameraHasAction(const int CameraID, const std::string& strActionID)
|
|
|
+/**
|
|
|
+ * @brief 区域人员检测,检测这个区域内的人数,不能少于多少人,不能多余多少人
|
|
|
+ * 1、报警判断条件:直播间报警:当前频率所有直播间摄像头的区域人员检测算法输出结果均大于或小于设定人
|
|
|
+ 数值时,记为报警行为,直接展示报警结果
|
|
|
+ 2、录播间报警:当前频率所有录播间摄像头的区域人员检测算法输出结果均大于或小于设定人数值时,记为报
|
|
|
+ 警行为,直接展示报警结果
|
|
|
+ 3、直播间+录播间报警:当前频率直播间人数+录播间人数大于或小于设定人数值时,记为报警行为,直接展示
|
|
|
+ 报警结果
|
|
|
+ *
|
|
|
+ * @param RAInfo 传入的房间ID和算法ID
|
|
|
+ */
|
|
|
+void SPAServer::threadActPersonNumber(RoomActionInfo* RAInfo)
|
|
|
{
|
|
|
- for(const auto& it : m_mapCameraActionID)
|
|
|
+ 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>();
|
|
|
+ *pRAInfo = *RAInfo;
|
|
|
+ int CameraCount = pRAInfo->listCameraID.size();
|
|
|
+ /* 摄像机数目小于0就退出线程 */
|
|
|
+ while (CameraCount > 0)
|
|
|
{
|
|
|
- if(it.first == CameraID)
|
|
|
+ /* 更新算法关联的摄像机个数 */
|
|
|
+ pRAInfo->listCameraID.clear();
|
|
|
+ updateRoomActionCameraCount(pRAInfo);
|
|
|
+ CameraCount = pRAInfo->listCameraID.size();
|
|
|
+
|
|
|
+ /* 读取Redis数据 */
|
|
|
+ for(const auto& camID : pRAInfo->listCameraID)
|
|
|
{
|
|
|
- if(it.second == strActionID)
|
|
|
+ std::string strKey = std::to_string(camID) + ":" + pRAInfo->ActionID;
|
|
|
+ std::string strRetValue;
|
|
|
+ if(!fromRedis->getRedisString(strKey, strRetValue))
|
|
|
{
|
|
|
- return true;
|
|
|
+ SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
|
|
|
+ continue;
|
|
|
}
|
|
|
+ /* 解析数据 */
|
|
|
+ AlarmInfo alarmInfo;
|
|
|
+ parseRedisData(strRetValue, alarmInfo);
|
|
|
}
|
|
|
}
|
|
|
- return false;
|
|
|
}
|
|
|
|
|
|
+
|