#include "UniversalFunc.h" #include "spdlog/spdlog.h" #include "GlobalVariable.h" #include "GlobalConfig.h" /** * @brief 解析Redis的基础通用数据,不包含bBoxes数组数据 * * @param strData Redis返回的源数据,JSON格式 * @param alarmInfo 解析出来的数据 */ void parseRedisBaseData(const std::string& strData, AlarmInfo& alarmInfo) { try { nJson json0; json0 = nJson::parse(strData); // SPDLOG_DEBUG("解析Redis数据: \n{}", json0.dump(4)); alarmInfo.AlarmID = json0["alarmId"].get(); alarmInfo.ActionID = json0["actionId"].get(); alarmInfo.ActionDes = json0["actionDes"].is_null() ? "" : json0["actionDes"].get(); // alarmInfo.ImageInfo = json0["picUrl"].is_null() ? "" : json0["picUrl"].get(); alarmInfo.ImageInfo = json0["imageInfo"].is_null() ? "" : json0["imageInfo"].get(); /* 解析时间,需要将时间中的“T”换成空格 */ std::string startTime = json0["beginTime"].get(); std::replace(startTime.begin(), startTime.end(), 'T', ' '); std::string endTime = json0["endTime"].get(); std::replace(endTime.begin(), endTime.end(), 'T', ' '); std::string eventTime = json0["eventTime"].get(); std::replace(eventTime.begin(), eventTime.end(), 'T', ' '); alarmInfo.StartTime = strToDateTime(startTime); alarmInfo.EndTime = strToDateTime(endTime); alarmInfo.EventTime = strToDateTime(eventTime); } catch (const nJson::parse_error& e) { SPDLOG_ERROR("解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id); return; } catch (const nJson::type_error& e) { SPDLOG_ERROR("解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id); return; } catch (...) { SPDLOG_ERROR("解析Redis数据失败,其他错误!"); return; } } /** * @brief 解析Redis的bBoxes数据,这个内容可能根据算法ID不同,内容不同 * * @param strData * @param alarmInfo */ void parseRedisBBoxesData(const std::string& strData, AlarmInfo& alarmInfo) { try { nJson json0; json0 = nJson::parse(strData); /* 判断bBoxes有无数据,有数据就解析,没数据就直接返回了 */ nJson JsonBBoxes = json0["bBoxes"] .is_null() ? nJson::array() : json0["bBoxes"]; std::string labelList; /* 记录违禁品 */ std::list listBbox; /* 记录bbox */ if(!JsonBBoxes.empty()) { for(auto& it0 : JsonBBoxes) { /* 如果status是true,就不是报警,直接跳过 */ bool status = it0["status"].get(); if(status) { continue; } /* 这一条Box数据报警了将其内容存储起来 */ alarmInfo.Is_Alarm = true; /* 解析bbox,在图像中方框的未知 */ nJson bbox = it0["bbox"].is_null() ? nJson::array() : it0["bbox"]; std::string strBbox; for(auto& it1 : bbox) { strBbox += std::to_string(it1.get()) + ","; } /* 去掉最后一个“,” */ if(!strBbox.empty()) { strBbox.pop_back(); } listBbox.push_back(strBbox); /* 解析label,违禁品关键字,先判断这个是不是违禁品检测的算法ID */ if(alarmInfo.ActionID == GVariable.ActContraband()) { /* 解析报警,取出报警类型,label是报警说明,如“玩手机的人” * 这里主要用于读取违禁品名称 */ nJson label = it0["label"]; for(auto& it1 : label) { std::string strLabel = it1.get(); /* 检测是否已经加入到字符串中了 */ strLabel += "|"; if(labelList.find(strLabel) != std::string::npos) { continue; } labelList += strLabel; } } } /* 去掉最后一个“|” */ if(!labelList.empty()) { labelList.pop_back(); } // SPDLOG_DEBUG("label列表:{}", labelList); } /* 如果有报警的Box,解析出报警的说明 */ if(alarmInfo.Is_Alarm) { /* 添加报警信息的提示信息 */ alarmInfo.listBbox = listBbox; /* 违禁品报警信息,违禁品列表不是空的,就添加补充的文字 */ if( (alarmInfo.ActionID == GVariable.ActContraband()) && !labelList.empty() ) { alarmInfo.ActionDes = fmt::format("出现违禁品[{}]告警", labelList); SPDLOG_DEBUG("{}", alarmInfo.ActionDes); }else { /* 其他报警信息,直接获取 */ alarmInfo.ActionDes = json0["actionDes"].get(); } /* 判断有没有报警数据 */ if(alarmInfo.ImageInfo.empty()) { SPDLOG_WARN("有报警区域,但是没有图片信息"); return; } /* 如果是人员报警,就存储人员报警信息 */ if(alarmInfo.ActionID == GVariable.ActFaceIdentify()) { nJson jsonArray = json0["personList"]; for(auto& it : jsonArray) { PersonInfo personInfo; personInfo.PersonID = it["personId"].get(); personInfo.PersonName = it["personName"].get(); alarmInfo.listPersonInfo.push_back(personInfo); } } } } catch (const nJson::parse_error& e) { SPDLOG_ERROR("解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id); return; } catch (const nJson::type_error& e) { SPDLOG_ERROR("解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id); return; } catch (...) { SPDLOG_ERROR("解析Redis数据失败,其他错误!"); return; } } /* 解析Redis的其他数据,人员计数版,主要是BBoxes和PersonList */ bool parseOtherDataPersonCount(const std::string& strData, AlarmInfo& alarmInfo) { try { nJson json0; json0 = nJson::parse(strData); /* 判断bBoxes有无数据,有数据就解析,没数据就直接返回了 */ nJson JsonBBoxes = json0["bBoxes"] .is_null() ? nJson::array() : json0["bBoxes"]; std::list listBbox; /* 记录bbox */ if(JsonBBoxes.empty()) { // SPDLOG_WARN("没有bBoxes数据"); return false; } /* 解析bBoxes JSON数组 */ for(const auto& it0 : JsonBBoxes) { bool status = it0["status"].get(); /* 如果status是true,就不是报警,直接跳过 */ if(status) { continue; } /* 这一条Box数据报警了将其内容存储起来 */ alarmInfo.Is_Alarm = true; /* 解析bbox,貌似是在图像中的位置 */ nJson bbox = it0["bbox"]; std::string strBbox; for(auto& it1 : bbox) { strBbox += std::to_string(it1.get()) + ","; } /* 去掉最后一个“,” */ if(!strBbox.empty()) { strBbox.pop_back(); } listBbox.push_back(strBbox); } /* 如果有报警的Box,解析出报警的说明 */ if(alarmInfo.Is_Alarm) { /* 添加报警信息的提示信息 */ alarmInfo.listBbox = listBbox; /* 其他报警信息,直接获取(已经在基础解析中获取了) */ // alarmInfo.ActionDes = json0["actionDes"].get(); /* 判断有没有报警图片 */ if(alarmInfo.ImageInfo.empty()) { SPDLOG_WARN("有报警区域,但是没有图片信息"); return false; } /* 如果是人员报警,就存储人员报警信息 */ // nJson jsonArray = json0["personList"]; // for(auto& it : jsonArray) // { // PersonInfo personInfo; // personInfo.PersonID = it["personId"].get(); // personInfo.PersonName = it["personName"].get(); // alarmInfo.listPersonInfo.push_back(personInfo); // } } } catch (const nJson::parse_error& e) { SPDLOG_ERROR("解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id); return false; } catch (const nJson::type_error& e) { SPDLOG_ERROR("解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id); return false; } catch (...) { SPDLOG_ERROR("解析Redis数据失败,其他错误!"); return false; } return true; } /* 将字符串转换成QDateTime */ QDateTime strToDateTime(const std::string& strTime) { /* 将字符串转换成QDateTime,带有小数点 */ QDateTime eventTime = QDateTime::fromString(QString::fromStdString(strTime), "yyyy-MM-dd hh:mm:ss.zzz"); if(eventTime.isNull()) { /* 尝试不带小数点的格式 */ eventTime = QDateTime::fromString(QString::fromStdString(strTime), "yyyy-MM-dd hh:mm:ss"); if(eventTime.isNull()) { SPDLOG_WARN("时间格式错误:{}", strTime); return QDateTime::fromString("2000-01-01 00:00:00", "yyyy-MM-dd hh:mm:ss"); } } return eventTime; } /** * @brief 判断时间是否长时间没有更新,默认的是600秒,超过这个时间Redis还未更新,可能是超脑挂了 * * @param strTime * @return true * @return false */ bool isEventTimeVaild(const std::string& strTime) { /* 获取当前时间 */ std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); /* 字符串转成时间 */ std::istringstream iss(strTime); std::tm tmEvent = {}; iss >> std::get_time(&tmEvent, "%Y-%m-%d %H:%M:%S.%z"); if(iss.fail()) { SPDLOG_WARN("时间格式错误:{}", strTime); return false; } /* 时间差 */ std::chrono::system_clock::time_point eventTime = std::chrono::system_clock::from_time_t(std::mktime(&tmEvent)); std::chrono::duration diff = now - eventTime; // SPDLOG_LOGGER_DEBUG(m_logger, "now:{} eventTime: {} 时间差:{}秒",now, eventTime, diff); if(diff.count() > 600) { // SPDLOG_LOGGER_ERROR(m_logger, "Redis数据长时间没有更新,EventTime:{}", strTime); return false; } return true; } /* 判断redis数据是否长时间没有更新 */ bool isEventTimeVaild(const QDateTime& nowTime, const std::string& strTime) { /* 将字符串转换成QDateTime,带有小数点 */ QDateTime eventTime = QDateTime::fromString(QString::fromStdString(strTime), "yyyy-MM-dd hh:mm:ss.zzz"); if(eventTime.isNull()) { SPDLOG_WARN("时间格式错误:{}", strTime); return false; } /* 判断时间差 */ qint64 diff = nowTime.toSecsSinceEpoch() - eventTime.toSecsSinceEpoch(); if(diff > 600) { // SPDLOG_WARN("Redis数据长时间没有更新,nowTime: {}, EventTime:{}", nowTime.toString("yyyy-MM-dd hh:mm:ss.zzz").toStdString(), strTime); return false; } return true; } /* 计算与当前时间的时间差,返回秒 */ int timeDiffWithNow(const std::string& strTime) { auto now = std::chrono::system_clock::now(); auto eventTime = strTimeToChrono(strTime); std::chrono::duration diff = now - eventTime; return diff.count(); } /* 字符串时间转换成std::chrono时间点 */ std::chrono::system_clock::time_point strTimeToChrono(const std::string& strTime) { std::istringstream iss(strTime); std::tm tmEvent = {}; iss >> std::get_time(&tmEvent, "%Y-%m-%d %H:%M:%S.zzz"); return std::chrono::system_clock::from_time_t(std::mktime(&tmEvent)); } /* 时间点转换成字符串 */ std::string 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); } /* 通过应用ID获取应用名称 */ std::string getAppFunctionName(const AppFunction appID) { std::string strRet; switch(appID) { case AppFunction::APP_OnWork: strRet = "人员在岗识别"; break; case AppFunction::APP_Contraband: strRet = "违禁物品识别"; break; case AppFunction::APP_Illegal: strRet = "区域非法入侵检测"; break; case AppFunction::APP_Fatigue: strRet = "疲劳检测识别"; break; case AppFunction::APP_Regional: strRet = "区域人员统计"; break; case AppFunction::APP_Mouse: strRet = "老鼠识别"; break; case AppFunction::APP_PlayPhone: strRet = "玩手机识别"; break; case AppFunction::APP_NoMask: strRet = "未戴口罩识别"; break; case AppFunction::APP_AllDown: strRet = "摔倒识别"; break; default: strRet = "未知功能"; break; } return strRet; } /* 获取应用ID在EQM数据库中的编号,按位运算的编号 */ int getAppFunctionID(const AppFunction appID) { int nRet = 0; switch(appID) { case AppFunction::APP_OnWork: nRet = 0x01; break; case AppFunction::APP_Contraband: nRet = 0x02; break; case AppFunction::APP_Illegal: nRet = 0x04; break; case AppFunction::APP_Fatigue: nRet = 0x08; break; case AppFunction::APP_Regional: nRet = 0x10; break; case AppFunction::APP_Mouse: nRet = 0x20; break; case AppFunction::APP_PlayPhone: nRet = 0x40; break; case AppFunction::APP_NoMask: nRet = 0x80; break; case AppFunction::APP_AllDown: nRet = 0x100; break; default: nRet = 0x00; break; } return nRet; } /* 根据EQM数据库中的编号,转换成本地的AppID */ AppFunction getAppFunctionID(int nID) { AppFunction appID = AppFunction::APP_NONE; switch(nID) { case 0x01: appID = AppFunction::APP_OnWork; break; case 0x02: appID = AppFunction::APP_Contraband; break; case 0x04: appID = AppFunction::APP_Illegal; break; case 0x08: appID = AppFunction::APP_Fatigue; break; case 0x10: appID = AppFunction::APP_Regional; break; case 0x20: appID = AppFunction::APP_Mouse; break; case 0x40: appID = AppFunction::APP_PlayPhone; break; case 0x80: appID = AppFunction::APP_NoMask; break; case 0x100: appID = AppFunction::APP_AllDown; break; default: appID = AppFunction::APP_NONE; break; } return appID; } /* 根据数字获取周几字符串,范围1-7 */ std::string getWeekDayString(int nWeek) { std::string strRet; switch(nWeek) { case 1: strRet = "周一"; break; case 2: strRet = "周二"; break; case 3: strRet = "周三"; break; case 4: strRet = "周四"; break; case 5: strRet = "周五"; break; case 6: strRet = "周六"; break; case 7: strRet = "周日"; break; default: strRet = "未知"; break; } return strRet; }