perf: optimize video playback and detection interval

This commit is contained in:
sladro 2025-12-01 14:28:23 +08:00
parent c6a2e4ada0
commit 54ed5e0682
2 changed files with 181 additions and 68 deletions

View File

@ -85,3 +85,14 @@ logging:
# 调试图像保存路径
debug_image_path: "debug/"
# 性能保护配置
performance:
# 处理帧率上限每秒最多处理多少帧0 或 null 表示不限制
max_processing_fps: 0
# 帧间隔1 表示每帧处理2 表示处理 1 帧跳过 1 帧
frame_stride: 1
# 检测时间间隔0 表示每帧都检测
detection_interval_seconds: 0.1 # 每秒检测10次

238
main.py
View File

@ -77,6 +77,7 @@ class YantaiVisionXSystem:
self.alarm_manager = AlarmManager(self.logger)
self.tech_ui = TechUI()
self.performance_limiter = PerformanceLimiter()
self._detection_interval_seconds: float = 0.0
self._window_internal_name = "YantaiVisionX Monitor"
self._window_display_name = "烟台蓬莱国际机场低能见度识别软件"
@ -118,16 +119,24 @@ class YantaiVisionXSystem:
max_fps = performance_cfg.get("max_processing_fps")
frame_stride = performance_cfg.get("frame_stride", 1)
detection_interval = performance_cfg.get("detection_interval_seconds", 0)
self.performance_limiter.update_settings(max_processing_fps=max_fps, frame_stride=frame_stride)
try:
detection_interval_value = float(detection_interval)
except (TypeError, ValueError):
detection_interval_value = 0.0
self._detection_interval_seconds = detection_interval_value if detection_interval_value and detection_interval_value > 0 else 0.0
self.logger.log_info(
f"性能限制器配置: max_fps={self.performance_limiter.max_processing_fps}, "
f"frame_stride={self.performance_limiter.frame_stride}"
f"frame_stride={self.performance_limiter.frame_stride}, "
f"detection_interval={self._detection_interval_seconds}s"
)
def update_performance_settings(
self,
max_processing_fps: Optional[float] = None,
frame_stride: Optional[int] = None,
detection_interval_seconds: Optional[float] = None,
) -> None:
"""运行中动态调整性能限制参数"""
@ -135,6 +144,12 @@ class YantaiVisionXSystem:
max_processing_fps=max_processing_fps,
frame_stride=frame_stride,
)
if detection_interval_seconds is not None:
try:
value = float(detection_interval_seconds)
except (TypeError, ValueError):
value = 0.0
self._detection_interval_seconds = value if value > 0 else 0.0
def initialize_system(self, camera_config=None) -> bool:
"""
@ -210,10 +225,24 @@ class YantaiVisionXSystem:
self.logger.log_error("摄像头打开失败")
return
self.logger.log_info("开始 LED 检测...")
# 获取视频/摄像头帧率,用于控制播放速度
video_fps = self.camera.get_fps()
if video_fps <= 0:
video_fps = 30.0
frame_interval = 1.0 / video_fps # 每帧间隔(秒)
self.logger.log_info(f"开始 LED 检测... 帧率: {video_fps:.1f}fps")
limiter = self.performance_limiter
frame_index = 0
last_detection_result = None
last_detection_time: Optional[float] = None
display_frame_interval = 5 # 每5帧显示一次降低UI绑定开销
# 性能统计
loop_start = time.perf_counter()
total_display_time = 0.0
display_count = 0
try:
while self.is_running:
@ -225,45 +254,77 @@ class YantaiVisionXSystem:
current_frame_index = frame_index
frame_index += 1
current_time = time.perf_counter()
# 每100帧输出一次性能统计
if frame_index % 100 == 0:
elapsed = current_time - loop_start
actual_fps = frame_index / elapsed if elapsed > 0 else 0
avg_display = (total_display_time / display_count * 1000) if display_count > 0 else 0
print(f"[性能] 帧:{frame_index} 实际FPS:{actual_fps:.1f} 显示次数:{display_count} 平均显示耗时:{avg_display:.1f}ms")
should_process = True
if limiter and not limiter.should_process_frame(current_frame_index):
continue
# 图像预处理
enhanced_frame = self.image_enhancer.preprocess_frame(
frame, mode="normal"
)
# LED检测
detection_result = self.led_detector.detect_leds(enhanced_frame)
# 记录结果
self.logger.log_detection_result(detection_result)
should_process = False
if last_detection_result is None:
should_process = True
alarm_result = self.alarm_manager.process_detection(detection_result)
for event in alarm_result.events:
self.logger.log_alarm_event(event)
for roi_name in alarm_result.recoveries:
self.logger.log_recovery_event(
roi_name,
detection_result.frame_count,
detection_result.timestamp
if should_process and self._detection_interval_seconds > 0:
now = time.perf_counter()
if (
last_detection_time is not None
and (now - last_detection_time) < self._detection_interval_seconds
):
should_process = False
else:
last_detection_time = now
elif should_process:
last_detection_time = time.perf_counter()
detection_result = None
if should_process:
# 图像预处理
enhanced_frame = self.image_enhancer.preprocess_frame(
frame, mode="normal"
)
# 保存结果
if (
save_results
and self.logger.save_results_enabled
and detection_result.frame_count % self.logger.save_results_interval == 0
):
self.logger.save_result_to_file(detection_result)
# 显示结果
if self.display_enabled:
self._display_results(frame, detection_result)
if limiter:
limiter.enforce_rate_limit()
# LED检测
detection_result = self.led_detector.detect_leds(enhanced_frame)
last_detection_result = detection_result
# 记录结果
self.logger.log_detection_result(detection_result)
alarm_result = self.alarm_manager.process_detection(detection_result)
for event in alarm_result.events:
self.logger.log_alarm_event(event)
for roi_name in alarm_result.recoveries:
self.logger.log_recovery_event(
roi_name,
detection_result.frame_count,
detection_result.timestamp
)
# 保存结果
if (
save_results
and self.logger.save_results_enabled
and detection_result.frame_count % self.logger.save_results_interval == 0
):
self.logger.save_result_to_file(detection_result)
display_detection_result = last_detection_result if last_detection_result is not None else detection_result
# 控制显示帧率每N帧显示一次避免UI绑定拖慢速度
should_display = (current_frame_index % display_frame_interval == 0)
# 显示结果
if self.display_enabled and display_detection_result is not None and should_display:
t0 = time.perf_counter()
self._display_results(frame, display_detection_result)
total_display_time += time.perf_counter() - t0
display_count += 1
# 检查退出条件
if cv2.waitKey(1) & 0xFF == ord('q'):
break
@ -310,14 +371,23 @@ class YantaiVisionXSystem:
results = [] if self.logger.save_results_enabled else None
last_frame = None
last_detection_result = None
last_detection_time: Optional[float] = None
display_frame_interval = 5 # 每5帧显示一次降低UI绑定开销
self.logger.log_info(f"开始处理视频: {video_path}")
limiter = self.performance_limiter
frame_index = 0
# 性能统计
loop_start = time.perf_counter()
total_display_time = 0.0
display_count = 0
try:
while self.is_running:
current_time = time.perf_counter()
success, frame = self.camera.read_frame()
if not success:
if self.display_enabled and last_frame is not None:
@ -326,46 +396,78 @@ class YantaiVisionXSystem:
current_frame_index = frame_index
frame_index += 1
# 每100帧输出一次性能统计
if frame_index % 100 == 0:
elapsed = current_time - loop_start
actual_fps = frame_index / elapsed if elapsed > 0 else 0
avg_display = (total_display_time / display_count * 1000) if display_count > 0 else 0
print(f"[性能] 帧:{frame_index} 实际FPS:{actual_fps:.1f} 显示次数:{display_count} 平均显示耗时:{avg_display:.1f}ms")
should_process = True
if limiter and not limiter.should_process_frame(current_frame_index):
continue
# 图像预处理
enhanced_frame = self.image_enhancer.preprocess_frame(
frame, mode="normal"
)
# LED检测
detection_result = self.led_detector.detect_leds(enhanced_frame)
if results is not None:
results.append(detection_result)
should_process = False
if last_detection_result is None:
should_process = True
if should_process and self._detection_interval_seconds > 0:
now = time.perf_counter()
if (
last_detection_time is not None
and (now - last_detection_time) < self._detection_interval_seconds
):
should_process = False
else:
last_detection_time = now
elif should_process:
last_detection_time = time.perf_counter()
detection_result = None
if should_process:
# 图像预处理
enhanced_frame = self.image_enhancer.preprocess_frame(
frame, mode="normal"
)
# LED检测
detection_result = self.led_detector.detect_leds(enhanced_frame)
last_detection_result = detection_result
if results is not None:
results.append(detection_result)
# 记录结果
if detection_result.frame_count % 100 == 0:
self.logger.log_detection_result(detection_result)
alarm_result = self.alarm_manager.process_detection(detection_result)
for event in alarm_result.events:
self.logger.log_alarm_event(event)
for roi_name in alarm_result.recoveries:
self.logger.log_recovery_event(
roi_name,
detection_result.frame_count,
detection_result.timestamp
)
if self.display_enabled and frame is not None:
last_frame = frame.copy()
else:
last_frame = None
last_detection_result = detection_result
# 记录结果
if detection_result.frame_count % 100 == 0:
self.logger.log_detection_result(detection_result)
alarm_result = self.alarm_manager.process_detection(detection_result)
for event in alarm_result.events:
self.logger.log_alarm_event(event)
for roi_name in alarm_result.recoveries:
self.logger.log_recovery_event(
roi_name,
detection_result.frame_count,
detection_result.timestamp
)
display_detection_result = last_detection_result if last_detection_result is not None else detection_result
# 控制显示帧率每N帧显示一次避免UI绑定拖慢速度
should_display = (current_frame_index % display_frame_interval == 0)
# 显示结果
if self.display_enabled:
self._display_results(frame, detection_result)
if self.display_enabled and display_detection_result is not None and should_display:
t0 = time.perf_counter()
self._display_results(frame, display_detection_result)
total_display_time += time.perf_counter() - t0
display_count += 1
if cv2.waitKey(1) & 0xFF == ord('q'):
break
if limiter:
limiter.enforce_rate_limit()
# 保存批量结果
if results: