UniversalFunc.cpp 16 KB

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