添加我的代码

This commit is contained in:
2026-04-10 21:43:08 +08:00
parent 4259774365
commit e7e2b86cd7

View File

@@ -2,243 +2,446 @@ import cv2
import numpy as np
import time
import requests
from collections import deque
from biz.base_frame_processor import BaseFrameProcessorWorker
from algorithm.common.npu_yolo_onnx_person_car_phone import YOLOv8_ONNX
from yolox.tracker.byte_tracker import BYTETracker
from common.constants import MODEL_ROOT_PATH
# ========================= 走廊场景专属配置 =========================
DETECT_MODEL_PATH = 'YOLO_Weight/kanshousuo.onnx' # 犯人检测onnx模型路径
INPUT_SIZE = 640 # 模型输入尺寸
RTSP_FPS = 10 # 视频流目标FPS
ALERT_PUSH_INTERVAL = 5 # 相同报警5秒内仅推送1次
MODEL_PATH = 'YOLO_Weight/kanshousuo.onnx'
INPUT_SIZE = 640
RTSP_FPS = 10
ALERT_PUSH_INTERVAL = 10
ALERT_PUSH_URL = "http://123.57.151.210:10000/picenter/websocket/test/process"
# 消失判定中心点在ROI内消失后持续无检测的帧数1.0秒,可微调)
ROI_LOST_FRAMES_THRESH = int(0.5 * RTSP_FPS) # todo: 从frame改为时间
ROI_LOST_FRAMES_THRESH = int(1 * RTSP_FPS)
# ========================= 默认ROI区域配置当config.yaml未配置时使用 =========================
DEFAULT_DOOR_ROIS = {
"left_door_1": {
"points": [[0.195, 0.242], [0.265, 0.17], [0.3, 0.63], [0.248, 0.8]],
"color": [255, 0, 0]
}
# ========================= ROI区域配置 =========================
ROI_CONFIG = {
"left": [[0.195, 0.245], [0.42, 0], [0.421, 0.185], [0.248, 0.8]],
"right": [[0.575, 0.], [0.81, 0.22], [0.78, 0.8], [0.575, 0.185]],
}
# ==================================================================================
class PrisonerDoorDetector:
def __init__(self, params=None):
self.params = params or {}
# 0. 从params解析ROI配置无则使用默认值
door_rois_config = self.params.get('door_rois', DEFAULT_DOOR_ROIS)
self.roi_config = {}
self.roi_colors = {}
for door_name, door_cfg in door_rois_config.items():
self.roi_config[door_name] = door_cfg['points']
self.roi_colors[door_name] = tuple(door_cfg['color'])
model_path = self.params.get('model_path')
if model_path:
full_model_path = f"{MODEL_ROOT_PATH}/{model_path}"
else:
full_model_path = DETECT_MODEL_PATH
# 1. 加载YOLO模型 - 降低阈值提高检测率
self.detector = YOLOv8_ONNX(
full_model_path,
conf_threshold=0.5, # 置信度阈值,可根据模型精度调整
iou_threshold=0.45, # IOU阈值
MODEL_PATH,
conf_threshold=0.57, # 进一步降低,捕获更多检测
iou_threshold=0.4,
input_size=INPUT_SIZE
)
# 2. 初始化ByteTracker跟踪器(适配走廊单/多犯人跟踪)
# 2. ByteTracker参数优化
class TrackerArgs:
track_thresh = 0.25
track_buffer = 20 # 减小缓冲避免跟踪漂移
match_thresh = 0.75
track_thresh = 0.65 # 更低的跟踪阈值
track_buffer = 60 # 更大的缓冲,应对短暂消失
match_thresh = 0.5 # 更宽松的匹配
mot20 = False
self.tracker = BYTETracker(TrackerArgs(), frame_rate=RTSP_FPS)
# 3. 状态变量初始化
self.last_alert_time = 0.0 # 最后报警时间(防重复推送)
# 犯人跟踪信息:{track_id: {'is_cx_in_roi': 中心点是否在ROI, 'lost_frames': 消失帧数, 'lost_roi': 消失的ROI名称, 'last_cxcy': 最后中心点坐标}}
self.prisoner_track_info = {}
self.frame_width = 0 # 帧宽度(动态获取)
self.frame_height = 0 # 帧高度(动态获取)
self.roi_abs_cache = {} # ROI绝对坐标缓存{roi_name: np.int32数组}
# 3. 状态变量
self.last_alert_time = 0.0
self.frame_width = 0
self.frame_height = 0
self.roi_abs_cache = {}
self.entry_frame_cache = {}
# 【核心改进】基于位置的跟踪状态管理
self.active_targets = {} # {target_id: {...}}
self.next_target_id = 0
self.position_history = {} # {target_id: deque of positions}
# 距离阈值(用于匹配检测框和已有目标)
self.distance_threshold = 100 # 像素距离
def compute_center_distance(self, box1, box2):
"""计算两个框中心点的欧氏距离"""
cx1 = (box1[0] + box1[2]) / 2
cy1 = (box1[1] + box1[3]) / 2
cx2 = (box2[0] + box2[2]) / 2
cy2 = (box2[1] + box2[3]) / 2
return np.sqrt((cx1 - cx2) ** 2 + (cy1 - cy2) ** 2)
def compute_iou(self, boxA, boxB):
"""IOU计算:匹配跟踪框与犯人检测框,过滤非犯人目标"""
"""IOU计算"""
xA = max(boxA[0], boxB[0])
yA = max(boxA[1], boxB[1])
xB = min(boxA[2], boxB[2])
yB = min(boxA[3], boxB[3])
interW = max(0, xB - xA)
interH = max(0, yB - yA)
interArea = interW * interH
boxAArea = (boxA[2] - boxA[0]) * (boxA[3] - boxA[1])
boxBArea = (boxB[2] - boxB[0]) * (boxB[3] - boxB[1])
boxAArea = max(0, (boxA[2] - boxA[0]) * (boxA[3] - boxA[1]))
boxBArea = max(0, (boxB[2] - boxB[0]) * (boxB[3] - boxB[1]))
unionArea = boxAArea + boxBArea - interArea
return interArea / unionArea if unionArea > 0 else 0.0
def _get_roi_abs(self, roi_name):
"""相对坐标转绝对像素坐标适配当前帧分辨率OpenCV要求int32"""
if roi_name not in self.roi_config:
"""相对坐标转绝对像素坐标"""
if roi_name not in ROI_CONFIG:
return None
roi_rel = np.array(self.roi_config[roi_name], dtype=np.float64)
roi_rel = np.array(ROI_CONFIG[roi_name], dtype=np.float64)
roi_abs = roi_rel * np.array([self.frame_width, self.frame_height])
return roi_abs.astype(np.int32)
def is_cxcy_in_roi(self, cx, cy):
"""判断犯人框**中心点(cx,cy)** 是否在任意ROI内,返回:(是否在ROI, 所在ROI名称)"""
"""判断中心点是否在ROI内"""
for roi_name, roi_abs in self.roi_abs_cache.items():
# OpenCV点在多边形内判定>=0 表示在内部/边上
if cv2.pointPolygonTest(roi_abs, (cx, cy), False) >= 0:
return (True, roi_name)
return (False, "outside")
# def push_alert(self, camera_id, track_id, lost_roi, last_cxcy, timestamp):
# """报警推送带频率限制携带消失ROI、最后中心点坐标"""
# current_time = time.time()
# if current_time - self.last_alert_time < ALERT_PUSH_INTERVAL:
# return False
# # 构造报警信息(可根据平台要求扩展字段)
# alert_info = {
# "camera_id": camera_id,
# "alert_type": "prisoner_cx_disappear_in_roi",
# "prisoner_track_id": track_id,
# "disappear_roi": lost_roi,
# "last_cx": round(last_cxcy[0], 2),
# "last_cy": round(last_cxcy[1], 2),
# "timestamp": timestamp,
# "details": f"犯人框中心点在{lost_roi}区域内消失,触发报警"
# }
# # 推送报警请求
# try:
# requests.post(ALERT_PUSH_URL, json=alert_info, timeout=3)
# print(f"[报警成功] {alert_info}")
# self.last_alert_time = current_time
# return True
# except Exception as e:
# print(f"[报警失败] 原因:{str(e)}")
# return False
def match_detection_to_target(self, detection_box, detection_conf):
"""
【核心】将检测框匹配到已有目标
返回: (matched_target_id, match_score)
"""
best_match_id = None
best_match_score = 0
det_center = np.array([(detection_box[0] + detection_box[2]) / 2,
(detection_box[1] + detection_box[3]) / 2])
for target_id, target_info in self.active_targets.items():
# 计算与目标最后已知位置的距离
last_box = target_info['last_box']
last_center = np.array([(last_box[0] + last_box[2]) / 2,
(last_box[1] + last_box[3]) / 2])
distance = np.linalg.norm(det_center - last_center)
# 计算IOU如果目标最近刚更新
time_since_update = time.time() - target_info['last_update_time']
iou_score = self.compute_iou(detection_box, last_box) if time_since_update < 1.0 else 0
# 综合评分:距离近 + IOU高
distance_score = max(0, 1 - distance / self.distance_threshold)
match_score = 0.3 * distance_score + 0.7 * iou_score
# 考虑位置预测(如果目标在移动中)
if target_id in self.position_history and len(self.position_history[target_id]) >= 2:
# 简单的线性预测
hist = list(self.position_history[target_id])
if len(hist) >= 2:
velocity = hist[-1] - hist[-2]
predicted_pos = last_center + velocity
pred_distance = np.linalg.norm(det_center - predicted_pos)
pred_score = max(0, 1 - pred_distance / self.distance_threshold)
match_score = 0.7 * match_score + 0.3 * pred_score
if match_score > best_match_score and match_score > 0.3: # 阈值可调
best_match_score = match_score
best_match_id = target_id
return best_match_id, best_match_score
def push_alert(self, camera_id, target_id, lost_roi, last_cxcy, timestamp, entry_frame):
"""报警推送"""
current_time = time.time()
if current_time - self.last_alert_time < ALERT_PUSH_INTERVAL:
return False
_, frame_encoded = cv2.imencode('.jpg', entry_frame)
frame_base64 = frame_encoded.tobytes()
alert_info = {
"camera_id": camera_id,
"alert_type": "prisoner_cx_disappear_in_roi",
"prisoner_track_id": target_id,
"disappear_roi": lost_roi,
"last_cx": round(last_cxcy[0], 2),
"last_cy": round(last_cxcy[1], 2),
"timestamp": timestamp,
"entry_frame_base64": frame_base64,
"details": f"犯人框中心点在{lost_roi}区域内消失"
}
try:
requests.post(ALERT_PUSH_URL, json=alert_info, timeout=3)
print(f"[报警成功] target_id={target_id}, roi={lost_roi}")
self.last_alert_time = current_time
return True
except Exception as e:
print(f"[报警失败] {str(e)}")
return False
def process_frame(self, frame, camera_id: int, timestamp: float) -> dict:
"""
核心帧处理:
1. 绘制5个ROI区域 2. 检测+跟踪犯人 3. 判定中心点是否在ROI内
4. 中心点在ROI内消失则累计帧数达到阈值触发报警
"""
"""核心帧处理 - 增强检测版"""
self.frame_height, self.frame_width = frame.shape[:2]
current_frame_alerts = [] # 本帧报警信息
current_frame_alerts = []
frame_copy = frame.copy()
current_time = time.time()
# ========================= 1. 初始化ROI绝对坐标并绘制ROI =========================
# ========================= 1. 绘制ROI区域 =========================
roi_colors = {"left": (255, 0, 0), "right": (255, 0, 0)}
self.roi_abs_cache.clear()
for roi_name in self.roi_config:
for roi_name, _ in ROI_CONFIG.items():
roi_abs = self._get_roi_abs(roi_name)
if roi_abs is None:
continue
self.roi_abs_cache[roi_name] = roi_abs
# 绘制ROI多边形闭合+ ROI名称标签
roi_draw = roi_abs.reshape((-1, 1, 2)) # OpenCV绘制要求形状 (n,1,2)
color = self.roi_colors.get(roi_name, (255, 255, 255))
cv2.polylines(frame, [roi_draw], isClosed=True, color=color, thickness=2)
roi_draw = roi_abs.reshape((-1, 1, 2))
cv2.polylines(frame, [roi_draw], isClosed=True, color=roi_colors[roi_name], thickness=2)
cv2.putText(frame, roi_name, (roi_abs[0][0], roi_abs[0][1] - 5),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
cv2.FONT_HERSHEY_SIMPLEX, 0.5, roi_colors[roi_name], 2)
# ========================= 2. 模型推理:仅提取犯人检测框 =========================
# ========================= 2. 模型推理 =========================
detect_results = self.detector(frame)
prisoner_dets_xyxy = [] # 仅存犯人检测框 [x1,y1,x2,y2]
dets_for_tracker = [] # 跟踪器输入 [x1,y1,x2,y2,conf]
prisoner_detections = []
if detect_results:
for det in detect_results:
x1, y1, x2, y2, conf, cls_id = det
dets_for_tracker.append([x1, y1, x2, y2, conf])
# 替换为你模型中「犯人」的实际类别ID此处默认cls_id=1
if cls_id == 1:
prisoner_dets_xyxy.append([x1, y1, x2, y2])
# 确保坐标在图像范围内
x1 = max(0, min(x1, self.frame_width - 1))
y1 = max(0, min(y1, self.frame_height - 1))
x2 = max(0, min(x2, self.frame_width - 1))
y2 = max(0, min(y2, self.frame_height - 1))
# ========================= 3. 目标跟踪:更新犯人跟踪结果 =========================
dets_np = np.array(dets_for_tracker, dtype=np.float32) if dets_for_tracker else np.empty((0, 5))
track_results = self.tracker.update(dets_np, [self.frame_height, self.frame_width],
[self.frame_height, self.frame_width])
if cls_id == 1 and x2 > x1 and y2 > y1 and (x2 - x1) * (y2 - y1) > 100: # 过滤太小的框
prisoner_detections.append([x1, y1, x2, y2, conf, cls_id])
# ========================= 3. ByteTracker跟踪 =========================
prisoner_det_boxes = np.array(
[[x1, y1, x2, y2, conf] for x1, y1, x2, y2, conf, cls_id in prisoner_detections],
dtype=np.float32) if prisoner_detections else np.empty((0, 5))
if len(prisoner_det_boxes) > 0:
track_results = self.tracker.update(
prisoner_det_boxes,
[self.frame_height, self.frame_width],
[self.frame_height, self.frame_width]
)
else:
track_results = []
# ========================= 4. 【核心改进】融合跟踪和检测 =========================
# 4.1 先处理跟踪结果
tracked_detections = {} # {track_id: detection_box}
used_det_indices = set()
# ========================= 4. 遍历跟踪结果判定犯人中心点是否在ROI =========================
current_prisoner_tids = set() # 本帧存在的犯人track_id
for track in track_results:
track_id = track.track_id
track_box = list(map(float, track.tlbr)) # 跟踪框 [x1,y1,x2,y2]
# IOU匹配过滤非犯人目标仅保留真正的犯人
is_prisoner = False
for p_box in prisoner_dets_xyxy:
if self.compute_iou(track_box, p_box) > 0.3:
is_prisoner = True
break
if not is_prisoner:
t_box = [float(x) for x in track.tlbr]
# 寻找匹配的检测框
best_iou = 0.0 # 最低阈值
best_det_idx = -1
for det_idx, det in enumerate(prisoner_detections):
if det_idx in used_det_indices:
continue
iou = self.compute_iou(t_box, det[:4])
if iou > best_iou:
best_iou = iou
best_det_idx = det_idx
# 计算犯人框**中心点坐标**(核心判定依据)
cx = (track_box[0] + track_box[2]) / 2
cy = (track_box[1] + track_box[3]) / 2
# 判定中心点是否在ROI内返回(是否在ROI, 所在ROI名称)
is_cx_in_roi, current_roi = self.is_cxcy_in_roi(cx, cy)
# 更新犯人跟踪信息记录中心点状态、所在ROI、最后坐标重置消失帧数
self.prisoner_track_info[track_id] = {
"is_cx_in_roi": is_cx_in_roi,
"lost_frames": 0,
"lost_roi": current_roi,
"last_cxcy": (cx, cy)
if best_det_idx != -1:
# 跟踪框有对应的检测框,使用检测框(更准确)
tracked_detections[f"track_{track_id}"] = {
'box': prisoner_detections[best_det_idx][:4],
'conf': prisoner_detections[best_det_idx][4],
'source': 'tracked'
}
used_det_indices.add(best_det_idx)
else:
# 跟踪框没有对应的检测框,但仍保留跟踪框
tracked_detections[f"track_{track_id}"] = {
'box': t_box,
'conf': 0.5, # 给个中等置信度
'source': 'track_only'
}
current_prisoner_tids.add(track_id)
# 绘制犯人框+中心点+状态标签(可视化调试)
x1, y1, x2, y2 = map(int, track_box)
cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), 2) # 红色犯人框
cv2.circle(frame, (int(cx), int(cy)), 5, (0, 255, 255), -1) # 黄色中心点
cv2.putText(frame, f"Prisoner_{track_id}({current_roi})", (x1, y1 - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
# 4.2 处理未被跟踪的检测框
for det_idx, det in enumerate(prisoner_detections):
if det_idx not in used_det_indices:
tracked_detections[f"det_{det_idx}"] = {
'box': det[:4],
'conf': det[4],
'source': 'det_only'
}
# ========================= 5. 匹配到已有目标 =========================
current_target_ids = set()
matched_det_keys = set()
for det_key, det_info in tracked_detections.items():
det_box = det_info['box']
det_conf = det_info['conf']
# 计算中心点
cx = (det_box[0] + det_box[2]) / 2
cy = (det_box[1] + det_box[3]) / 2
# 匹配到已有目标
matched_target_id, match_score = self.match_detection_to_target(det_box, det_conf)
if matched_target_id is not None and match_score > 0.3:
# 更新已有目标
target_id = matched_target_id
target_info = self.active_targets[target_id]
# 更新位置历史
if target_id not in self.position_history:
self.position_history[target_id] = deque(maxlen=10)
self.position_history[target_id].append(np.array([cx, cy]))
# 判断是否在ROI内
is_cx_in_roi, current_roi = self.is_cxcy_in_roi(cx, cy)
# 首次进入ROI缓存帧
if not target_info.get('in_roi', False) and is_cx_in_roi:
self.entry_frame_cache[target_id] = frame_copy.copy()
target_info['lost_frames'] = 0
# 更新目标信息
target_info.update({
'last_box': det_box,
'last_cxcy': (cx, cy),
'last_conf': det_conf,
'last_update_time': current_time,
'in_roi': is_cx_in_roi,
'current_roi': current_roi if is_cx_in_roi else target_info.get('current_roi', 'outside'),
'detection_source': det_info['source']
})
current_target_ids.add(target_id)
matched_det_keys.add(det_key)
else:
# 创建新目标
target_id = self.next_target_id
self.next_target_id += 1
is_cx_in_roi, current_roi = self.is_cxcy_in_roi(cx, cy)
self.active_targets[target_id] = {
'first_seen': current_time,
'last_box': det_box,
'last_cxcy': (cx, cy),
'last_conf': det_conf,
'last_update_time': current_time,
'in_roi': is_cx_in_roi,
'current_roi': current_roi if is_cx_in_roi else 'outside',
'lost_frames': 0,
'detection_source': det_info['source']
}
self.position_history[target_id] = deque(maxlen=10)
self.position_history[target_id].append(np.array([cx, cy]))
if is_cx_in_roi:
self.entry_frame_cache[target_id] = frame_copy.copy()
current_target_ids.add(target_id)
matched_det_keys.add(det_key)
# ========================= 6. 处理消失和报警 =========================
for target_id in list(self.active_targets.keys()):
target_info = self.active_targets[target_id]
if target_id not in current_target_ids:
# 目标在当前帧未出现
if target_info['in_roi']:
# 在ROI内消失
target_info['lost_frames'] += 1
if target_info['lost_frames'] >= ROI_LOST_FRAMES_THRESH:
# 触发报警
entry_frame = self.entry_frame_cache.get(target_id, frame_copy)
self.push_alert(
camera_id=camera_id,
target_id=target_id,
lost_roi=target_info['current_roi'],
last_cxcy=target_info['last_cxcy'],
timestamp=timestamp,
entry_frame=entry_frame
)
# ========================= 5. 核心判定中心点在ROI内消失则报警 =========================
for track_id in list(self.prisoner_track_info.keys()):
if track_id not in current_prisoner_tids:
# 犯人本帧消失,获取其最后状态
track_info = self.prisoner_track_info[track_id]
# 仅处理「**中心点原本在ROI内**」的消失情况
if track_info["is_cx_in_roi"]:
track_info["lost_frames"] += 1 # 累计消失帧数
# 消失帧数达到阈值,触发报警
if track_info["lost_frames"] >= ROI_LOST_FRAMES_THRESH:
# self.push_alert(
# camera_id=camera_id,
# track_id=track_id,
# lost_roi=track_info["lost_roi"],
# last_cxcy=track_info["last_cxcy"],
# timestamp=timestamp
# )
# 记录本帧报警信息
current_frame_alerts.append({
"time": timestamp,
"camera_id": camera_id,
"action": "Indoor Violation",
"prisoner_track_id": track_id,
"disappear_roi": track_info["lost_roi"],
"last_cx": round(track_info["last_cxcy"][0], 2),
"last_cy": round(track_info["last_cxcy"][1], 2)
"action": "prisoner_cx_disappear_in_door",
"prisoner_track_id": target_id,
"disappear_roi": target_info['current_roi'],
"last_cx": round(target_info['last_cxcy'][0], 2),
"last_cy": round(target_info['last_cxcy'][1], 2)
})
del self.prisoner_track_info[track_id] # 报警后清除状态,避免重复触发
else:
del self.prisoner_track_info[track_id] # 中心点不在ROI的消失直接清除
# ========================= 6. 绘制辅助信息摄像头ID、在押犯人数 =========================
# 清理
del self.active_targets[target_id]
if target_id in self.position_history:
del self.position_history[target_id]
if target_id in self.entry_frame_cache:
del self.entry_frame_cache[target_id]
else:
# 不在ROI内消失直接清理
del self.active_targets[target_id]
if target_id in self.position_history:
del self.position_history[target_id]
if target_id in self.entry_frame_cache:
del self.entry_frame_cache[target_id]
else:
# 目标仍在但可能已离开ROI
if not target_info['in_roi']:
target_info['lost_frames'] = 0
# ========================= 7. 清理超时目标 =========================
timeout_threshold = 5.0 # 5秒无更新就清理
for target_id in list(self.active_targets.keys()):
if current_time - self.active_targets[target_id]['last_update_time'] > timeout_threshold:
del self.active_targets[target_id]
if target_id in self.position_history:
del self.position_history[target_id]
if target_id in self.entry_frame_cache:
del self.entry_frame_cache[target_id]
# ========================= 8. 绘制可视化 =========================
for target_id, target_info in self.active_targets.items():
box = target_info['last_box']
cx, cy = target_info['last_cxcy']
in_roi = target_info['in_roi']
current_roi = target_info['current_roi']
source = target_info.get('detection_source', 'unknown')
# 根据状态选择颜色
if in_roi:
color = (0, 0, 255) # 绿色在ROI内
else:
color = (0, 255, 0) # 橙色不在ROI内
# 根据来源选择线型
thickness = 3 if source == 'tracked' else 2
cv2.rectangle(frame, (int(box[0]), int(box[1])),
(int(box[2]), int(box[3])), color, thickness)
cv2.circle(frame, (int(cx), int(cy)), 5, color, -1)
status = f"T{target_id}_{current_roi[:2]}"
if source == 'det_only':
status += "_DET"
cv2.putText(frame, status, (int(box[0]), int(box[1]) - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
# ========================= 9. 统计信息 =========================
cv2.putText(frame, f"Camera: {camera_id}", (20, self.frame_height - 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
cv2.putText(frame, f"Prisoners: {len(current_prisoner_tids)}", (20, self.frame_height - 50),
cv2.putText(frame, f"Active Targets: {len(self.active_targets)}",
(20, self.frame_height - 50),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 0), 2)
return {"image": frame, "alerts": current_frame_alerts}
# ========================= 帧处理线程(对接原有框架,直接复用) =========================
# ========================= 帧处理线程 =========================
class FrameProcessorWorker(BaseFrameProcessorWorker):
"""看守所走廊犯人检测 - 5ROI+中心点消失判定"""
DETECTOR_FACTORY = lambda params: PrisonerDoorDetector(params)
POST_TYPE = 3 # 与原有业务区分,自定义即可
POST_TYPE = 3
TARGET_FPS = RTSP_FPS