Răsfoiți Sursa

V0.1.14
1、添加了检测房间与摄像机配置的线程函数,并取出了房间内的算法所需要的相机

Apple 7 luni în urmă
părinte
comite
eb9ffc987c

+ 46 - 1
SecurePlayAuxServer/GlobalInfo/GlobalInfo.h

@@ -3,6 +3,8 @@
 
 #include <QString>
 #include <vector>
+#include <list>
+#include <map>
 #include "nlohmann/json.hpp"
 
 
@@ -229,12 +231,55 @@ struct AlarmInfo
     std::vector<PersonInfo> vecPersonInfo;    /* 人员信息 */
 };
 
+/**
+ * @brief 房间和摄像机关联信息,这个是从客户端配置的
+ *        一个房间对应多个摄像机
+ * 
+ */
+struct RoomCameraInfo
+{
+    int RoomID;                     /* 房间ID */
+    std::list<int> listCameraID;    /* 摄像机和算法关联信息 */
 
+    RoomCameraInfo() = default;
+    RoomCameraInfo& operator=(const RoomCameraInfo& other) {
+        if (this != &other) {
+            RoomID = other.RoomID;
+            listCameraID = other.listCameraID;
+        }
+        return *this;
+    }
+    /* 这里只对比RoomID */
+    bool operator==(const RoomCameraInfo& other) const {
+        if(RoomID != other.RoomID) {
+            return false;
+        }
+        return true;
+    }
+};
 
 
+/**
+ * @brief 房间ID和算法ID关联的信息,里面也包含该算法使用了哪些摄像机
+ * 
+ */
+struct RoomActionInfo
+{
+    int RoomID;                 /* 房间ID */
+    std::string ActionID;       /* 算法ID */
+    std::list<int> listCameraID;  /* 摄像机ID */
 
+    RoomActionInfo() = default;
+    RoomActionInfo& operator=(const RoomActionInfo& other) {
+        if (this != &other) {
+            RoomID = other.RoomID;
+            ActionID = other.ActionID;
+            listCameraID = other.listCameraID;
+        }
+        return *this;
+    }
 
-
+};
 
 
 

+ 129 - 0
SecurePlayAuxServer/SPAServer.cpp

@@ -81,6 +81,10 @@ void SPAServer::threadFromSuperBrain()
 
         vecAlgNewInfo.clear();
         vecDevNewInfo.clear();
+        /* 更新关联关系 */
+        m_mutexCameraActionID.lock();
+        m_toEQMDataBase.getDeviceAlgorithmInfo(m_mapCameraActionID);
+        m_mutexCameraActionID.unlock();
         std::this_thread::sleep_for(std::chrono::seconds(10));
     }
 }
@@ -556,3 +560,128 @@ bool SPAServer::isEventTimeVaild(const std::string& strTime)
     return true;
 }
 
+
+/**
+ * @brief 刷新房间和摄像机关联的线程
+ *        线程定时刷新房间和摄像机的管理关系,以及和算法Action的关联关系
+ */
+void SPAServer::threadRoomCamera()
+{
+    /* 房间相机关联信息 */
+    std::list<RoomCameraInfo> listRC;
+    /* 创建连接数据库实例 */
+    std::shared_ptr<ToEQMDataBase> toEQMDataBase = std::make_shared<ToEQMDataBase>();
+
+    while (m_threadRunning)
+    {
+        /* 先获取EQM数据库信息,取出房间和摄像机关联信息 */
+        toEQMDataBase->getRoomCameraInfo(listRC);
+        /* 取出每个房间的所有算法,int是RoomID,string是Action */
+        std::multimap<int, std::string> mapCameraActionID;
+        m_mutexCameraActionID.lock();
+        for(const auto& it0 : listRC)
+        {
+            /* 根据房间内的摄像机的ID寻找对应的算法 */
+            for(const auto& it1 : it0.listCameraID)
+            {
+                for(const auto& it2 : m_mapCameraActionID)
+                {
+                    if(it1 == it2.first)
+                    {
+                    }
+                }
+            }
+        }
+        m_mutexCameraActionID.unlock();
+        /* 根据每个房间的算法功能,匹配其对应的摄像机 */
+        m_mutexRoomCameraInfo.lock();
+        /* 循环查找每个房间的算法ID与之关联的设备 */
+        for(const auto& it0 : mapCameraActionID)
+        {
+            /* 人员在岗识别 */
+            if(it0.second == ActPersonWork)
+            {
+                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 
+                {
+                    /* 算法在列表中,清空算法的摄像机列表,重新加入列表中 */
+                    RoomActionInfo* roomActionInfo = findActionIDInList(it0.first, it0.second);
+                    roomActionInfo->listCameraID.clear();
+                    /* 将这个算法相关联的在这个房间内的相机加入其中 */
+                    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);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            /* 违禁物品识别 */
+        }
+    }
+}
+
+
+/* 查找算法ID是否已在列表中 */
+RoomActionInfo* SPAServer::findActionIDInList(const int RoomID, const std::string& strActionID)
+{
+    for(const auto& it0 : m_listRoomCameraInfo)
+    {
+        if(it0->RoomID == RoomID)
+        {
+            if(it0->ActionID == strActionID)
+            {
+                return it0;
+            }
+        }
+    }
+    return nullptr;
+}
+
+/* 判断相机是否有这个算法 */
+bool SPAServer::isCameraHasAction(const int CameraID, const std::string& strActionID)
+{
+    for(const auto& it : m_mapCameraActionID)
+    {
+        if(it.first == CameraID)
+        {
+            if(it.second == strActionID)
+            {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+

+ 20 - 0
SecurePlayAuxServer/SPAServer.h

@@ -37,6 +37,13 @@ private:
     /* 判断时间是否长时间没有更新 */
     bool isEventTimeVaild(const std::string& strTime);
 
+    /* 刷新房间和摄像机关联的线程 */
+    void threadRoomCamera();
+    /* 查找算法ID是否已在列表中 */
+    RoomActionInfo* findActionIDInList(const int RoomID, const std::string& strActionID);
+    /* 判断相机是否有这个算法 */
+    bool isCameraHasAction(const int CameraID, const std::string& strActionID);
+
 private:
     std::shared_ptr<spdlog::logger> m_logger = nullptr;
 
@@ -48,12 +55,25 @@ private:
     std::string m_keyContraband;                        /* 违禁品检测的Key,这个Key后面可能随时会变动 */
     std::string m_KeyFace;                              /* 人脸检测的Key */
 
+    std::string ActPersonWork;                          /* 人员在岗识别 */
+    std::string ActContraband;                          /* 违禁品检测 */
+    std::string ActIllegalInvasion;                     /* 非法入侵检测 */
+    std::string ActFatigueDetection;                    /* 疲劳检测 */
+    std::string ActPersonNumber;                        /* 区域人员检测 */
+    
+
     /* 算法信息,这个就是tAction在内存中的数据,方便后续对比,程序启动的时候会先获取一份 */
     std::vector<AlgorithmInfo> m_vecEqmAlgInfo;
     /* 设备信息,这个是tActionCamer的信息 */
     std::vector<DeviceInfo> m_vecEqmDevInfo;
+    /* 摄像机ID和算法ID对应表 */
+    std::mutex m_mutexCameraActionID;
+    std::multimap<int, std::string> m_mapCameraActionID;
     /* 设备和算法关联信息,这里存储着已经删除的设备对应的算法信息,将在这一轮循环中删除 */
     std::list<int> m_listDevIDDelete;
+    /* 房间和算法关联的信息,包含所需要的摄像机ID */
+    std::mutex m_mutexRoomCameraInfo;
+    std::list<RoomActionInfo*> m_listRoomCameraInfo;
 
 };
 

+ 124 - 0
SecurePlayAuxServer/communication/ToEQMDataBase.cpp

@@ -671,4 +671,128 @@ bool ToEQMDataBase::getDeviceAlgorithmInfo(std::vector<DeviceInfo>& vecInfo, std
     return true;
 }
 
+/* 获取设备和算法关联信息,重载版,只获取关联关系 */
+bool ToEQMDataBase::getDeviceAlgorithmInfo(std::multimap<int, std::string>& mapCameraActionID)
+{
+    if(m_httpApi == nullptr)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger,"WebApi is nullptr");
+        return false;
+    }
+    mapCameraActionID.clear();
+    nJson json0;
+    json0["opName"] = "SPSS_SelectFromActionCamer";
+    QString strCmd = QString::fromStdString(json0.dump());
+    QString strRet;
+    auto ret = m_httpApi->DBQDoInterface(enDBOperatorType::EDBOT_Select, strCmd, strRet);
+    if(ret < 0)
+    {
+        SPDLOG_LOGGER_DEBUG(m_logger,"获取ActionCamer失败:{}, 错误信息:{}",ret,m_httpApi->DoGetLastError(&ret).toStdString());
+        return false;
+    }
+    /* 解析信息 */
+    try
+    {
+        nJson json1 = nJson::parse(strRet.toStdString());
+        int retCode = json1["code"].get<int>();
+        if(retCode != 0)
+        {
+            SPDLOG_LOGGER_ERROR(m_logger,"获取ActionCamer失败");
+            return false;
+        }
+        nJson result = json1["result"];
+        if(result.empty())
+        {
+            return false;
+        }
+        /* 取出所有的设备算法信息 */
+        for(const auto& it : result)
+        {
+            int cameraID = it["camerId"].get<int>();
+            std::string actionID = it["actionId"].is_null() ? "" : it["actionId"].get<std::string>();
+            mapCameraActionID.insert(std::make_pair(cameraID, actionID));
+        }
+    }
+    catch (const nJson::parse_error& e) {
+        SPDLOG_LOGGER_ERROR(m_logger,"解析ActionCamer数据失败:{}, 错误ID:{}",e.what(), e.id);
+        return false;
+    }
+    catch (const nJson::type_error& e) {
+        SPDLOG_LOGGER_ERROR(m_logger,"解析ActionCamer数据失败:{}, 错误ID:{}",e.what(), e.id);
+        return false;
+    }
+
+    return true;
+}
+
+
+/* 获取摄像机和房间关联信息 */
+bool ToEQMDataBase::getRoomCameraInfo(std::list<RoomCameraInfo>& vecInfo)
+{
+    if(m_httpApi == nullptr)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger,"WebApi is nullptr");
+        return false;
+    }
+    vecInfo.clear();
+    nJson json0;
+    json0["opName"] = "SPSS_SelectRoomCamer";
+    QString strCmd = QString::fromStdString(json0.dump());
+    QString strRet;
+    auto ret = m_httpApi->DBQDoInterface(enDBOperatorType::EDBOT_Select, strCmd, strRet);
+    if(ret < 0)
+    {
+        SPDLOG_LOGGER_DEBUG(m_logger,"获取RoomCamer失败:{}, 错误信息:{}",ret,m_httpApi->DoGetLastError(&ret).toStdString());
+        return false;
+    }
+    try
+    {
+        nJson json1 = nJson::parse(strRet.toStdString());
+        int retCode = json1["code"].get<int>();
+        if(retCode != 0)
+        {
+            SPDLOG_LOGGER_ERROR(m_logger,"获取RoomCamer失败");
+            return false;
+        }
+        nJson result = json1["result"];
+        if(result.empty())
+        {
+            return false;
+        }
+        for(const auto& it : result)
+        {
+            auto roomID = it["roomId"].get<int>();
+            auto cameraID = it["camerId"].is_null() ? -1 : it["camerId"].get<int>();
+            /* 先检查RoomID是否已经在列表中了 */
+            bool isExist = false;
+            for(auto& it0 : vecInfo)
+            {
+                if(it0.RoomID == roomID)
+                {
+                    it0.listCameraID.push_back(cameraID);
+                    isExist = true;
+                    break;
+                }
+            }
+            /* 没有找到RoomID,创建一个新的 */
+            if(!isExist)
+            {
+                RoomCameraInfo info;
+                info.RoomID = roomID;
+                info.listCameraID.push_back(cameraID);
+            }
+        }
+    }
+    catch (const nJson::parse_error& e) {
+        SPDLOG_LOGGER_ERROR(m_logger,"解析ActionCamer数据失败:{}, 错误ID:{}",e.what(), e.id);
+        return false;
+    }
+    catch (const nJson::type_error& e) {
+        SPDLOG_LOGGER_ERROR(m_logger,"解析ActionCamer数据失败:{}, 错误ID:{}",e.what(), e.id);
+        return false;
+    }
+
+    return true;
+}
+
 

+ 5 - 0
SecurePlayAuxServer/communication/ToEQMDataBase.h

@@ -39,6 +39,11 @@ public:
     bool deleteDeviceAlgorithmInfo(std::list<int>& vecID);
     /* 获取设备和算法信息关联表,需要先从EQM数据库中获取到设备信息,然后根据读取到的设备信息,取出已经删除的设备ID */
     bool getDeviceAlgorithmInfo(std::vector<DeviceInfo>& vecInfo, std::list<int>& listDevIDDelete);
+    bool getDeviceAlgorithmInfo(std::multimap<int, std::string>& mapCameraActionID);
+
+    /* 获取摄像机和房间关联信息 */
+    bool getRoomCameraInfo(std::list<RoomCameraInfo>& vecInfo);
+    
 
 private:
     std::shared_ptr<spdlog::logger> m_logger = nullptr;

+ 1 - 0
安播辅助服务程序说明.md

@@ -119,4 +119,5 @@
 
 ## 应用各算法的检测逻辑
 1. 逻辑详情见[安播辅助提示系统需求文档](https://alidocs.dingtalk.com/i/nodes/20eMKjyp81pbx3nQUAEOAlnGJxAZB1Gv?utm_scene=person_space)
+2. 这里不在是一个摄像机一个线程了,而是根据任务分配线程,如违禁物品每个摄像机对应的Action都可以检测,那么每个Redis Key就是一个线程;检测人员在岗需要房间内的多个摄像机联合起来判断,那么这个房间内的整个摄像机都是对应的Action都在一个线程中。