1. tuned arrow mesh drawing

2. centralixzed arrow config in layout.py
3. seperate mesh render and display resolution to speed up (~40 fps)
This commit is contained in:
ykcheungab
2026-06-19 14:28:28 +08:00
parent 3fd9b839a9
commit 2e5c047d1e
19 changed files with 980 additions and 147 deletions
+66 -11
View File
@@ -3,6 +3,7 @@
from __future__ import annotations
import sys
import time
from pathlib import Path
from PyQt5.QtCore import Qt, QTimer
@@ -55,6 +56,9 @@ class FingerDashboardWindow(QMainWindow):
self.layout = layout
self.pipeline = FingerPipeline(config)
self._running = False
self._frame_index = 0
self._wall_fps = 0.0
self._wall_fps_alpha = 0.15
self.setWindowTitle(layout.window_title)
self.setStyleSheet(STYLE)
@@ -124,7 +128,7 @@ class FingerDashboardWindow(QMainWindow):
self.mesh_viewport = MeshViewportWidget(layout=layout)
self.arrow_panel = ArrowPanelWidget(flow_threshold=layout.arrow_flow_threshold, layout=layout)
self.force_charts = ForceChartWidget(layout=layout, lowpass_cutoff_hz=self.config.lowpass_cutoff_hz)
self.log_widget = make_log_widget()
self.log_widget = make_log_widget(layout.log_config)
self._panel_widgets["mesh"] = self.mesh_viewport
self._panel_widgets["arrows"] = self.arrow_panel
@@ -216,6 +220,8 @@ class FingerDashboardWindow(QMainWindow):
return
self._running = True
self._frame_index = 0
self._wall_fps = 0.0
self.timer.start(self.layout.timer_interval_ms)
self.btn_start.setText("启动")
self.btn_stop.setEnabled(True)
@@ -230,6 +236,7 @@ class FingerDashboardWindow(QMainWindow):
return
self._running = False
self.timer.stop()
self.log_handler.clear_status_line()
self.btn_stop.setText("停止中...")
self.btn_stop.setEnabled(False)
QApplication.processEvents()
@@ -252,25 +259,70 @@ class FingerDashboardWindow(QMainWindow):
def _on_timer(self) -> None:
if not self._running:
return
frame = self.pipeline.tick()
frame_t0 = time.perf_counter()
frame, timings = self.pipeline.tick_timed()
if frame is None:
print("采集结束或读取失败。")
self._on_stop()
return
self._frame_index += 1
layout = self.layout
profile = self.pipeline.profiler
mesh_ms = 0.0
if layout.mesh_render_stride <= 1 or self._frame_index % layout.mesh_render_stride == 0:
mesh_ms = self.mesh_viewport.update_frame(frame)
if profile is not None and mesh_ms > 0:
profile.record("mesh", mesh_ms)
arrows_ms = 0.0
t0 = time.perf_counter()
self.arrow_panel.update_frame(frame)
arrows_ms = (time.perf_counter() - t0) * 1000.0
if profile is not None:
profile.record("arrows", arrows_ms)
charts_ms = 0.0
if layout.chart_update_stride <= 1 or self._frame_index % layout.chart_update_stride == 0:
t0 = time.perf_counter()
self.force_charts.update_frame(frame)
charts_ms = (time.perf_counter() - t0) * 1000.0
if profile is not None:
profile.record("charts", charts_ms)
total_ms = (time.perf_counter() - frame_t0) * 1000.0
instant_fps = 1000.0 / total_ms if total_ms > 0 else 0.0
if self._wall_fps <= 0:
self._wall_fps = instant_fps
else:
self._wall_fps = (
self._wall_fps_alpha * instant_fps
+ (1.0 - self._wall_fps_alpha) * self._wall_fps
)
if profile is not None:
profile.record("total", total_ms)
self.pipeline.record_total_frame(total_ms)
flow_mag = 0.0
if frame.flow.size:
flow_mag = float((frame.flow[:, :, 0] ** 2 + frame.flow[:, :, 1] ** 2).mean() ** 0.5)
print(
f"FPS={frame.fps:.2f} flow_rms={flow_mag:.2f} "
f"mask={frame.mask_coverage:.2f} normal={frame.fnormal:.2f} "
f"shear=({frame.fshearx:.2f}, {frame.fsheary:.2f})",
end="\r",
)
self.mesh_viewport.update_frame(frame)
self.arrow_panel.update_frame(frame)
self.force_charts.update_frame(frame)
log_cfg = layout.log_config
if log_cfg.status_enabled:
self.log_handler.set_status_line(
log_cfg.format_status(
fps=frame.fps,
fnormal=frame.fnormal,
fshearx=frame.fshearx,
fsheary=frame.fsheary,
flow_rms=flow_mag,
mask_coverage=frame.mask_coverage,
wall_fps=self._wall_fps,
)
)
def _select_camera(self) -> None:
path, _ = QFileDialog.getOpenFileName(
@@ -325,6 +377,9 @@ def run_dashboard(config: PipelineConfig, *, layout: DashboardLayout = LAYOUT) -
from .app import get_or_create_qapp
print("\n按键说明:Q 退出 | R 重置追踪器 | S 开始录像 | E 结束录像 | ESC 全屏")
if config.profile:
print(f"Profiling enabled (report every {config.profile_every} frames).")
print("Log FPS= is end-to-end dashboard rate; sdk= is Sensor internal rate.")
app = get_or_create_qapp()
window = FingerDashboardWindow(config, layout=layout)