選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

1520 行
84KB

  1. # -*- coding: utf-8 -*-
  2. import base64
  3. import json
  4. import os
  5. import time
  6. import copy
  7. from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED
  8. from os.path import join, exists
  9. from traceback import format_exc
  10. import cv2
  11. import numpy as np
  12. from multiprocessing import Process, Queue
  13. from loguru import logger
  14. from common.Constant import init_progess, success_progess
  15. from util.GPUtils import check_gpu_resource
  16. from util.LogUtils import init_log
  17. from concurrency.CommonThread import Common
  18. from concurrency.PullStreamThread import RecordingPullStreamThread
  19. from concurrency.PullVideoStreamProcess import OnlinePullVideoStreamProcess, OfflinePullVideoStreamProcess
  20. from concurrency.RecordingHeartbeatThread import RecordingHeartbeat
  21. from enums.AnalysisStatusEnum import AnalysisStatus
  22. from enums.AnalysisTypeEnum import AnalysisType
  23. from enums.ExceptionEnum import ExceptionType
  24. from enums.ModelTypeEnum import ModelType
  25. from enums.RecordingStatusEnum import RecordingStatus
  26. from util import TimeUtils
  27. from util.AliyunSdk import AliyunOssSdk, ThAliyunVodSdk
  28. from util.CpuUtils import check_cpu
  29. from util.Cv2Utils import Cv2Util, video_conjuncing, push_video_stream, write_or_video, write_ai_video, close_all_p
  30. from entity.FeedBack import message_feedback, recording_feedback
  31. from exception.CustomerException import ServiceException
  32. from util.ImageUtils import PictureWaterMark, url2Array, add_water_pic
  33. from util.ModelUtils import MODEL_CONFIG, FONTPATH
  34. from util.OcrBaiduSdk import OcrBaiduSdk
  35. from enums.BaiduSdkEnum import VehicleEnumVALUE, VehicleEnum
  36. from enums.ModelTypeEnum import BaiduModelTarget
  37. from util.PlotsUtils import draw_painting_joint, get_label_arrays
  38. class IntelligentRecognitionProcess(Process):
  39. __slots__ = (
  40. '_fbQueue',
  41. 'eventQueue',
  42. '_imageQueue',
  43. '_hbQueue',
  44. 'pullQueue',
  45. '_context',
  46. '_msg',
  47. '_analyse_type',
  48. '_base_dir',
  49. '_gpu_name',
  50. '_enable_add_water',
  51. '_logo',
  52. 'start_proccess_time'
  53. )
  54. def __init__(self, param):
  55. super().__init__()
  56. # Param(self._fbQueue, msg, analysisType, self.__base_dir)
  57. self._fbQueue = param.fbqueue
  58. self.eventQueue = Queue()
  59. self._imageQueue = Queue()
  60. self._hbQueue = Queue()
  61. self.pullQueue = Queue(100)
  62. self._context = param.context
  63. self._base_dir = param.base_dir
  64. self._msg = param.msg
  65. self._gpu_name = param.gpu_name
  66. self._analyse_type = param.analyse_type
  67. self._enable_add_water = bool(self._context["video"]["video_add_water"])
  68. self.start_proccess_time = time.time()
  69. self._logo = None
  70. if self._enable_add_water:
  71. self._logo = self._msg.get("logo_url")
  72. if self._logo:
  73. self._logo = url2Array(self._logo, enable_ex=False)
  74. if not self._logo:
  75. self._logo = cv2.imread(join(self._base_dir, "image/logo.png"), -1)
  76. putStatusMessage(self._fbQueue, AnalysisStatus.WAITING.value, init_progess, self._analyse_type,
  77. self._msg.get("request_id"))
  78. def clearPullQueue(self):
  79. while True:
  80. if self.pullQueue.qsize() > 0 or self._imageQueue.qsize() > 0:
  81. getNoBlockQueue(self.pullQueue)
  82. getNoBlockQueue(self._imageQueue)
  83. else:
  84. break
  85. def waitPullStream(self, pullProcess):
  86. while True:
  87. self.clearPullQueue()
  88. start = time.time()
  89. pullProcess.join(5)
  90. if time.time() - start >= 5:
  91. self.clearPullQueue()
  92. else:
  93. break
  94. # 给本进程发送事件
  95. def sendEvent(self, eBody):
  96. try:
  97. self.eventQueue.put(eBody, timeout=10)
  98. except Exception:
  99. logger.error("添加事件到队列超时异常:{}, requestId:{}", format_exc(), self._msg.get("request_id"))
  100. raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
  101. ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
  102. def getImageQueue(self):
  103. eBody = None
  104. try:
  105. eBody = self._imageQueue.get(block=False)
  106. except Exception as e:
  107. pass
  108. return eBody
  109. def sendImageQueue(self, result):
  110. try:
  111. self._imageQueue.put(result, timeout=10)
  112. except Exception:
  113. logger.error("添加图片到队列超时异常:{}, requestId:{}", format_exc(),
  114. self._msg.get("request_id"))
  115. raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
  116. ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
  117. def sendhbQueue(self, result):
  118. try:
  119. self._hbQueue.put(result, timeout=10)
  120. except Exception:
  121. logger.error("添加心跳到队列超时异常:{}, requestId:{}", format_exc(),
  122. self._msg.get("request_id"))
  123. raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
  124. ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
  125. '''
  126. "models": [{
  127. "code": "模型编号",
  128. "categories":[{
  129. "id": "模型id",
  130. "config": {
  131. "k1": "v1",
  132. "k2": "v2"
  133. }
  134. }]
  135. }]
  136. '''
  137. def get_model(self):
  138. requestId = self._msg.get("request_id")
  139. try:
  140. analyse_type_tuple = (AnalysisType.ONLINE.value, AnalysisType.OFFLINE.value)
  141. models = self._msg.get("models")
  142. if models is None or len(models) == 0:
  143. raise ServiceException(ExceptionType.AI_MODEL_CONFIG_EXCEPTION.value[0],
  144. ExceptionType.AI_MODEL_CONFIG_EXCEPTION.value[1])
  145. if self._analyse_type in analyse_type_tuple:
  146. if len(models) > self._context["model"]['limit']:
  147. raise ServiceException(ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[0],
  148. ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[1])
  149. modelArray = []
  150. codeArray = set()
  151. for model in models:
  152. # 模型编码
  153. code = model.get("code")
  154. # 检验code是否重复
  155. if code in codeArray:
  156. continue
  157. codeArray.add(code)
  158. # 检测目标数组
  159. needed_objectsIndex = list(set([int(category.get("id")) for category in model.get("categories")]))
  160. # 检测目标和相关检测目标配置
  161. # categories = model.get("categories")
  162. logger.info("模型编号: {}, 检查目标: {}, requestId: {}", code, needed_objectsIndex, requestId)
  163. model_method = MODEL_CONFIG.get(code)
  164. if model_method is not None:
  165. check_cpu(self._base_dir, requestId)
  166. gpu_ids = check_gpu_resource(requestId)
  167. if self._analyse_type in analyse_type_tuple:
  168. if model.get("is_video") == "1":
  169. mod = model_method[0](gpu_ids[0], needed_objectsIndex, requestId, self._gpu_name,
  170. self._base_dir)
  171. modelArray.append((mod.model_conf, code))
  172. else:
  173. raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[0],
  174. ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[1],
  175. model_method[1].value[2])
  176. # 如果是图片识别
  177. if self._analyse_type == AnalysisType.IMAGE.value:
  178. if model.get("is_image") == "1":
  179. mod = model_method[0](gpu_ids[0], needed_objectsIndex, requestId, self._gpu_name,
  180. self._base_dir)
  181. modelArray.append((mod.model_conf, code))
  182. else:
  183. raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[0],
  184. ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[1],
  185. model_method[1].value[2])
  186. else:
  187. logger.error("未匹配到对应的模型, request_id:{}", requestId)
  188. raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0],
  189. ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1])
  190. if len(modelArray) == 0:
  191. raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0],
  192. ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1])
  193. return modelArray
  194. except ServiceException as s:
  195. raise s
  196. except Exception as e:
  197. logger.error("模型配置处理异常: {}, request_id: {}", format_exc(), requestId)
  198. raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0],
  199. ExceptionType.MODEL_LOADING_EXCEPTION.value[1])
  200. def putQueue(queue, result, requestId, enable_ex=True):
  201. try:
  202. queue.put(result, timeout=10)
  203. except Exception:
  204. logger.error("添加队列超时异常:{}, requestId:{}", format_exc(), requestId)
  205. if enable_ex:
  206. raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
  207. ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
  208. def putStatusMessage(fb_queue, analysisStatus, progress, analyse_type, requestId):
  209. putQueue(fb_queue, {"feedback": message_feedback(requestId,
  210. analysisStatus,
  211. analyse_type,
  212. progress=progress,
  213. analyse_time=TimeUtils.now_date_to_str())}, requestId)
  214. def getNoBlockQueue(queue):
  215. eBody = None
  216. try:
  217. eBody = queue.get(block=False)
  218. except Exception as e:
  219. pass
  220. return eBody
  221. def getBlockQueue(queue):
  222. return queue.get()
  223. def checkPullProcess(pullProcess, requestId):
  224. if pullProcess is not None and not pullProcess.is_alive():
  225. logger.info("拉流进程停止异常, requestId: {}", requestId)
  226. raise Exception("拉流进程异常停止")
  227. def buildFrame(pull_queue, logo, enable_add_water, frame_score, model_array, task_status, ttt, requestId):
  228. frames = []
  229. status = None
  230. for i in range(pull_queue.qsize()):
  231. frame_result = getNoBlockQueue(pull_queue)
  232. if frame_result is None:
  233. continue
  234. if frame_result[0] == '4':
  235. width = frame_result[3]
  236. if task_status[0] == 1:
  237. for model in model_array:
  238. model_conf = model[0]
  239. label_method = MODEL_CONFIG[model_conf[0].value[1]][2]
  240. if label_method:
  241. model_param = model_conf[2]
  242. label_method(width, model_param)
  243. task_status[0] = 0
  244. # 如果是第一条消息, 第一条消息设置变量为true
  245. # 参数1: ("4", frame, concurrent_frame, w_2, h_2, all_frames), requestId)
  246. # 参数2:task_status 任务记录状态 第一个参数是否发现问题 1发现 0 否
  247. # 参数3:模型信息
  248. # 参数4:logo
  249. # 参数5:是否添加logo
  250. # 参数6:得分多少以上才输出问题
  251. # 参数7: 线程池
  252. # 参数8:是否是第一帧
  253. # 参数9 是否是问题
  254. frames.append((frame_result, task_status, model_array, logo, enable_add_water, frame_score,
  255. ttt, requestId))
  256. else:
  257. status = frame_result
  258. return frames, status
  259. def analyze(mod, frame, task_status):
  260. model_conf = mod[0]
  261. code = mod[1]
  262. model_param = model_conf[2]
  263. model_param[0] = frame
  264. allowedList = None
  265. label_arraylist = None
  266. rainbows = None
  267. if task_status[1] == 1:
  268. p_result, timeOut = MODEL_CONFIG[code][3](model_param)
  269. if p_result[2] is not None and len(p_result[2]) > 0:
  270. allowedList = model_conf[1]
  271. label_arraylist = model_conf[2][4]
  272. rainbows = model_conf[2][5]
  273. else:
  274. time_e = int(time.time())
  275. if time_e % 2 == 0:
  276. p_result, timeOut = MODEL_CONFIG[code][3](model_param)
  277. if p_result[2] is not None and len(p_result[2]) > 0:
  278. allowedList = model_conf[1]
  279. label_arraylist = model_conf[2][4]
  280. rainbows = model_conf[2][5]
  281. else:
  282. p_result = [[], frame, [], []]
  283. return p_result, code, allowedList, label_arraylist, rainbows
  284. def process(frame):
  285. try:
  286. # (frame_result, task_status, model_array, logo, enable_add_water, frame_score, ttt, is_question, requestId)
  287. frame_result = frame[0]
  288. analyze_result = []
  289. or_frame = frame_result[1]
  290. copy_frame = or_frame.copy()
  291. task_status = frame[1]
  292. model_array = frame[2]
  293. logo = frame[3]
  294. enable_add_water = frame[4]
  295. frame_score = frame[5]
  296. ttt = frame[6]
  297. requestId = frame[7]
  298. # 按模型组合识别
  299. for mod in model_array:
  300. result = ttt.submit(analyze, mod, or_frame, task_status)
  301. analyze_result.append(result)
  302. results = wait(analyze_result, timeout=60, return_when=ALL_COMPLETED)
  303. completed_futures = results.done
  304. det_xywh = {}
  305. for r in completed_futures:
  306. if r.exception():
  307. raise r.exception()
  308. p_result, code, allowedList, label_arraylist, rainbows = r.result()
  309. if allowedList is not None:
  310. det_xywh[code] = {}
  311. ai_result_list = p_result[2]
  312. for ai_result in ai_result_list:
  313. # 检测目标
  314. detect_targets_code = int(ai_result[0])
  315. score = ai_result[-1]
  316. # 如果检测目标在识别任务中,继续处理
  317. if detect_targets_code in allowedList and score >= frame_score:
  318. label_array = label_arraylist[detect_targets_code]
  319. color = rainbows[detect_targets_code]
  320. # [float(cls_c), xc,yc,w,h, float(conf_c)]
  321. # [ cls,[ (x0,y0),(x1,y1),(x2,y2),(x3,y3) ],score]
  322. if not isinstance(ai_result[1], (list, tuple, np.ndarray)):
  323. xc = int(ai_result[1])
  324. yc = int(ai_result[2])
  325. x2 = int(ai_result[3])
  326. y2 = int(ai_result[4])
  327. tl = (xc, yc)
  328. tr = (x2, yc)
  329. br = (x2, y2)
  330. bl = (xc, y2)
  331. box = [tl, tr, br, bl]
  332. else:
  333. box = ai_result[1]
  334. draw_painting_joint(box, copy_frame, label_array, score, color, "leftTop")
  335. cd = det_xywh[code].get(detect_targets_code)
  336. if cd is None:
  337. det_xywh[code][detect_targets_code] = [
  338. [detect_targets_code, box, score, label_array, color]]
  339. else:
  340. det_xywh[code][detect_targets_code].append(
  341. [detect_targets_code, box, score, label_array, color])
  342. if enable_add_water:
  343. or_frame = add_water_pic(or_frame, logo, requestId)
  344. copy_frame = add_water_pic(copy_frame, logo, requestId)
  345. frame_merge = video_conjuncing(or_frame, copy_frame)
  346. return frame_result, frame_merge, det_xywh
  347. except ServiceException as s:
  348. raise s
  349. except Exception as e:
  350. logger.error("模型分析异常: {}", format_exc())
  351. raise e
  352. class OnlineIntelligentRecognitionProcess(IntelligentRecognitionProcess):
  353. __slots__ = ('__orFilePath', '__aiFilePath')
  354. def __init__(self, param):
  355. super(OnlineIntelligentRecognitionProcess, self).__init__(param)
  356. random_time = TimeUtils.now_date_to_str(TimeUtils.YMDHMSF)
  357. self.__orFilePath = "%s%s%s%s%s" % (
  358. join(self._base_dir, self._context["video"]["file_path"]), random_time, "_on_or_",
  359. self._msg.get("request_id"), ".mp4")
  360. self.__aiFilePath = "%s%s%s%s%s" % (
  361. join(self._base_dir, self._context["video"]["file_path"]), random_time, "_on_ai_",
  362. self._msg.get("request_id"), ".mp4")
  363. # 停止任务方法
  364. def stop_task(self, pullProcess, snalysisStatus):
  365. pullProcess.sendCommand({"command": "stop_pull_stream"})
  366. if not os.path.exists(self.__orFilePath) or not os.path.exists(self.__aiFilePath):
  367. logger.error("原视频或AI视频不存在!requestId:{}", self._msg.get("request_id"))
  368. raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0],
  369. ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1])
  370. aliyunVodSdk = ThAliyunVodSdk(self._base_dir, self._msg.get("request_id"), self._context["dsp"]["active"])
  371. upload_video_thread_or = Common(self._context, aliyunVodSdk.get_play_url, self.__orFilePath,
  372. "or_online_%s" % self._msg.get("request_id"))
  373. upload_video_thread_ai = Common(self._context, aliyunVodSdk.get_play_url, self.__aiFilePath,
  374. "ai_online_%s" % self._msg.get("request_id"))
  375. upload_video_thread_or.setDaemon(True)
  376. upload_video_thread_ai.setDaemon(True)
  377. upload_video_thread_or.start()
  378. upload_video_thread_ai.start()
  379. or_url = upload_video_thread_or.get_result()
  380. ai_url = upload_video_thread_ai.get_result()
  381. if or_url is None or ai_url is None:
  382. logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", self._msg.get("request_id"))
  383. raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0],
  384. ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1])
  385. pullProcess.sendCommand({"command": "stop_image_hb"})
  386. self.waitPullStream(pullProcess)
  387. putQueue(self._fbQueue, {"feedback": message_feedback(self._msg.get("request_id"), snalysisStatus,
  388. self._analyse_type,
  389. progress=success_progess,
  390. original_url=or_url,
  391. sign_url=ai_url,
  392. analyse_time=TimeUtils.now_date_to_str())},
  393. self._msg.get("request_id"))
  394. def start_pull_stream(self):
  395. pullProcess = OnlinePullVideoStreamProcess(self._msg, self._context, self.pullQueue,
  396. self._fbQueue, self._hbQueue, self._imageQueue,
  397. self._analyse_type, self._base_dir)
  398. pullProcess.daemon = True
  399. pullProcess.start()
  400. return pullProcess
  401. def run(self):
  402. # cv2tool = None
  403. feedback = None
  404. pullProcess = None
  405. requestId = self._msg.get("request_id")
  406. push_url = self._msg.get("push_url")
  407. orFilePath = self.__orFilePath
  408. aiFilePath = self.__aiFilePath
  409. push_p = None
  410. or_video_file = None
  411. ai_video_file = None
  412. fb_queue = self._fbQueue
  413. try:
  414. init_log(self._base_dir)
  415. logger.info("实时任务进行中!!!!!!!requestId: {}", requestId)
  416. # 获取变量
  417. eventQueue = self.eventQueue
  418. pull_queue = self.pullQueue
  419. image_queue = self._imageQueue
  420. # 加载模型
  421. model_array = self.get_model()
  422. # 启动拉流进程
  423. pullProcess = self.start_pull_stream()
  424. enable_add_water = self._enable_add_water
  425. logo = self._logo
  426. # 第1个参数控制是否第一帧, 是1, 不是 0
  427. # 第2个参数控制是否发现问题, 发现问题1, 没有问题0
  428. task_status = [1, 1]
  429. frame_score = float(self._context["service"]["frame_score"])
  430. # cv2tool = Cv2Util(None, self._msg.get("push_url"), self.__orFilePath, self.__aiFilePath, requestId)
  431. putStatusMessage(self._fbQueue, AnalysisStatus.RUNNING.value, init_progess, self._analyse_type, requestId)
  432. task_frame = None
  433. p_push_array = [0, 0]
  434. with ThreadPoolExecutor(max_workers=5) as t:
  435. with ThreadPoolExecutor(max_workers=3) as tt:
  436. with ThreadPoolExecutor(max_workers=15) as ttt:
  437. while True:
  438. checkPullProcess(pullProcess, requestId)
  439. event_result = getNoBlockQueue(eventQueue)
  440. if event_result:
  441. cmdStr = event_result.get("command")
  442. # 接收到停止指令
  443. if "stop_ex" == cmdStr:
  444. close_all_p(push_p, or_video_file, ai_video_file, requestId)
  445. logger.info("实时任务开始停止, requestId: {}", requestId)
  446. pullProcess.sendCommand({"command": 'stop_image_hb'})
  447. feedback = {"feedback": message_feedback(requestId, AnalysisStatus.FAILED.value,
  448. self._analyse_type,
  449. ExceptionType.NO_RESOURCES.value[0],
  450. ExceptionType.NO_RESOURCES.value[1],
  451. analyse_time=TimeUtils.now_date_to_str())}
  452. self.waitPullStream(pullProcess)
  453. break
  454. # 接收到停止指令
  455. if "stop" == cmdStr:
  456. logger.info("实时任务开始停止, requestId: {}", requestId)
  457. pullProcess.sendCommand({"command": 'stop_pull_stream'})
  458. frames = []
  459. status = None
  460. if task_frame:
  461. frames, status = task_frame.result()
  462. task_frame = tt.submit(buildFrame, pull_queue, logo, enable_add_water, frame_score,
  463. model_array, task_status, ttt, requestId)
  464. if len(frames) == 0 and status is None:
  465. time.sleep(0.5)
  466. continue
  467. if len(frames) > 0:
  468. check = False
  469. for result in t.map(process, frames):
  470. if result is not None:
  471. frame_result, frame_merge, det_xywh = result
  472. write_or_video_result = tt.submit(write_or_video, frame_result[1], orFilePath,
  473. or_video_file, frame_result[3],
  474. frame_result[4],
  475. requestId)
  476. write_ai_video_result = tt.submit(write_ai_video, frame_merge, aiFilePath,
  477. ai_video_file, frame_result[3],
  478. frame_result[4],
  479. requestId)
  480. push_p = push_video_stream(frame_merge, push_p, push_url,
  481. frame_result[3], frame_result[4], p_push_array,
  482. requestId)
  483. ai_video_file = write_ai_video_result.result()
  484. or_video_file = write_or_video_result.result()
  485. # res = [push_stream_result, write_or_video_result, write_ai_video_result]
  486. # completed_results = wait(res, timeout=600, return_when=ALL_COMPLETED)
  487. # completed_futures = completed_results.done
  488. # for r in completed_futures:
  489. # if r.exception():
  490. # raise r.exception()
  491. if len(det_xywh) > 0:
  492. check = True
  493. putQueue(image_queue, {"image": (frame_result, det_xywh)}, requestId)
  494. if check:
  495. task_status[1] = 1
  496. if not check:
  497. task_status[1] = 0
  498. if status is None:
  499. continue
  500. if status[0] == "1":
  501. raise ServiceException(status[1], status[2])
  502. elif status[0] == "3":
  503. close_all_p(push_p, or_video_file, ai_video_file, requestId)
  504. self.stop_task(pullProcess, AnalysisStatus.TIMEOUT.value)
  505. break
  506. elif status[0] == "9":
  507. logger.info("实时任务正常结束:requestId: {}", self._msg.get("request_id"))
  508. close_all_p(push_p, or_video_file, ai_video_file, requestId)
  509. self.stop_task(pullProcess, AnalysisStatus.SUCCESS.value)
  510. break
  511. else:
  512. raise Exception("未知拉流状态异常!")
  513. logger.info("实时进程任务完成,requestId:{}", self._msg.get("request_id"))
  514. except ServiceException as s:
  515. logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg,
  516. self._msg.get("request_id"))
  517. feedback = {"feedback": message_feedback(requestId, AnalysisStatus.FAILED.value,
  518. self._analyse_type,
  519. s.code,
  520. s.msg,
  521. analyse_time=TimeUtils.now_date_to_str())}
  522. except Exception as e:
  523. logger.error("服务异常: {}, requestId: {},", format_exc(), self._msg.get("request_id"))
  524. feedback = {"feedback": message_feedback(requestId, AnalysisStatus.FAILED.value,
  525. self._analyse_type,
  526. ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
  527. ExceptionType.SERVICE_INNER_EXCEPTION.value[1],
  528. analyse_time=TimeUtils.now_date_to_str())}
  529. finally:
  530. close_all_p(push_p, or_video_file, ai_video_file, requestId)
  531. if pullProcess is not None and pullProcess.is_alive():
  532. pullProcess.sendCommand({"command": "stop_image_hb"})
  533. self.waitPullStream(pullProcess)
  534. if feedback:
  535. putQueue(fb_queue, feedback, requestId)
  536. # 删除本地视频文件
  537. if self.__orFilePath is not None and exists(self.__orFilePath):
  538. logger.info("开始删除原视频, orFilePath: {}, requestId: {}", self.__orFilePath, requestId)
  539. os.remove(self.__orFilePath)
  540. logger.info("删除原视频成功, orFilePath: {}, requestId: {}", self.__orFilePath, requestId)
  541. if self.__aiFilePath is not None and exists(self.__aiFilePath):
  542. logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", self.__aiFilePath, requestId)
  543. os.remove(self.__aiFilePath)
  544. logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", self.__aiFilePath, requestId)
  545. class OfflineIntelligentRecognitionProcess(IntelligentRecognitionProcess):
  546. __slots__ = "__aiFilePath"
  547. def __init__(self, cfg):
  548. super(OfflineIntelligentRecognitionProcess, self).__init__(cfg)
  549. # 定义原视频、AI视频保存名称
  550. random_time = TimeUtils.now_date_to_str(TimeUtils.YMDHMSF)
  551. self.__aiFilePath = "%s%s%s%s%s" % (
  552. join(self._base_dir, self._context["video"]["file_path"]), random_time, "_on_ai_",
  553. self._msg.get("request_id"), ".mp4")
  554. def stop_task(self, pullProcess, analysisStatus):
  555. pullProcess.sendCommand({"command": "stop_pull_stream"})
  556. if not os.path.exists(self.__aiFilePath):
  557. logger.error("AI视频不存在!requestId:{}", self._msg.get("request_id"))
  558. raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0],
  559. ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1])
  560. aliyunVodSdk = ThAliyunVodSdk(self._base_dir, self._msg.get("request_id"), self._context["dsp"]["active"])
  561. upload_video_thread_ai = Common(self._context, aliyunVodSdk.get_play_url, self.__aiFilePath,
  562. "ai_offLine_%s" % self._msg.get("request_id"))
  563. upload_video_thread_ai.setDaemon(True)
  564. upload_video_thread_ai.start()
  565. ai_play_url = upload_video_thread_ai.get_result()
  566. if ai_play_url is None:
  567. logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", self._msg.get("request_id"))
  568. raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0],
  569. ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1])
  570. pullProcess.sendCommand({"command": "stop_image_hb"})
  571. self.waitPullStream(pullProcess)
  572. putQueue(self._fbQueue, {"feedback": message_feedback(self._msg.get("request_id"), analysisStatus,
  573. AnalysisType.OFFLINE.value,
  574. progress=success_progess,
  575. sign_url=ai_play_url,
  576. analyse_time=TimeUtils.now_date_to_str())},
  577. self._msg.get("request_id"))
  578. def start_pull_stream(self):
  579. pullProcess = OfflinePullVideoStreamProcess(self._msg, self._context, self.pullQueue, self._fbQueue,
  580. self._hbQueue, self._imageQueue, self._analyse_type, self._base_dir)
  581. pullProcess.daemon = True
  582. pullProcess.start()
  583. return pullProcess
  584. def run(self):
  585. # cv2tool = None
  586. requestId = self._msg.get("request_id")
  587. push_url = self._msg.get("push_url")
  588. eventQueue = self.eventQueue
  589. pull_queue = self.pullQueue
  590. image_queue = self._imageQueue
  591. hb_queue = self._hbQueue
  592. fb_queue = self._fbQueue
  593. pullProcess = None
  594. feedback = None
  595. push_p = None
  596. aiFilePath = self.__aiFilePath
  597. ai_video_file = None
  598. try:
  599. init_log(self._base_dir)
  600. enable_add_water = self._enable_add_water
  601. logo = self._logo
  602. task_status = [1, 1]
  603. frame_score = float(self._context["service"]["frame_score"])
  604. # 加载模型
  605. model_array = self.get_model()
  606. pullProcess = self.start_pull_stream()
  607. # cv2tool = Cv2Util(None, self._msg.get("push_url"), aiFilePath=self.__aiFilePath,
  608. # requestId=self._msg.get("request_id"))
  609. task_frame = None
  610. p_push_array = [0, 0]
  611. with ThreadPoolExecutor(max_workers=5) as t:
  612. with ThreadPoolExecutor(max_workers=2) as tt:
  613. with ThreadPoolExecutor(max_workers=15) as ttt:
  614. while True:
  615. if pullProcess is not None and not pullProcess.is_alive():
  616. logger.info("拉流进程停止异常, requestId: {}", requestId)
  617. raise Exception("拉流进程异常停止")
  618. # 检查是否获取到视频信息
  619. event_result = getNoBlockQueue(eventQueue)
  620. if event_result:
  621. cmdStr = event_result.get("command")
  622. if "stop_ex" == cmdStr:
  623. logger.info("离线任务开始停止, requestId: {}", requestId)
  624. pullProcess.sendCommand({"command": 'stop_image_hb'})
  625. feedback = {"feedback": message_feedback(requestId, AnalysisStatus.FAILED.value,
  626. self._analyse_type,
  627. ExceptionType.NO_RESOURCES.value[0],
  628. ExceptionType.NO_RESOURCES.value[1],
  629. analyse_time=TimeUtils.now_date_to_str())}
  630. self.waitPullStream(pullProcess)
  631. break
  632. if "stop" == cmdStr:
  633. logger.info("离线任务开始停止分析, requestId: {}", requestId)
  634. pullProcess.sendCommand({"command": 'stop_pull_stream'})
  635. frames = []
  636. status = None
  637. if task_frame is not None:
  638. frames, status = task_frame.result()
  639. task_frame = tt.submit(buildFrame, pull_queue, logo, enable_add_water, frame_score,
  640. model_array, task_status, ttt, requestId)
  641. if len(frames) == 0 and status is None:
  642. time.sleep(0.5)
  643. continue
  644. if len(frames) > 0:
  645. check = False
  646. for result in t.map(process, frames):
  647. if result is not None:
  648. frame_result, frame_merge, det_xywh = result
  649. write_ai_video_result = tt.submit(write_ai_video, frame_merge, aiFilePath,
  650. ai_video_file, frame_result[3],
  651. frame_result[4],
  652. requestId)
  653. push_p = push_video_stream(frame_merge, push_p, push_url,
  654. frame_result[3], frame_result[4], p_push_array,
  655. requestId)
  656. ai_video_file = write_ai_video_result.result()
  657. # frame_all, frame_merge = result
  658. # push_stream_result = tt.submit(cv2tool.push_stream, frame_merge)
  659. # write_ai_video_result = tt.submit(cv2tool.video_ai_write, frame_merge)
  660. # res = [push_stream_result, write_ai_video_result]
  661. # completed_results = wait(res, timeout=600, return_when=ALL_COMPLETED)
  662. # completed_futures = completed_results.done
  663. # for r in completed_futures:
  664. # if r.exception():
  665. # raise r.exception()
  666. if len(det_xywh) > 0:
  667. check = True
  668. putQueue(image_queue, {"image": (frame_result, det_xywh)}, requestId)
  669. if frame_result[2] % 400 == 0 and frame_result[2] <= frame_result[5]:
  670. task_process = str(format(float(frame_result[2]) / float(frame_result[5]),
  671. '.4f'))
  672. putQueue(hb_queue, {"hb_value": task_process}, requestId)
  673. if check:
  674. task_status[1] = 1
  675. if not check:
  676. task_status[1] = 0
  677. if status is None:
  678. continue
  679. if status[0] == "1":
  680. raise ServiceException(status[1], status[2])
  681. elif status[0] == "2":
  682. close_all_p(push_p, None, ai_video_file, requestId)
  683. self.stop_task(pullProcess, AnalysisStatus.SUCCESS.value)
  684. break
  685. elif status[0] == "3":
  686. close_all_p(push_p, None, ai_video_file, requestId)
  687. self.stop_task(pullProcess, AnalysisStatus.TIMEOUT.value)
  688. break
  689. elif status[0] == "9":
  690. close_all_p(push_p, None, ai_video_file, requestId)
  691. logger.info("离线任务正常结束:requestId: {}", requestId)
  692. self.stop_task(pullProcess, AnalysisStatus.SUCCESS.value)
  693. break
  694. logger.info("离线进程任务完成,requestId:{}", self._msg.get("request_id"))
  695. except ServiceException as s:
  696. logger.error("服务异常,异常编号:{}, 异常描述:{}, requestId:{}", s.code, s.msg, self._msg.get("request_id"))
  697. feedback = {"feedback": message_feedback(requestId, AnalysisStatus.FAILED.value,
  698. AnalysisType.OFFLINE.value,
  699. s.code,
  700. s.msg,
  701. analyse_time=TimeUtils.now_date_to_str())}
  702. except Exception as e:
  703. logger.error("服务异常: {}, requestId:{}", format_exc(), requestId)
  704. feedback = {"feedback": message_feedback(requestId, AnalysisStatus.FAILED.value,
  705. AnalysisType.OFFLINE.value,
  706. ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
  707. ExceptionType.SERVICE_INNER_EXCEPTION.value[1],
  708. analyse_time=TimeUtils.now_date_to_str())}
  709. finally:
  710. close_all_p(push_p, None, ai_video_file, requestId)
  711. if pullProcess is not None and pullProcess.is_alive():
  712. pullProcess.sendCommand({"command": "stop_image_hb"})
  713. self.waitPullStream(pullProcess)
  714. if feedback:
  715. putQueue(fb_queue, feedback, requestId)
  716. # 删除本地视频文件
  717. if self.__aiFilePath is not None and exists(self.__aiFilePath):
  718. logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", self.__aiFilePath, requestId)
  719. os.remove(self.__aiFilePath)
  720. logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", self.__aiFilePath, requestId)
  721. '''
  722. 图片识别
  723. '''
  724. class PhotosIntelligentRecognitionProcess(IntelligentRecognitionProcess):
  725. __slots__ = ()
  726. def epidemic_prevention(self, imageUrl, mod, orc):
  727. try:
  728. model_conf, model_type_code = mod
  729. image = url2Array(imageUrl)
  730. model_param = model_conf[2]
  731. model_param[0] = image
  732. dataBack = MODEL_CONFIG[model_type_code][3](model_param)
  733. # [frame, device, model, par, img_type, requestId]
  734. img_type = model_param[4]
  735. allowedList = model_conf[1]
  736. if img_type == 'plate':
  737. carCode = ''
  738. if dataBack is None or dataBack.get("plateImage") is None or len(dataBack.get("plateImage")) == 0:
  739. result = orc.license_plate_recognition(image, self._msg.get("request_id"))
  740. score = ''
  741. if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0:
  742. logger.error("车牌识别为空: {}", result)
  743. carCode = ''
  744. else:
  745. for word in result.get("words_result"):
  746. if word is not None and word.get("number") is not None:
  747. if len(carCode) == 0:
  748. carCode = word.get("number")
  749. else:
  750. carCode = carCode + "," + word.get("number")
  751. else:
  752. result = orc.license_plate_recognition(dataBack.get("plateImage")[0], self._msg.get("request_id"))
  753. score = dataBack.get("plateImage")[1]
  754. if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0:
  755. result = orc.license_plate_recognition(image, self._msg.get("request_id"))
  756. if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0:
  757. logger.error("车牌识别为空: {}", result)
  758. carCode = ''
  759. else:
  760. for word in result.get("words_result"):
  761. if word is not None and word.get("number") is not None:
  762. if len(carCode) == 0:
  763. carCode = word.get("number")
  764. else:
  765. carCode = carCode + "," + word.get("number")
  766. else:
  767. for word in result.get("words_result"):
  768. if word is not None and word.get("number") is not None:
  769. if len(carCode) == 0:
  770. carCode = word.get("number")
  771. else:
  772. carCode = carCode + "," + word.get("number")
  773. if len(carCode) > 0:
  774. plate_result = {'type': str(3), 'modelCode': model_type_code, 'carUrl': imageUrl,
  775. 'carCode': carCode,
  776. 'score': score}
  777. putQueue(self._fbQueue, {"feedback": message_feedback(self._msg.get("request_id"),
  778. AnalysisStatus.RUNNING.value,
  779. AnalysisType.IMAGE.value, "", "",
  780. '',
  781. imageUrl,
  782. imageUrl,
  783. str(model_type_code),
  784. str(3),
  785. TimeUtils.now_date_to_str(),
  786. json.dumps(plate_result))},
  787. self._msg.get("request_id"))
  788. if img_type == 'code':
  789. if dataBack is None or dataBack.get("type") is None:
  790. return
  791. # 行程码
  792. if dataBack.get("type") == 1 and 1 in allowedList:
  793. # 手机号
  794. if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0:
  795. phoneNumberRecognition = ''
  796. phone_score = ''
  797. else:
  798. phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0],
  799. self._msg.get("request_id"))
  800. phone_score = dataBack.get("phoneNumberImage")[1]
  801. if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0:
  802. logger.error("手机号识别为空: {}", phone)
  803. phoneNumberRecognition = ''
  804. else:
  805. phoneNumberRecognition = phone.get("words_result")
  806. if dataBack.get("cityImage") is None or len(dataBack.get("cityImage")) == 0:
  807. cityRecognition = ''
  808. city_score = ''
  809. else:
  810. city = orc.universal_text_recognition(dataBack.get("cityImage")[0], self._msg.get("request_id"))
  811. city_score = dataBack.get("cityImage")[1]
  812. if city is None or city.get("words_result") is None or len(city.get("words_result")) == 0:
  813. logger.error("城市识别为空: {}", city)
  814. cityRecognition = ''
  815. else:
  816. cityRecognition = city.get("words_result")
  817. if len(phoneNumberRecognition) > 0 or len(cityRecognition) > 0:
  818. trip_result = {'type': str(1),
  819. 'modelCode': model_type_code,
  820. 'imageUrl': imageUrl,
  821. 'phoneNumberRecognition': phoneNumberRecognition,
  822. 'phone_sorce': phone_score,
  823. 'cityRecognition': cityRecognition,
  824. 'city_score': city_score}
  825. putQueue(self._fbQueue, {"feedback": message_feedback(self._msg.get("request_id"),
  826. AnalysisStatus.RUNNING.value,
  827. AnalysisType.IMAGE.value, "", "",
  828. '',
  829. imageUrl,
  830. imageUrl,
  831. str(model_type_code),
  832. str(1),
  833. TimeUtils.now_date_to_str(),
  834. json.dumps(trip_result))},
  835. self._msg.get("request_id"))
  836. if dataBack.get("type") == 2 and 2 in allowedList:
  837. if dataBack.get("nameImage") is None or len(dataBack.get("nameImage")) == 0:
  838. nameRecognition = ''
  839. name_score = ''
  840. else:
  841. name = orc.universal_text_recognition(dataBack.get("nameImage")[0], self._msg.get("request_id"))
  842. name_score = dataBack.get("nameImage")[1]
  843. if name is None or name.get("words_result") is None or len(name.get("words_result")) == 0:
  844. logger.error("名字识别为空: {}", name)
  845. nameRecognition = ''
  846. else:
  847. nameRecognition = name.get("words_result")
  848. if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0:
  849. phoneNumberRecognition = ''
  850. phone_score = ''
  851. else:
  852. phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0],
  853. self._msg.get("request_id"))
  854. phone_score = dataBack.get("phoneNumberImage")[1]
  855. if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0:
  856. logger.error("手机号识别为空: {}", phone)
  857. phoneNumberRecognition = ''
  858. else:
  859. phoneNumberRecognition = phone.get("words_result")
  860. if dataBack.get("hsImage") is None or len(dataBack.get("hsImage")) == 0:
  861. hsRecognition = ''
  862. hs_score = ''
  863. else:
  864. hs = orc.universal_text_recognition(dataBack.get("hsImage")[0], self._msg.get("request_id"))
  865. hs_score = dataBack.get("hsImage")[1]
  866. if hs is None or hs.get("words_result") is None or len(hs.get("words_result")) == 0:
  867. logger.error("核酸识别为空: {}", hs)
  868. hsRecognition = ''
  869. else:
  870. hsRecognition = hs.get("words_result")
  871. if len(nameRecognition) > 0 or len(phoneNumberRecognition) > 0 or len(hsRecognition) > 0:
  872. healthy_result = {'type': str(2),
  873. 'modelCode': model_type_code,
  874. 'imageUrl': imageUrl,
  875. 'color': dataBack.get("color"),
  876. 'nameRecognition': nameRecognition,
  877. 'name_score': name_score,
  878. 'phoneNumberRecognition': phoneNumberRecognition,
  879. 'phone_score': phone_score,
  880. 'hsRecognition': hsRecognition,
  881. 'hs_score': hs_score}
  882. putQueue(self._fbQueue, {"feedback": message_feedback(self._msg.get("request_id"),
  883. AnalysisStatus.RUNNING.value,
  884. AnalysisType.IMAGE.value, "", "",
  885. '',
  886. imageUrl,
  887. imageUrl,
  888. str(model_type_code),
  889. str(2),
  890. TimeUtils.now_date_to_str(),
  891. json.dumps(healthy_result))},
  892. self._msg.get("request_id"))
  893. except ServiceException as s:
  894. raise s
  895. except Exception as e:
  896. logger.error("模型分析异常: {}, requestId: {}", format_exc(), self._msg.get("request_id"))
  897. raise e
  898. '''
  899. # 防疫模型
  900. '''
  901. def epidemicPrevention(self, imageUrls, mod, tt):
  902. orc = OcrBaiduSdk(self._base_dir)
  903. obj_list = []
  904. for imageUrl in imageUrls:
  905. obj = tt.submit(self.epidemic_prevention, imageUrl, mod, orc)
  906. obj_list.append(obj)
  907. completed_results = wait(obj_list, timeout=120, return_when=ALL_COMPLETED)
  908. completed_futures = completed_results.done
  909. for r in completed_futures:
  910. if r.exception():
  911. raise r.exception()
  912. def image_recognition(self, imageUrl, mod, aliyunOssSdk):
  913. try:
  914. frame_score = float(self._context["service"]["frame_score"])
  915. model_conf, model_type_code = mod
  916. model_param = model_conf[2]
  917. image = url2Array(imageUrl)
  918. model_param[0] = image
  919. label_method = MODEL_CONFIG[model_type_code][2]
  920. if label_method:
  921. label_method(int(image.shape[1]), model_param)
  922. # 调用AI模型
  923. p_result, timeOut = MODEL_CONFIG[model_type_code][3](model_param)
  924. if p_result is None or len(p_result) < 4:
  925. return
  926. if self._enable_add_water:
  927. image = add_water_pic(image, self._logo, self._msg.get("request_id"))
  928. ai_result_list = p_result[2]
  929. if ai_result_list is not None and len(ai_result_list) > 0:
  930. allowedList = model_conf[1]
  931. label_arraylist = model_param[4]
  932. rainbows = model_param[5]
  933. if allowedList is not None:
  934. det_xywh = {}
  935. for ai_result in ai_result_list:
  936. detect_targets_code = int(ai_result[0])
  937. score = ai_result[-1]
  938. # 如果检测目标在识别任务中,继续处理
  939. if detect_targets_code in allowedList and score >= frame_score:
  940. label_array = label_arraylist[detect_targets_code]
  941. color = rainbows[detect_targets_code]
  942. # [float(cls_c), xc,yc,w,h, float(conf_c)]
  943. # [ cls,[ (x0,y0),(x1,y1),(x2,y2),(x3,y3) ],score]
  944. if not isinstance(ai_result[1], (list, tuple, np.ndarray)):
  945. xc = int(ai_result[1])
  946. yc = int(ai_result[2])
  947. x2 = int(ai_result[3])
  948. y2 = int(ai_result[4])
  949. tl = (xc, yc)
  950. tr = (x2, yc)
  951. br = (x2, y2)
  952. bl = (xc, y2)
  953. box = [tl, tr, br, bl]
  954. else:
  955. box = ai_result[1]
  956. cd = det_xywh.get(detect_targets_code)
  957. if cd is None or len(cd) == 0:
  958. frame = copy.deepcopy(image)
  959. draw_painting_joint(box, frame, label_array, score, color, "leftTop")
  960. det_xywh[detect_targets_code] = {
  961. "modelCode": str(model_type_code),
  962. "detectTargetCode": str(detect_targets_code),
  963. "frame": frame
  964. }
  965. else:
  966. frame = cd.get("frame")
  967. draw_painting_joint(box, frame, label_array, score, color, "leftTop")
  968. det_xywh[detect_targets_code]['frame'] = frame
  969. for target_list in list(det_xywh.keys()):
  970. if det_xywh.get(target_list) is not None and len(det_xywh.get(target_list)) > 0:
  971. ai_result, ai_image = cv2.imencode(".jpg", det_xywh.get(target_list).get("frame"))
  972. ai_image_name = self.build_image_name(det_xywh.get(target_list).get("detectTargetCode"))
  973. aliyunOssSdk.sync_upload_file(ai_image_name, ai_image.tobytes())
  974. putQueue(self._fbQueue, {"feedback": message_feedback(self._msg.get("request_id"),
  975. AnalysisStatus.RUNNING.value,
  976. self._analyse_type, "", "",
  977. '',
  978. imageUrl,
  979. ai_image_name,
  980. str(model_type_code),
  981. det_xywh.get(target_list).get(
  982. "detectTargetCode"),
  983. TimeUtils.now_date_to_str())},
  984. self._msg.get("request_id"))
  985. except ServiceException as s:
  986. raise s
  987. except Exception as e:
  988. logger.error("模型分析异常: {}, requestId: {}", format_exc(), self._msg.get("request_id"))
  989. raise e
  990. def publicIdentification(self, imageUrls, mod, aliyunOssSdk, tt):
  991. obj_list = []
  992. for imageUrl in imageUrls:
  993. obj = tt.submit(self.image_recognition, imageUrl, mod, aliyunOssSdk)
  994. obj_list.append(obj)
  995. completed_results = wait(obj_list, timeout=120, return_when=ALL_COMPLETED)
  996. completed_futures = completed_results.done
  997. for r in completed_futures:
  998. if r.exception():
  999. raise r.exception()
  1000. '''
  1001. 1. imageUrls: 图片url数组,多张图片
  1002. 2. mod: 模型对象
  1003. 3. model_type_code: 模型编号
  1004. 4. t: 线程池对象
  1005. 5. aliyunOssSdk: 阿里云sdk
  1006. '''
  1007. def baiduRecognition(self, imageUrls, mod, tt, ttt, aliyunOssSdk):
  1008. obj_list = []
  1009. for imageUrl in imageUrls:
  1010. obj = tt.submit(self.baidu_recognition, imageUrl, mod, aliyunOssSdk, ttt)
  1011. obj_list.append(obj)
  1012. completed_results = wait(obj_list, timeout=120, return_when=ALL_COMPLETED)
  1013. completed_futures = completed_results.done
  1014. for r in completed_futures:
  1015. if r.exception():
  1016. raise r.exception()
  1017. def baidu_recognition(self, imageUrl, mod, aliyunOssSdk, ttt):
  1018. try:
  1019. # (modeType, allowedList, model_param, rainbows)
  1020. model_conf, model_type_code = mod
  1021. allowedList = model_conf[1]
  1022. rainbows = model_conf[3]
  1023. # 检查检测目标
  1024. if allowedList is None or len(allowedList) == 0:
  1025. raise ServiceException(ExceptionType.THE_DETECTION_TARGET_CANNOT_BE_EMPTY.value[0],
  1026. ExceptionType.THE_DETECTION_TARGET_CANNOT_BE_EMPTY.value[1])
  1027. # 图片转数组
  1028. img = url2Array(imageUrl)
  1029. base_dir = self._base_dir
  1030. fontsize = int(img.shape[1] / 1920 * 40)
  1031. names = [VehicleEnum.CAR.value[1], VehicleEnum.TRICYCLE.value[1], VehicleEnum.MOTORBIKE.value[1],
  1032. VehicleEnum.CARPLATE.value[1], VehicleEnum.TRUCK.value[1], VehicleEnum.BUS.value[1]]
  1033. label_array = get_label_arrays(names, rainbows, fontSize=fontsize,
  1034. fontPath=join(base_dir, FONTPATH))
  1035. person = ['人']
  1036. person_label = get_label_arrays(person, rainbows, fontSize=fontsize,
  1037. fontPath=join(base_dir, FONTPATH))
  1038. obj_list = []
  1039. for target in allowedList:
  1040. reuslt = ttt.submit(self.baidu_method, mod, target, imageUrl, img, aliyunOssSdk, label_array,
  1041. person_label)
  1042. obj_list.append(reuslt)
  1043. completed_results = wait(obj_list, timeout=120, return_when=ALL_COMPLETED)
  1044. completed_futures = completed_results.done
  1045. for r in completed_futures:
  1046. if r.exception():
  1047. raise r.exception()
  1048. except ServiceException as s:
  1049. raise s
  1050. except Exception as e:
  1051. logger.error("百度AI分析异常: {}, requestId: {}", format_exc(), self._msg.get("request_id"))
  1052. raise e
  1053. def build_image_name(self, target):
  1054. random_num = TimeUtils.now_date_to_str(TimeUtils.YMDHMSF)
  1055. time_now = TimeUtils.now_date_to_str("%Y-%m-%d-%H-%M-%S")
  1056. image_format = "{base_dir}/{time_now}_frame-{current_frame}-{last_frame}_type_{random_num}-{mode_type}" \
  1057. "-{target}-{requestId}_{image_type}.jpg"
  1058. image_name = image_format.format(
  1059. base_dir=self._msg.get("results_base_dir"),
  1060. time_now=time_now,
  1061. current_frame=str(0),
  1062. last_frame=str(0),
  1063. random_num=random_num,
  1064. mode_type=AnalysisType.IMAGE.value,
  1065. target=target,
  1066. requestId=self._msg.get("request_id"),
  1067. image_type="AI")
  1068. return image_name
  1069. def baidu_method(self, mod, target, imageUrl, img, aliyunOssSdk, label_arrays, person_label):
  1070. # (modeType, allowedList, model_param, rainbows)
  1071. model_conf, model_type_code = mod
  1072. model_param = model_conf[2]
  1073. model_param[0] = target
  1074. model_param[1] = imageUrl
  1075. rainbows = model_conf[3]
  1076. # [target, url, aipImageClassifyClient, aipBodyAnalysisClient, requestId]
  1077. result = MODEL_CONFIG[model_type_code][3](model_param)
  1078. if target == BaiduModelTarget.VEHICLE_DETECTION.value[1] and result is not None:
  1079. vehicleInfo = result.get("vehicle_info")
  1080. if vehicleInfo is not None and len(vehicleInfo) > 0:
  1081. aiIamge = None
  1082. copy_frame = img.copy()
  1083. for i, info in enumerate(vehicleInfo):
  1084. value = VehicleEnumVALUE.get(info.get("type"))
  1085. target_num = value.value[2]
  1086. label_array = label_arrays[target_num]
  1087. color = rainbows[target_num]
  1088. if value is None:
  1089. logger.error("车辆识别出现未支持的目标类型!type:{}, requestId:{}", info.get("type"),
  1090. self._msg.get("request_id"))
  1091. return
  1092. left_top = (int(info.get("location").get("left")), int(info.get("location").get("top")))
  1093. right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")),
  1094. int(info.get("location").get("top")))
  1095. right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")),
  1096. int(info.get("location").get("top")) + int(info.get("location").get("height")))
  1097. left_bottom = (int(info.get("location").get("left")),
  1098. int(info.get("location").get("top")) + int(info.get("location").get("height")))
  1099. box = [left_top, right_top, right_bottom, left_bottom]
  1100. score = "%.2f" % info.get("probability")
  1101. if self._enable_add_water:
  1102. copy_frame = add_water_pic(copy_frame, self._logo, self._msg.get("request_id"))
  1103. draw_painting_joint(box, copy_frame, label_array, float(score), color, "leftTop")
  1104. aiIamge = copy_frame
  1105. info["id"] = str(i)
  1106. if aiIamge is not None and len(aiIamge) > 0:
  1107. ai_image_name = self.build_image_name(target)
  1108. ai_result, ai_image = cv2.imencode(".jpg", aiIamge)
  1109. aliyunOssSdk.sync_upload_file(ai_image_name, ai_image.tobytes())
  1110. result["type"] = str(target)
  1111. result["modelCode"] = model_type_code
  1112. putQueue(self._fbQueue, {"feedback": message_feedback(self._msg.get("request_id"),
  1113. AnalysisStatus.RUNNING.value,
  1114. AnalysisType.IMAGE.value, "", "",
  1115. '',
  1116. imageUrl,
  1117. ai_image_name,
  1118. str(model_type_code),
  1119. str(target),
  1120. TimeUtils.now_date_to_str(),
  1121. json.dumps(result))},
  1122. self._msg.get("request_id"))
  1123. # 人体识别
  1124. if target == BaiduModelTarget.HUMAN_DETECTION.value[1] and result is not None:
  1125. personInfo = result.get("person_info")
  1126. personNum = result.get("person_num")
  1127. if personNum is not None and personNum > 0 and personInfo is not None and len(personInfo) > 0:
  1128. personImage = None
  1129. copy_frame = img.copy()
  1130. for i, info in enumerate(personInfo):
  1131. left_top = (int(info.get("location").get("left")), int(info.get("location").get("top")))
  1132. right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")),
  1133. int(info.get("location").get("top")))
  1134. right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")),
  1135. int(info.get("location").get("top")) + int(info.get("location").get("height")))
  1136. left_bottom = (int(info.get("location").get("left")),
  1137. int(info.get("location").get("top")) + int(info.get("location").get("height")))
  1138. box = [left_top, right_top, right_bottom, left_bottom]
  1139. score = "%.2f" % info.get("location").get("score")
  1140. if self._enable_add_water:
  1141. copy_frame = add_water_pic(copy_frame, self._logo, self._msg.get("request_id"))
  1142. draw_painting_joint(box, copy_frame, person_label[0], float(score), rainbows[0], "leftTop")
  1143. personImage = copy_frame
  1144. info["id"] = str(i)
  1145. if personImage is not None and len(personImage) > 0:
  1146. ai_image_name = self.build_image_name(target)
  1147. ai_result, ai_image = cv2.imencode(".jpg", personImage)
  1148. aliyunOssSdk.sync_upload_file(ai_image_name, ai_image.tobytes())
  1149. result["type"] = str(target)
  1150. result["modelCode"] = model_type_code
  1151. putQueue(self._fbQueue, {"feedback": message_feedback(self._msg.get("request_id"),
  1152. AnalysisStatus.RUNNING.value,
  1153. AnalysisType.IMAGE.value, "", "",
  1154. '',
  1155. imageUrl,
  1156. ai_image_name,
  1157. str(model_type_code),
  1158. str(target),
  1159. TimeUtils.now_date_to_str(),
  1160. json.dumps(result))},
  1161. self._msg.get("request_id"))
  1162. # 人流量
  1163. if target == BaiduModelTarget.PEOPLE_COUNTING.value[1] and result is not None:
  1164. base64Image = result.get("image")
  1165. if base64Image is not None and len(base64Image) > 0:
  1166. baiduImage = base64.b64decode(base64Image)
  1167. ai_image_name = self.build_image_name(target)
  1168. aliyunOssSdk.sync_upload_file(ai_image_name, baiduImage)
  1169. result["type"] = str(target)
  1170. result["modelCode"] = model_type_code
  1171. del result["image"]
  1172. putQueue(self._fbQueue, {"feedback": message_feedback(self._msg.get("request_id"),
  1173. AnalysisStatus.RUNNING.value,
  1174. AnalysisType.IMAGE.value, "", "",
  1175. '',
  1176. imageUrl,
  1177. ai_image_name,
  1178. str(model_type_code),
  1179. str(target),
  1180. TimeUtils.now_date_to_str(),
  1181. json.dumps(result))},
  1182. self._msg.get("request_id"))
  1183. def run(self):
  1184. with ThreadPoolExecutor(max_workers=5) as t:
  1185. with ThreadPoolExecutor(max_workers=10) as tt:
  1186. with ThreadPoolExecutor(max_workers=5) as ttt:
  1187. try:
  1188. requestId = self._msg.get("request_id")
  1189. # 初始化日志
  1190. init_log(self._base_dir)
  1191. model_array = self.get_model()
  1192. imageUrls = self._msg.get("image_urls")
  1193. aliyunOssSdk = AliyunOssSdk(self._base_dir, requestId)
  1194. aliyunOssSdk.get_oss_bucket()
  1195. task_list = []
  1196. for model in model_array:
  1197. # 百度模型逻辑
  1198. if model[1] == ModelType.BAIDU_MODEL.value[1]:
  1199. result = t.submit(self.baiduRecognition, imageUrls, model, tt, ttt, aliyunOssSdk)
  1200. task_list.append(result)
  1201. # 防疫模型
  1202. elif model[1] == ModelType.EPIDEMIC_PREVENTION_MODEL.value[1]:
  1203. result = t.submit(self.epidemicPrevention, imageUrls, model, tt)
  1204. task_list.append(result)
  1205. # 车牌模型
  1206. elif model[1] == ModelType.PLATE_MODEL.value[1]:
  1207. result = t.submit(self.epidemicPrevention, imageUrls, model, tt)
  1208. task_list.append(result)
  1209. else:
  1210. result = t.submit(self.publicIdentification, imageUrls, model, aliyunOssSdk, tt)
  1211. task_list.append(result)
  1212. if len(task_list) > 0:
  1213. completed_results = wait(task_list, timeout=120, return_when=ALL_COMPLETED)
  1214. completed_futures = completed_results.done
  1215. for r in completed_futures:
  1216. if r.exception():
  1217. raise r.exception()
  1218. logger.info("图片进程任务完成,requestId:{}", self._msg.get("request_id"))
  1219. putQueue(self._fbQueue,
  1220. {"feedback": message_feedback(self._msg.get("request_id"),
  1221. AnalysisStatus.SUCCESS.value,
  1222. AnalysisType.IMAGE.value,
  1223. progress=success_progess,
  1224. analyse_time=TimeUtils.now_date_to_str())},
  1225. self._msg.get("request_id"))
  1226. except ServiceException as s:
  1227. logger.error("图片分析异常,异常编号:{}, 异常描述:{}, requestId:{}", s.code, s.msg,
  1228. self._msg.get("request_id"))
  1229. putQueue(self._fbQueue,
  1230. {"feedback": message_feedback(self._msg.get("request_id"), AnalysisStatus.FAILED.value,
  1231. self._analyse_type,
  1232. s.code,
  1233. s.msg,
  1234. analyse_time=TimeUtils.now_date_to_str())},
  1235. self._msg.get("request_id"))
  1236. except Exception as e:
  1237. logger.error("图片分析异常: {}, requestId:{}", format_exc(),
  1238. self._msg.get("request_id"))
  1239. putQueue(self._fbQueue,
  1240. {"feedback": message_feedback(self._msg.get("request_id"), AnalysisStatus.FAILED.value,
  1241. self._analyse_type,
  1242. ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
  1243. ExceptionType.SERVICE_INNER_EXCEPTION.value[1],
  1244. analyse_time=TimeUtils.now_date_to_str())},
  1245. self._msg.get("request_id"))
  1246. '''
  1247. 录屏进程
  1248. '''
  1249. class ScreenRecordingProcess(Process):
  1250. __slots__ = [
  1251. '_fbQueue',
  1252. '_eventQueue',
  1253. '_hbQueue',
  1254. '_pullQueue',
  1255. '_context',
  1256. '_msg',
  1257. '_pic',
  1258. '_service_timeout',
  1259. '_orFilePath',
  1260. '_analysisType',
  1261. '_base_dir',
  1262. '_gpu_name'
  1263. ]
  1264. def __init__(self, param):
  1265. super().__init__()
  1266. # Param(self.__fbQueue, msg, analysisType, self.__base_dir, self.__context, self.__gpu_name)
  1267. ######################################### 初始化变量 #########################################
  1268. self._fbQueue = param.fbqueue
  1269. self.eventQueue = Queue()
  1270. self._hbQueue = Queue()
  1271. self.pullQueue = Queue(200)
  1272. self._context = param.context
  1273. self._msg = param.msg
  1274. self._analysisType = param.analyse_type
  1275. self._base_dir = param.base_dir
  1276. self._gpu_name = param.gpu_name
  1277. self._pic = PictureWaterMark(requestId=self._msg.get("request_id"))
  1278. self._service_timeout = self._context["service"]["timeout"]
  1279. random_time = TimeUtils.now_date_to_str(TimeUtils.YMDHMSF)
  1280. self._orFilePath = "%s%s%s%s%s" % (self._context["video"]["file_path"], random_time, "_or_",
  1281. self._msg.get("request_id"), ".mp4")
  1282. self.sendhbMessage(RecordingStatus.RECORDING_WAITING.value[0])
  1283. def clearPullQueue(self):
  1284. while True:
  1285. if self.pullQueue.qsize() > 0:
  1286. self.getPullQueue()
  1287. else:
  1288. break
  1289. def sendEvent(self, eBody):
  1290. self.eventQueue.put(eBody)
  1291. # 获取下一个事件
  1292. def getEvent(self):
  1293. eBody = None
  1294. try:
  1295. eBody = self.eventQueue.get(block=False)
  1296. return eBody
  1297. except Exception as e:
  1298. pass
  1299. return eBody
  1300. def getPullQueue(self):
  1301. eBody = None
  1302. try:
  1303. eBody = self.pullQueue.get(block=False)
  1304. return eBody
  1305. except Exception as e:
  1306. pass
  1307. return eBody
  1308. # 推送执行结果
  1309. def sendResult(self, result):
  1310. self._fbQueue.put(result)
  1311. def sendhbMessage(self, status, error_code="", error_msg="", recording_video_url=""):
  1312. self.sendResult({"recording": recording_feedback(self._msg.get("request_id"),
  1313. status,
  1314. error_code,
  1315. error_msg,
  1316. recording_video_url)})
  1317. def start_pull_stream_thread(self):
  1318. pullThread = RecordingPullStreamThread(self._msg, self._context, self.pullQueue, self._fbQueue)
  1319. pullThread.setDaemon(True)
  1320. pullThread.start()
  1321. return pullThread
  1322. # 停止任务方法
  1323. def stop_task(self, hb, status):
  1324. if not os.path.exists(self._orFilePath):
  1325. logger.error("原视频不存在!requestId:{}", self._msg.get("request_id"))
  1326. raise ServiceException(ExceptionType.OR_VIDEO_DO_NOT_EXEIST_EXCEPTION.value[0],
  1327. ExceptionType.OR_VIDEO_DO_NOT_EXEIST_EXCEPTION.value[1])
  1328. aliyunVodSdk = ThAliyunVodSdk(self._base_dir, self._msg.get("request_id"), self._context["dsp"]["active"])
  1329. upload_video_thread_or = Common(self._context, aliyunVodSdk.get_play_url, self._orFilePath,
  1330. "or_recording_%s" % self._msg.get("request_id"))
  1331. upload_video_thread_or.setDaemon(True)
  1332. upload_video_thread_or.start()
  1333. or_play_url = upload_video_thread_or.get_result()
  1334. if or_play_url is None:
  1335. logger.error("原视频上传VOD失败!原视频播放地址:{}, requestId: {}", or_play_url, self._msg.get("request_id"))
  1336. raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0],
  1337. ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1])
  1338. hb.sendHbQueue({"command": "stop"})
  1339. hb.join(20)
  1340. self.sendhbMessage(status, "", "", or_play_url)
  1341. def recordingFrame(self, cv2tool):
  1342. frames = []
  1343. status = None
  1344. for i in range(self.pullQueue.qsize()):
  1345. frame_result = self.getPullQueue()
  1346. if frame_result is None:
  1347. continue
  1348. if frame_result.get("status") == '4':
  1349. cv2tool.getFrameConfig(int(frame_result.get("fps")), int(frame_result.get("width")),
  1350. int(frame_result.get("height")))
  1351. frames.append((frame_result))
  1352. else:
  1353. status = frame_result
  1354. return frames, status
  1355. def start_hb_thread(self):
  1356. hb = RecordingHeartbeat(self._fbQueue, self._hbQueue, self._msg.get("request_id"))
  1357. hb.setDaemon(True)
  1358. hb.start()
  1359. return hb
  1360. def run(self):
  1361. cv2tool = None
  1362. recording = None
  1363. pullThread = None
  1364. status = True
  1365. hb = None
  1366. try:
  1367. # 程序开始时间
  1368. init_log(self._base_dir)
  1369. pullThread = self.start_pull_stream_thread()
  1370. cv2tool = Cv2Util(orFilePath=self._orFilePath, requestId=self._msg.get("request_id"))
  1371. hb = self.start_hb_thread()
  1372. task_frame = None
  1373. with ThreadPoolExecutor(max_workers=6) as t:
  1374. while True:
  1375. if status and not pullThread.is_alive():
  1376. logger.info("录屏拉流线程停止异常, requestId: {}", self._msg.get("request_id"))
  1377. raise Exception("录屏拉流线程异常停止")
  1378. if not hb.is_alive():
  1379. logger.info("录屏心跳线程异常停止, requestId: {}", self._msg.get("request_id"))
  1380. raise Exception("录屏心跳线程异常停止")
  1381. eBody = self.getEvent()
  1382. if eBody is not None and len(eBody) > 0:
  1383. cmdStr = eBody.get("command")
  1384. # 接收到停止指令
  1385. if 'stop' == cmdStr:
  1386. logger.info("录屏任务开始停止, requestId: {}", self._msg.get("request_id"))
  1387. pullThread.sendCommand({"command": "stop"})
  1388. frames = []
  1389. status = None
  1390. if task_frame is not None:
  1391. frames, status = task_frame.result()
  1392. task_frame = t.submit(self.recordingFrame, cv2tool)
  1393. if len(frames) == 0 and status is None:
  1394. time.sleep(0.02)
  1395. continue
  1396. if frames is not None and len(frames) > 0:
  1397. for frame in frames:
  1398. cv2tool.video_or_write(frame[0].get("frame"))
  1399. if status is None:
  1400. continue
  1401. if status.get("status") == "1":
  1402. raise ServiceException(status.get("error").get("code"), status.get("error").get("msg"))
  1403. elif status.get("status") == "2":
  1404. cv2tool.close()
  1405. self.stop_task(hb, RecordingStatus.RECORDING_SUCCESS.value[0])
  1406. pullThread.join(10)
  1407. break
  1408. else:
  1409. raise Exception("未知拉流状态异常!")
  1410. logger.info("录屏线程任务完成,requestId:{}", self._msg.get("request_id"))
  1411. except ServiceException as s:
  1412. logger.error("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, self._msg.get("request_id"))
  1413. recording = {"recording": recording_feedback(self._msg.get("request_id"),
  1414. RecordingStatus.RECORDING_FAILED.value[0],
  1415. s.code,
  1416. s.msg)}
  1417. except Exception:
  1418. logger.error("服务异常: {}, requestId: {},", format_exc(), self._msg.get("request_id"))
  1419. recording = {"recording": recording_feedback(self._msg.get("request_id"),
  1420. RecordingStatus.RECORDING_FAILED.value[0],
  1421. ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
  1422. ExceptionType.SERVICE_INNER_EXCEPTION.value[1])}
  1423. finally:
  1424. if cv2tool:
  1425. cv2tool.close()
  1426. if hb:
  1427. hb.sendHbQueue({"command": "stop"})
  1428. hb.join(20)
  1429. self.clearPullQueue()
  1430. if pullThread is not None and pullThread.is_alive():
  1431. pullThread.sendCommand({"command": "stop"})
  1432. pullThread.join(20)
  1433. if recording:
  1434. self.sendResult(recording)
  1435. # 删除本地视频文件
  1436. if self._orFilePath is not None and os.path.exists(self._orFilePath):
  1437. logger.info("开始删除原视频, orFilePath: {}, requestId: {}", self._orFilePath,
  1438. self._msg.get("request_id"))
  1439. os.remove(self._orFilePath)
  1440. logger.info("删除原视频成功, orFilePath: {}, requestId: {}", self._orFilePath,
  1441. self._msg.get("request_id"))