diff --git a/biz/checkpoint/checkpoint_biz.py b/biz/checkpoint/checkpoint_biz.py index bd0d816..ed5efc9 100644 --- a/biz/checkpoint/checkpoint_biz.py +++ b/biz/checkpoint/checkpoint_biz.py @@ -12,6 +12,8 @@ from algorithm.checkpoint.npu_yolo_onnx_person_car_phone import YOLOv8_ONNX from algorithm.checkpoint.npu_yolo_pose_onnx import YOLOv8_Pose_ONNX # Pose 专用模型 from yolox.tracker.byte_tracker import BYTETracker +from utils.logger import get_logger +logger = get_logger(__name__) # ========================= 配置区 ========================= # Kadian 模型路径与ROI(可根据实际情况修改) @@ -114,15 +116,15 @@ class KadianDetector: self.frame_buffer_limit_person = int(self.TIME_TOLERANCE_PERSON * self.fps) self.frame_buffer_limit_car = int(self.TIME_TOLERANCE_CAR * self.fps) - print(f"\n超参数设置:") - print(f" FPS: {self.fps:.2f}") - print(f" 判定 'Only One' / 'Nobody' 需连续: {self.frame_thresh_one} 帧") - print(f" 判定 'Trunk Checked' 需累计检测: {self.frame_thresh_trunk_valid} 帧") - print(f" 判定 'Phone Detected' 需累计检测: {self.frame_thresh_phone} 帧") - print(f" 手机丢失缓冲帧数: {self.frame_buffer_phone} 帧") - print(f" 判定 'Uniform Invalid' 需连续检测: {self.frame_thresh_uniform} 帧") - print(f" 制服合规恢复缓冲帧数: {self.frame_buffer_uniform} 帧") - print(f" 判定 'Too Fast' (视为Nobody) 最小停留: {self.frame_thresh_car_min_duration} 帧") + logger.info(f"\n超参数设置:") + logger.info(f" FPS: {self.fps:.2f}") + logger.info(f" 判定 'Only One' / 'Nobody' 需连续: {self.frame_thresh_one} 帧") + logger.info(f" 判定 'Trunk Checked' 需累计检测: {self.frame_thresh_trunk_valid} 帧") + logger.info(f" 判定 'Phone Detected' 需累计检测: {self.frame_thresh_phone} 帧") + logger.info(f" 手机丢失缓冲帧数: {self.frame_buffer_phone} 帧") + logger.info(f" 判定 'Uniform Invalid' 需连续检测: {self.frame_thresh_uniform} 帧") + logger.info(f" 制服合规恢复缓冲帧数: {self.frame_buffer_uniform} 帧") + logger.info(f" 判定 'Too Fast' (视为Nobody) 最小停留: {self.frame_thresh_car_min_duration} 帧") self.current_frame_idx = 0 @@ -260,7 +262,7 @@ class KadianDetector: elif cls_id == 3: dets_roles.append("phone") - # print(f'dets_roles: {dets_roles}') + # logger.debug(f'dets_roles: {dets_roles}') dets = np.array(dets_for_tracker, dtype=np.float32) if len(dets_for_tracker) else np.empty((0, 5)) @@ -269,7 +271,7 @@ class KadianDetector: [self.height, self.width], [self.height, self.width] ) - # print("tracks: {}".format(tracks)) + # logger.debug("tracks: {}".format(tracks)) # 绘制骨骼 frame = YOLOv8_Pose_ONNX.draw_keypoints(frame, pose_results) # ========= 绘制 ROI ========= @@ -285,7 +287,7 @@ class KadianDetector: current_trunks = [] # (cx, cy) for t in tracks: - # print("t: {}".format(t)) + # logger.debug("t: {}".format(t)) tid = t.track_id # cls_id = -1 @@ -319,7 +321,7 @@ class KadianDetector: cls_id = 2 elif role == "phone": cls_id = 3 - # print("tid: {}, role: {}, cls: {}".format(tid, role,cls_id)) + # logger.debug("tid: {}, role: {}, cls: {}".format(tid, role,cls_id)) x1, y1, x2, y2 = map(int, t.tlbr) @@ -498,12 +500,12 @@ class KadianDetector: # 情况1:通过时间太短 -> 归类为 Nobody (Too Fast) if duration_frames < self.frame_thresh_car_min_duration: - print(f"ALARM: Car {car_id} passed too fast -> Regarded as Nobody Checked!") + logger.warning(f"ALARM: Car {car_id} passed too fast -> Regarded as Nobody Checked!") self.fast_pass_alerts[car_id] = self.current_frame_idx + int(3.0 * self.fps) # 情况2:时间够长,但没检查后备箱 -> Unchecked Trunk elif not car_info['is_checked']: - print(f"ALARM: Car {car_id} left without checking trunk!") + logger.warning(f"ALARM: Car {car_id} left without checking trunk!") self.unchecked_trunk_alerts[car_id] = self.current_frame_idx + int(3.0 * self.fps) del self.roi_car_registry[car_id] @@ -698,69 +700,75 @@ class FrameProcessorWorker(threading.Thread): except queue.Empty: continue - cam_id = item["camera_id"] - ts = item["timestamp"] - frame = item["frame"] - - # 抽帧控制 - if ts - self.last_ts.get(cam_id, 0) < target_interval: - self.raw_queue.task_done() - continue - self.last_ts[cam_id] = ts - - # 获取检测器实例 - if cam_id not in self.kadian_detectors: - self.kadian_detectors[cam_id] = KadianDetector() - detector = self.kadian_detectors[cam_id] - - # 执行检测 - result = detector.process_frame(frame.copy(), cam_id, ts) - - result_img = result["image"] - result_type = result["alerts"] - # print(f"alerts: {result_type}") - - # ========= 核心修改:过滤5秒内重复的action ========= - # 初始化当前摄像头的推送时间记录 - if cam_id not in self.last_alert_push_time: - self.last_alert_push_time[cam_id] = {} - - # 筛选出符合推送条件的action(5秒内未推送过) - push_actions = [] - current_time = time.time() - for alert in result_type: - action = alert['action'] - last_push = self.last_alert_push_time[cam_id].get(action, 0) - # 检查是否超过推送间隔 - if current_time - last_push >= ALERT_PUSH_INTERVAL: - push_actions.append(action) - # 更新该action的最后推送时间 - self.last_alert_push_time[cam_id][action] = current_time - - # 通过 WebSocket 发送帧结果 try: - img_b64 = self._encode_base64(result_img) - except Exception as e: - print(f"[ERROR] Encode image failed: {e}") - img_b64 = None + cam_id = item["camera_id"] + ts = item["timestamp"] + frame = item["frame"] - if img_b64 is not None: - # 将abnormal_actions对象数组转换为字符串数组 - # action_names = [action_info['action'] for action_info in push_actions] + # 抽帧控制 + if ts - self.last_ts.get(cam_id, 0) < target_interval: + self.raw_queue.task_done() + continue + self.last_ts[cam_id] = ts - msg = { - "msg_type": "frame", - "camera_id": 0, - "timestamp": ts, - # "result_type": action_names, - "result_type": push_actions, - "image_base64": img_b64, - } + # 获取检测器实例 + if cam_id not in self.kadian_detectors: + self.kadian_detectors[cam_id] = KadianDetector() + detector = self.kadian_detectors[cam_id] + + # 执行检测 + result = detector.process_frame(frame.copy(), cam_id, ts) + + result_img = result["image"] + result_type = result["alerts"] + # logger.debug(f"alerts: {result_type}") + + # ========= 核心修改:过滤5秒内重复的action ========= + # 初始化当前摄像头的推送时间记录 + if cam_id not in self.last_alert_push_time: + self.last_alert_push_time[cam_id] = {} + + # 筛选出符合推送条件的action(5秒内未推送过) + push_actions = [] + current_time = time.time() + for alert in result_type: + action = alert['action'] + last_push = self.last_alert_push_time[cam_id].get(action, 0) + # 检查是否超过推送间隔 + if current_time - last_push >= ALERT_PUSH_INTERVAL: + push_actions.append(action) + # 更新该action的最后推送时间 + self.last_alert_push_time[cam_id][action] = current_time + + # 通过 WebSocket 发送帧结果 try: - self.ws_queue.put(msg, timeout=1.0) - # if push_actions and len(push_actions) > 0: - # self.ws_queue_2.put(msg, timeout=1.0) - except queue.Full: - print("[WARN] ws_send_queue full, drop frame message") + img_b64 = self._encode_base64(result_img) + except Exception as e: + logger.error(f"[ERROR] Encode image failed: {e}") + img_b64 = None - self.raw_queue.task_done() + if img_b64 is not None: + # 将abnormal_actions对象数组转换为字符串数组 + # action_names = [action_info['action'] for action_info in push_actions] + + msg = { + "msg_type": "frame", + "camera_id": 0, + "timestamp": ts, + # "result_type": action_names, + "result_type": push_actions, + "image_base64": img_b64, + } + try: + self.ws_queue.put(msg, timeout=1.0) + # if push_actions and len(push_actions) > 0: + # self.ws_queue_2.put(msg, timeout=1.0) + except queue.Full: + logger.warning("[WARN] ws_send_queue full, drop frame message") + + except Exception as e: + logger.error(f"[ERROR] Frame processing failed for camera {cam_id if 'cam_id' in locals() else 'unknown'}: {e}") + logger.exception("Exception details:") # 打印完整的堆栈跟踪 + # 继续处理下一帧,不要退出循环 + finally: + self.raw_queue.task_done()