|
|
@@ -988,10 +988,11 @@ class AsyncCoordinator(Coordinator):
|
|
|
if detections:
|
|
|
self._process_detections(detections, frame, frame_size)
|
|
|
|
|
|
- # 选择跟踪目标并发送PTZ命令
|
|
|
- target = self._select_tracking_target()
|
|
|
- if target and self.enable_ptz_tracking and self.enable_ptz_camera:
|
|
|
- self._send_ptz_command_with_log(target, frame_size)
|
|
|
+ # 为每个检测到的人发送PTZ命令(不再只选一个)
|
|
|
+ if self.enable_ptz_tracking and self.enable_ptz_camera:
|
|
|
+ targets = self._get_all_valid_targets()
|
|
|
+ for target in targets:
|
|
|
+ self._send_ptz_command_with_log(target, frame_size)
|
|
|
elif not detections and self.current_target:
|
|
|
# 目标消失,切回IDLE
|
|
|
self._set_state(TrackingState.IDLE)
|
|
|
@@ -1154,14 +1155,35 @@ class AsyncCoordinator(Coordinator):
|
|
|
self._set_state(TrackingState.IDLE)
|
|
|
self.current_target = None
|
|
|
return None
|
|
|
-
|
|
|
+
|
|
|
# 使用目标选择器选择最优目标
|
|
|
self.current_target = self.target_selector.select_target(
|
|
|
self.tracking_targets
|
|
|
)
|
|
|
-
|
|
|
+
|
|
|
return self.current_target
|
|
|
-
|
|
|
+
|
|
|
+ def _get_all_valid_targets(self) -> List[TrackingTarget]:
|
|
|
+ """
|
|
|
+ 获取所有有效的检测目标(用于多目标PTZ定位)
|
|
|
+ 返回按优先级排序的目标列表
|
|
|
+ """
|
|
|
+ with self.targets_lock:
|
|
|
+ if not self.tracking_targets:
|
|
|
+ self._set_state(TrackingState.IDLE)
|
|
|
+ self.current_target = None
|
|
|
+ return []
|
|
|
+
|
|
|
+ # 按得分排序所有目标
|
|
|
+ targets = list(self.tracking_targets.values())
|
|
|
+ targets.sort(key=lambda t: t.score, reverse=True)
|
|
|
+
|
|
|
+ if targets:
|
|
|
+ self._set_state(TrackingState.TRACKING)
|
|
|
+ self.current_target = targets[0] # 第一个作为当前目标
|
|
|
+
|
|
|
+ return targets
|
|
|
+
|
|
|
def _send_ptz_command(self, target: TrackingTarget, frame_size: Tuple[int, int]):
|
|
|
"""将跟踪目标转化为PTZ命令放入队列"""
|
|
|
x_ratio, y_ratio = target.position
|
|
|
@@ -1194,23 +1216,6 @@ class AsyncCoordinator(Coordinator):
|
|
|
"""发送PTZ命令并打印日志"""
|
|
|
x_ratio, y_ratio = target.position
|
|
|
|
|
|
- # 检查位置变化是否超过阈值
|
|
|
- ptz_threshold = self.config.get('ptz_position_threshold', 0.03)
|
|
|
- if self.last_ptz_position is not None:
|
|
|
- last_x, last_y = self.last_ptz_position
|
|
|
- dx = abs(x_ratio - last_x)
|
|
|
- dy = abs(y_ratio - last_y)
|
|
|
- if dx < ptz_threshold and dy < ptz_threshold:
|
|
|
- logger.debug(f"[PTZ] 位置变化太小(dx={dx:.4f}, dy={dy:.4f}),跳过")
|
|
|
- return
|
|
|
-
|
|
|
- # 冷却检查
|
|
|
- current_time = time.time()
|
|
|
- ptz_cooldown = self.config.get('ptz_command_cooldown', 0.5)
|
|
|
- if current_time - self._last_ptz_time < ptz_cooldown:
|
|
|
- logger.debug(f"[PTZ] 冷却中,跳过 (间隔={current_time - self._last_ptz_time:.2f}s < {ptz_cooldown}s)")
|
|
|
- return
|
|
|
-
|
|
|
# 计算PTZ角度(用于日志)
|
|
|
if self.enable_calibration and self.calibrator and self.calibrator.is_calibrated():
|
|
|
pan, tilt = self.calibrator.transform(x_ratio, y_ratio)
|
|
|
@@ -1235,7 +1240,6 @@ class AsyncCoordinator(Coordinator):
|
|
|
|
|
|
try:
|
|
|
self._ptz_queue.put_nowait(cmd)
|
|
|
- self.last_ptz_position = (x_ratio, y_ratio)
|
|
|
self._update_stats('ptz_commands_sent' if 'ptz_commands_sent' in self.stats else 'persons_detected')
|
|
|
logger.info(
|
|
|
f"[PTZ] 命令已发送: 目标ID={target.track_id} "
|