对frame增加try以接住异常

This commit is contained in:
zqc
2026-02-03 09:16:13 +08:00
parent f6ea6082f3
commit 7f47735e0d

View File

@@ -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 algorithm.checkpoint.npu_yolo_pose_onnx import YOLOv8_Pose_ONNX # Pose 专用模型
from yolox.tracker.byte_tracker import BYTETracker from yolox.tracker.byte_tracker import BYTETracker
from utils.logger import get_logger
logger = get_logger(__name__)
# ========================= 配置区 ========================= # ========================= 配置区 =========================
# Kadian 模型路径与ROI可根据实际情况修改 # Kadian 模型路径与ROI可根据实际情况修改
@@ -114,15 +116,15 @@ class KadianDetector:
self.frame_buffer_limit_person = int(self.TIME_TOLERANCE_PERSON * self.fps) self.frame_buffer_limit_person = int(self.TIME_TOLERANCE_PERSON * self.fps)
self.frame_buffer_limit_car = int(self.TIME_TOLERANCE_CAR * self.fps) self.frame_buffer_limit_car = int(self.TIME_TOLERANCE_CAR * self.fps)
print(f"\n超参数设置:") logger.info(f"\n超参数设置:")
print(f" FPS: {self.fps:.2f}") logger.info(f" FPS: {self.fps:.2f}")
print(f" 判定 'Only One' / 'Nobody' 需连续: {self.frame_thresh_one}") logger.info(f" 判定 'Only One' / 'Nobody' 需连续: {self.frame_thresh_one}")
print(f" 判定 'Trunk Checked' 需累计检测: {self.frame_thresh_trunk_valid}") logger.info(f" 判定 'Trunk Checked' 需累计检测: {self.frame_thresh_trunk_valid}")
print(f" 判定 'Phone Detected' 需累计检测: {self.frame_thresh_phone}") logger.info(f" 判定 'Phone Detected' 需累计检测: {self.frame_thresh_phone}")
print(f" 手机丢失缓冲帧数: {self.frame_buffer_phone}") logger.info(f" 手机丢失缓冲帧数: {self.frame_buffer_phone}")
print(f" 判定 'Uniform Invalid' 需连续检测: {self.frame_thresh_uniform}") logger.info(f" 判定 'Uniform Invalid' 需连续检测: {self.frame_thresh_uniform}")
print(f" 制服合规恢复缓冲帧数: {self.frame_buffer_uniform}") logger.info(f" 制服合规恢复缓冲帧数: {self.frame_buffer_uniform}")
print(f" 判定 'Too Fast' (视为Nobody) 最小停留: {self.frame_thresh_car_min_duration}") logger.info(f" 判定 'Too Fast' (视为Nobody) 最小停留: {self.frame_thresh_car_min_duration}")
self.current_frame_idx = 0 self.current_frame_idx = 0
@@ -260,7 +262,7 @@ class KadianDetector:
elif cls_id == 3: elif cls_id == 3:
dets_roles.append("phone") 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)) 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],
[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) frame = YOLOv8_Pose_ONNX.draw_keypoints(frame, pose_results)
# ========= 绘制 ROI ========= # ========= 绘制 ROI =========
@@ -285,7 +287,7 @@ class KadianDetector:
current_trunks = [] # (cx, cy) current_trunks = [] # (cx, cy)
for t in tracks: for t in tracks:
# print("t: {}".format(t)) # logger.debug("t: {}".format(t))
tid = t.track_id tid = t.track_id
# cls_id = -1 # cls_id = -1
@@ -319,7 +321,7 @@ class KadianDetector:
cls_id = 2 cls_id = 2
elif role == "phone": elif role == "phone":
cls_id = 3 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) x1, y1, x2, y2 = map(int, t.tlbr)
@@ -498,12 +500,12 @@ class KadianDetector:
# 情况1通过时间太短 -> 归类为 Nobody (Too Fast) # 情况1通过时间太短 -> 归类为 Nobody (Too Fast)
if duration_frames < self.frame_thresh_car_min_duration: 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) self.fast_pass_alerts[car_id] = self.current_frame_idx + int(3.0 * self.fps)
# 情况2时间够长但没检查后备箱 -> Unchecked Trunk # 情况2时间够长但没检查后备箱 -> Unchecked Trunk
elif not car_info['is_checked']: 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) self.unchecked_trunk_alerts[car_id] = self.current_frame_idx + int(3.0 * self.fps)
del self.roi_car_registry[car_id] del self.roi_car_registry[car_id]
@@ -698,69 +700,75 @@ class FrameProcessorWorker(threading.Thread):
except queue.Empty: except queue.Empty:
continue 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] = {}
# 筛选出符合推送条件的action5秒内未推送过
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: try:
img_b64 = self._encode_base64(result_img) cam_id = item["camera_id"]
except Exception as e: ts = item["timestamp"]
print(f"[ERROR] Encode image failed: {e}") frame = item["frame"]
img_b64 = None
if img_b64 is not None: # 抽帧控制
# 将abnormal_actions对象数组转换为字符串数组 if ts - self.last_ts.get(cam_id, 0) < target_interval:
# action_names = [action_info['action'] for action_info in push_actions] self.raw_queue.task_done()
continue
self.last_ts[cam_id] = ts
msg = { # 获取检测器实例
"msg_type": "frame", if cam_id not in self.kadian_detectors:
"camera_id": 0, self.kadian_detectors[cam_id] = KadianDetector()
"timestamp": ts, detector = self.kadian_detectors[cam_id]
# "result_type": action_names,
"result_type": push_actions, # 执行检测
"image_base64": img_b64, 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] = {}
# 筛选出符合推送条件的action5秒内未推送过
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: try:
self.ws_queue.put(msg, timeout=1.0) img_b64 = self._encode_base64(result_img)
# if push_actions and len(push_actions) > 0: except Exception as e:
# self.ws_queue_2.put(msg, timeout=1.0) logger.error(f"[ERROR] Encode image failed: {e}")
except queue.Full: img_b64 = None
print("[WARN] ws_send_queue full, drop frame message")
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()