UniversalFunc.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. #include "UniversalFunc.h"
  2. #include "spdlog/spdlog.h"
  3. #include "GlobalVariable.h"
  4. #include "GlobalConfig.h"
  5. /**
  6. * @brief 解析Redis的基础通用数据,不包含bBoxes数组数据
  7. *
  8. * @param strData Redis返回的源数据,JSON格式
  9. * @param alarmInfo 解析出来的数据
  10. */
  11. void parseRedisBaseData(const std::string& strData, AlarmInfo& alarmInfo)
  12. {
  13. try
  14. {
  15. nJson json0;
  16. json0 = nJson::parse(strData);
  17. // SPDLOG_DEBUG("解析Redis数据: \n{}", json0.dump(4));
  18. alarmInfo.AlarmID = json0["alarmId"].get<int>();
  19. alarmInfo.ActionID = json0["actionId"].get<std::string>();
  20. alarmInfo.ActionDes = json0["actionDes"].is_null() ? "" : json0["actionDes"].get<std::string>();
  21. alarmInfo.PicUrl = json0["picUrl"].is_null() ? "" : json0["picUrl"].get<std::string>();
  22. alarmInfo.ImageInfo = json0["imageInfo"].is_null() ? "" : json0["imageInfo"].get<std::string>();
  23. /* 解析时间,需要将时间中的“T”换成空格 */
  24. alarmInfo.StartTime = json0["beginTime"].get<std::string>();
  25. std::replace(alarmInfo.StartTime.begin(), alarmInfo.StartTime.end(), 'T', ' ');
  26. alarmInfo.EndTime = json0["endTime"].get<std::string>();
  27. std::replace(alarmInfo.EndTime.begin(), alarmInfo.EndTime.end(), 'T', ' ');
  28. alarmInfo.EventTime = json0["eventTime"].get<std::string>();
  29. std::replace(alarmInfo.EventTime.begin(), alarmInfo.EventTime.end(), 'T', ' ');
  30. }
  31. catch (const nJson::parse_error& e)
  32. {
  33. SPDLOG_ERROR("解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id);
  34. return;
  35. }
  36. catch (const nJson::type_error& e)
  37. {
  38. SPDLOG_ERROR("解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id);
  39. return;
  40. }
  41. catch (...)
  42. {
  43. SPDLOG_ERROR("解析Redis数据失败,其他错误!");
  44. return;
  45. }
  46. }
  47. /**
  48. * @brief 解析Redis的bBoxes数据,这个内容可能根据算法ID不同,内容不同
  49. *
  50. * @param strData
  51. * @param alarmInfo
  52. */
  53. void parseRedisBBoxesData(const std::string& strData, AlarmInfo& alarmInfo)
  54. {
  55. try
  56. {
  57. nJson json0;
  58. json0 = nJson::parse(strData);
  59. /* 判断bBoxes有无数据,有数据就解析,没数据就直接返回了 */
  60. nJson json1 = json0["bBoxes"];
  61. std::string labelList; /* 记录违禁品 */
  62. std::list<std::string> listBbox; /* 记录bbox */
  63. if(!json1.empty())
  64. {
  65. for(auto& it0 : json1)
  66. {
  67. /* 如果status是true,就不是报警,直接跳过 */
  68. bool status = it0["status"].get<bool>();
  69. if(status)
  70. {
  71. continue;
  72. }
  73. /* 这一条Box数据报警了将其内容存储起来 */
  74. alarmInfo.Is_Alarm = true;
  75. /* 解析label,违禁品关键字,先判断这个是不是违禁品检测的算法ID */
  76. if(alarmInfo.ActionID == GVariable.ActContraband)
  77. {
  78. /* 解析报警,取出报警类型 */
  79. nJson label = it0["label"];
  80. for(auto& it1 : label)
  81. {
  82. std::string strLabel = it1.get<std::string>();
  83. /* 检测是否已经加入到字符串中了 */
  84. strLabel += "|";
  85. if(labelList.find(strLabel) != std::string::npos)
  86. {
  87. continue;
  88. }
  89. labelList += strLabel;
  90. }
  91. }
  92. /* 解析bbox,貌似是在图像中的位置 */
  93. nJson bbox = it0["bbox"];
  94. std::string strBbox;
  95. for(auto& it1 : bbox)
  96. {
  97. strBbox += std::to_string(it1.get<int>()) + ",";
  98. }
  99. /* 去掉最后一个“,” */
  100. if(!strBbox.empty())
  101. {
  102. strBbox.pop_back();
  103. }
  104. listBbox.push_back(strBbox);
  105. }
  106. /* 去掉最后一个“|” */
  107. if(!labelList.empty())
  108. {
  109. labelList.pop_back();
  110. }
  111. SPDLOG_DEBUG("违禁品列表:{}", labelList);
  112. }
  113. /* 如果有报警的Box,解析出报警的说明 */
  114. if(alarmInfo.Is_Alarm)
  115. {
  116. /* 添加报警信息的提示信息 */
  117. alarmInfo.listBbox = listBbox;
  118. /* 违禁品报警信息,违禁品列表不是空的,就添加补充的文字 */
  119. if( (alarmInfo.ActionID == GVariable.ActContraband) && !labelList.empty() )
  120. {
  121. alarmInfo.ActionDes = fmt::format("出现违禁品[{}]告警", labelList);
  122. SPDLOG_INFO("{}", alarmInfo.ActionDes);
  123. }else {
  124. /* 其他报警信息,直接获取 */
  125. alarmInfo.ActionDes = json0["actionDes"].get<std::string>();
  126. }
  127. /* 判断有没有报警数据 */
  128. if(alarmInfo.ImageInfo.empty())
  129. {
  130. SPDLOG_WARN("有报警区域,但是没有图片信息");
  131. return;
  132. }
  133. /* 如果是人员报警,就存储人员报警信息 */
  134. if(alarmInfo.ActionID == GVariable.ActFaceIdentify)
  135. {
  136. nJson jsonArray = json0["personList"];
  137. for(auto& it : jsonArray)
  138. {
  139. PersonInfo personInfo;
  140. personInfo.PersonID = it["personId"].get<std::string>();
  141. personInfo.PersonName = it["personName"].get<std::string>();
  142. alarmInfo.listPersonInfo.push_back(personInfo);
  143. }
  144. }
  145. }
  146. }
  147. catch (const nJson::parse_error& e)
  148. {
  149. SPDLOG_ERROR("解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id);
  150. return;
  151. }
  152. catch (const nJson::type_error& e)
  153. {
  154. SPDLOG_ERROR("解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id);
  155. return;
  156. }
  157. catch (...)
  158. {
  159. SPDLOG_ERROR("解析Redis数据失败,其他错误!");
  160. return;
  161. }
  162. }
  163. /* 解析Redis的其他数据,人员计数版,主要是BBoxes和PersonList */
  164. bool parseOtherDataPersonCount(const std::string& strData, AlarmInfo& alarmInfo)
  165. {
  166. try
  167. {
  168. nJson json0;
  169. json0 = nJson::parse(strData);
  170. /* 判断bBoxes有无数据,有数据就解析,没数据就直接返回了 */
  171. nJson jsonArray = json0["bBoxes"];
  172. std::list<std::string> listBbox; /* 记录bbox */
  173. if(jsonArray.empty())
  174. {
  175. SPDLOG_WARN("没有bBoxes数据");
  176. return false;
  177. }
  178. /* 解析bBoxes JSON数组 */
  179. for(const auto& it0 : jsonArray)
  180. {
  181. bool status = it0["status"].get<bool>();
  182. /* 如果status是true,就不是报警,直接跳过 */
  183. if(status)
  184. {
  185. continue;
  186. }
  187. /* 这一条Box数据报警了将其内容存储起来 */
  188. alarmInfo.Is_Alarm = true;
  189. /* 解析bbox,貌似是在图像中的位置 */
  190. nJson bbox = it0["bbox"];
  191. std::string strBbox;
  192. for(auto& it1 : bbox)
  193. {
  194. strBbox += std::to_string(it1.get<int>()) + ",";
  195. }
  196. /* 去掉最后一个“,” */
  197. if(!strBbox.empty())
  198. {
  199. strBbox.pop_back();
  200. }
  201. listBbox.push_back(strBbox);
  202. }
  203. /* 如果有报警的Box,解析出报警的说明 */
  204. if(alarmInfo.Is_Alarm)
  205. {
  206. /* 添加报警信息的提示信息 */
  207. alarmInfo.listBbox = listBbox;
  208. /* 其他报警信息,直接获取(已经在基础解析中获取了) */
  209. // alarmInfo.ActionDes = json0["actionDes"].get<std::string>();
  210. /* 判断有没有报警数据 */
  211. if(alarmInfo.ImageInfo.empty())
  212. {
  213. SPDLOG_WARN("有报警区域,但是没有图片信息");
  214. return false;
  215. }
  216. /* 如果是人员报警,就存储人员报警信息 */
  217. // if(alarmInfo.ActionID == GVariable.ActFaceIdentify)
  218. // {
  219. // nJson jsonArray = json0["personList"];
  220. // for(auto& it : jsonArray)
  221. // {
  222. // PersonInfo personInfo;
  223. // personInfo.PersonID = it["personId"].get<std::string>();
  224. // personInfo.PersonName = it["personName"].get<std::string>();
  225. // alarmInfo.listPersonInfo.push_back(personInfo);
  226. // }
  227. // }
  228. }
  229. }
  230. catch (const nJson::parse_error& e)
  231. {
  232. SPDLOG_ERROR("解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id);
  233. return false;
  234. }
  235. catch (const nJson::type_error& e)
  236. {
  237. SPDLOG_ERROR("解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id);
  238. return false;
  239. }
  240. catch (...)
  241. {
  242. SPDLOG_ERROR("解析Redis数据失败,其他错误!");
  243. return false;
  244. }
  245. return true;
  246. }
  247. /**
  248. * @brief 判断时间是否长时间没有更新,默认的是600秒,超过这个时间Redis还未更新,可能是超脑挂了
  249. *
  250. * @param strTime
  251. * @return true
  252. * @return false
  253. */
  254. bool isEventTimeVaild(const std::string& strTime)
  255. {
  256. /* 获取当前时间 */
  257. std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
  258. /* 字符串转成时间 */
  259. std::istringstream iss(strTime);
  260. std::tm tmEvent = {};
  261. iss >> std::get_time(&tmEvent, "%Y-%m-%d %H:%M:%S.%z");
  262. if(iss.fail())
  263. {
  264. SPDLOG_WARN("时间格式错误:{}", strTime);
  265. return false;
  266. }
  267. /* 时间差 */
  268. std::chrono::system_clock::time_point eventTime = std::chrono::system_clock::from_time_t(std::mktime(&tmEvent));
  269. std::chrono::duration<double> diff = now - eventTime;
  270. // SPDLOG_LOGGER_DEBUG(m_logger, "now:{} eventTime: {} 时间差:{}秒",now, eventTime, diff);
  271. if(diff.count() > 600)
  272. {
  273. // SPDLOG_LOGGER_ERROR(m_logger, "Redis数据长时间没有更新,EventTime:{}", strTime);
  274. return false;
  275. }
  276. return true;
  277. }
  278. /* 判断redis数据是否长时间没有更新 */
  279. bool isEventTimeVaild(const QDateTime& nowTime, const std::string& strTime)
  280. {
  281. /* 将字符串转换成QDateTime,带有小数点 */
  282. QDateTime eventTime = QDateTime::fromString(QString::fromStdString(strTime), "yyyy-MM-dd hh:mm:ss.zzz");
  283. if(eventTime.isNull())
  284. {
  285. SPDLOG_WARN("时间格式错误:{}", strTime);
  286. return false;
  287. }
  288. /* 判断时间差 */
  289. qint64 diff = nowTime.toSecsSinceEpoch() - eventTime.toSecsSinceEpoch();
  290. if(diff > 600)
  291. {
  292. // SPDLOG_WARN("Redis数据长时间没有更新,nowTime: {}, EventTime:{}", nowTime.toString("yyyy-MM-dd hh:mm:ss.zzz").toStdString(), strTime);
  293. return false;
  294. }
  295. return true;
  296. }
  297. /* 计算与当前时间的时间差,返回秒 */
  298. int timeDiffWithNow(const std::string& strTime)
  299. {
  300. auto now = std::chrono::system_clock::now();
  301. auto eventTime = strTimeToChrono(strTime);
  302. std::chrono::duration<double> diff = now - eventTime;
  303. return diff.count();
  304. }
  305. /* 字符串时间转换成std::chrono时间点 */
  306. std::chrono::system_clock::time_point strTimeToChrono(const std::string& strTime)
  307. {
  308. std::istringstream iss(strTime);
  309. std::tm tmEvent = {};
  310. iss >> std::get_time(&tmEvent, "%Y-%m-%d %H:%M:%S");
  311. return std::chrono::system_clock::from_time_t(std::mktime(&tmEvent));
  312. }
  313. /* 时间点转换成字符串 */
  314. std::string chronoToStrTime(const std::chrono::system_clock::time_point& timePoint)
  315. {
  316. std::time_t time = std::chrono::system_clock::to_time_t(timePoint);
  317. std::tm tmEvent = *std::localtime(&time);
  318. char buf[64] = {0};
  319. std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tmEvent);
  320. return std::string(buf);
  321. }
  322. /* 通过应用ID获取应用名称 */
  323. std::string getAppFunctionName(const AppFunction appID)
  324. {
  325. std::string strRet;
  326. switch(appID)
  327. {
  328. case AppFunction::APP_OnWork:
  329. strRet = "人员在岗识别";
  330. break;
  331. case AppFunction::APP_Contraband:
  332. strRet = "违禁物品识别";
  333. break;
  334. case AppFunction::APP_Illegal:
  335. strRet = "区域非法入侵检测";
  336. break;
  337. case AppFunction::APP_Fatigue:
  338. strRet = "疲劳检测识别";
  339. break;
  340. case AppFunction::APP_Regional:
  341. strRet = "区域人员统计";
  342. break;
  343. case AppFunction::APP_Mouse:
  344. strRet = "老鼠识别";
  345. break;
  346. case AppFunction::APP_PlayPhone:
  347. strRet = "玩手机识别";
  348. break;
  349. case AppFunction::APP_NoMask:
  350. strRet = "未戴口罩识别";
  351. break;
  352. case AppFunction::APP_AllDown:
  353. strRet = "摔倒识别";
  354. break;
  355. default:
  356. strRet = "未知功能";
  357. break;
  358. }
  359. return strRet;
  360. }
  361. /* 获取应用ID在EQM数据库中的编号,按位运算的编号 */
  362. int getAppFunctionID(const AppFunction appID)
  363. {
  364. int nRet = 0;
  365. switch(appID)
  366. {
  367. case AppFunction::APP_OnWork:
  368. nRet = 0x01;
  369. break;
  370. case AppFunction::APP_Contraband:
  371. nRet = 0x02;
  372. break;
  373. case AppFunction::APP_Illegal:
  374. nRet = 0x04;
  375. break;
  376. case AppFunction::APP_Fatigue:
  377. nRet = 0x08;
  378. break;
  379. case AppFunction::APP_Regional:
  380. nRet = 0x10;
  381. break;
  382. case AppFunction::APP_Mouse:
  383. nRet = 0x20;
  384. break;
  385. case AppFunction::APP_PlayPhone:
  386. nRet = 0x40;
  387. break;
  388. case AppFunction::APP_NoMask:
  389. nRet = 0x80;
  390. break;
  391. case AppFunction::APP_AllDown:
  392. nRet = 0x100;
  393. break;
  394. default:
  395. nRet = 0x00;
  396. break;
  397. }
  398. return nRet;
  399. }
  400. /* 根据EQM数据库中的编号,转换成本地的AppID */
  401. AppFunction getAppFunctionID(int nID)
  402. {
  403. AppFunction appID = AppFunction::APP_NONE;
  404. switch(nID)
  405. {
  406. case 0x01:
  407. appID = AppFunction::APP_OnWork;
  408. break;
  409. case 0x02:
  410. appID = AppFunction::APP_Contraband;
  411. break;
  412. case 0x04:
  413. appID = AppFunction::APP_Illegal;
  414. break;
  415. case 0x08:
  416. appID = AppFunction::APP_Fatigue;
  417. break;
  418. case 0x10:
  419. appID = AppFunction::APP_Regional;
  420. break;
  421. case 0x20:
  422. appID = AppFunction::APP_Mouse;
  423. break;
  424. case 0x40:
  425. appID = AppFunction::APP_PlayPhone;
  426. break;
  427. case 0x80:
  428. appID = AppFunction::APP_NoMask;
  429. break;
  430. case 0x100:
  431. appID = AppFunction::APP_AllDown;
  432. break;
  433. default:
  434. appID = AppFunction::APP_NONE;
  435. break;
  436. }
  437. return appID;
  438. }
  439. /* 根据数字获取周几字符串,范围1-7 */
  440. std::string getWeekDayString(int nWeek)
  441. {
  442. std::string strRet;
  443. switch(nWeek)
  444. {
  445. case 1:
  446. strRet = "周一";
  447. break;
  448. case 2:
  449. strRet = "周二";
  450. break;
  451. case 3:
  452. strRet = "周三";
  453. break;
  454. case 4:
  455. strRet = "周四";
  456. break;
  457. case 5:
  458. strRet = "周五";
  459. break;
  460. case 6:
  461. strRet = "周六";
  462. break;
  463. case 7:
  464. strRet = "周日";
  465. break;
  466. default:
  467. strRet = "未知";
  468. break;
  469. }
  470. return strRet;
  471. }