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:
+66
-11
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user