added camera search and select, auto preference saving and version tag to 0.4.2
This commit is contained in:
+129
-3
@@ -22,6 +22,8 @@ from pipeline.csv_recorder import CsvRecorder
|
||||
from pipeline.service import FingerPipeline
|
||||
|
||||
from .app_paths import resource_path
|
||||
from .camera_discovery import list_cameras, pick_default_camera
|
||||
from .preferences import get_preferred_video_source, load_preferences, save_preferences
|
||||
from .layout import (
|
||||
DashboardLayout,
|
||||
LAYOUT,
|
||||
@@ -102,26 +104,45 @@ class FingerDashboardWindow(QMainWindow):
|
||||
mesh_state=self.mesh_state,
|
||||
show_log=self._log_panel_visible,
|
||||
)
|
||||
# CLI / pipeline defaults first, then overlay saved user preferences.
|
||||
self.settings_panel.set_video_source(str(self.config.video))
|
||||
self.settings_panel.set_config_path(self.config.config)
|
||||
self.settings_panel.set_calibration_path(self.config.calib or "")
|
||||
self.settings_panel.set_finger_export_dir(self.config.export_dir)
|
||||
self.settings_panel.set_csv_save_dir(self.config.csv_save_dir)
|
||||
|
||||
self.settings_panel.log_visibility_changed.connect(self._set_log_panel_visible)
|
||||
self.settings_panel.free_rotation_changed.connect(self.mesh_viewport.set_free_rotation)
|
||||
self._preferences = load_preferences()
|
||||
self.settings_panel.apply_preference_state(self._preferences)
|
||||
self._log_panel_visible = bool(self.settings_panel.show_log_check.isChecked())
|
||||
self.mesh_viewport.set_free_rotation(bool(self.settings_panel.free_rotate_check.isChecked()))
|
||||
if self.arrow_panel is not None:
|
||||
self.settings_panel.arrow_background_changed.connect(self.arrow_panel.set_background)
|
||||
self.arrow_panel.set_background(self.settings_panel.arrow_background())
|
||||
# Sync pipeline config fields from restored panel values.
|
||||
self.config.video = self.settings_panel.video_source() or self.config.video
|
||||
self.config.config = self.settings_panel.config_path() or self.config.config
|
||||
self.config.export_dir = self.settings_panel.finger_export_dir() or self.config.export_dir
|
||||
self.config.csv_save_dir = self.settings_panel.csv_save_dir() or self.config.csv_save_dir
|
||||
|
||||
self.settings_panel.log_visibility_changed.connect(self._on_log_visibility_changed)
|
||||
self.settings_panel.free_rotation_changed.connect(self._on_free_rotation_changed)
|
||||
if self.arrow_panel is not None:
|
||||
self.settings_panel.arrow_background_changed.connect(self._on_arrow_background_changed)
|
||||
else:
|
||||
self.settings_panel.arrow_background_changed.connect(lambda _v: self._save_preferences())
|
||||
self.settings_panel.view_reset_requested.connect(self.mesh_viewport.reset_view)
|
||||
self.settings_panel.browse_video_requested.connect(self._select_camera)
|
||||
self.settings_panel.camera_refresh_requested.connect(self._refresh_cameras)
|
||||
self.settings_panel.camera_selection_changed.connect(self._on_camera_selection_changed)
|
||||
self.settings_panel.browse_config_requested.connect(self._select_config)
|
||||
self.settings_panel.browse_finger_assets_requested.connect(self._select_finger_assets)
|
||||
self.settings_panel.browse_csv_dir_requested.connect(self._select_csv_dir)
|
||||
self.settings_panel.csv_record_toggled.connect(self._on_csv_record_toggled)
|
||||
self.settings_panel.show_flow_arrows_check.toggled.connect(lambda _v: self._save_preferences())
|
||||
self.settings_panel.btn_play_pause.clicked.connect(self._on_play_pause_clicked)
|
||||
self.settings_panel.btn_reset_tracker.clicked.connect(self._on_reset)
|
||||
self.settings_panel.set_play_pause_state("run")
|
||||
self.settings_panel.set_csv_controls_for_pipeline(False)
|
||||
self._refresh_cameras(announce=True)
|
||||
|
||||
self._panel_widgets: dict[str, QWidget] = {}
|
||||
self._panel_widgets["mesh"] = self.mesh_viewport
|
||||
@@ -162,6 +183,37 @@ class FingerDashboardWindow(QMainWindow):
|
||||
self.log_widget.setVisible(self._log_panel_visible)
|
||||
QTimer.singleShot(0, self._apply_panel_layout)
|
||||
|
||||
def _on_log_visibility_changed(self, visible: bool) -> None:
|
||||
self._set_log_panel_visible(visible)
|
||||
self._save_preferences()
|
||||
|
||||
def _on_free_rotation_changed(self, enabled: bool) -> None:
|
||||
self.mesh_viewport.set_free_rotation(enabled)
|
||||
self._save_preferences()
|
||||
|
||||
def _on_arrow_background_changed(self, value: str) -> None:
|
||||
if self.arrow_panel is not None:
|
||||
self.arrow_panel.set_background(value)
|
||||
self._save_preferences()
|
||||
|
||||
def _save_preferences(self) -> None:
|
||||
prefs = self.settings_panel.preference_state()
|
||||
self._preferences = prefs
|
||||
save_preferences(prefs)
|
||||
# Keep in-memory pipeline config aligned with panel values.
|
||||
video = prefs.get("video_source")
|
||||
if isinstance(video, str) and video.strip():
|
||||
self.config.video = video.strip()
|
||||
config_path = prefs.get("config_path")
|
||||
if isinstance(config_path, str) and config_path.strip():
|
||||
self.config.config = config_path.strip()
|
||||
assets = prefs.get("finger_assets_dir")
|
||||
if isinstance(assets, str) and assets.strip():
|
||||
self.config.export_dir = assets.strip()
|
||||
csv_dir = prefs.get("csv_save_dir")
|
||||
if isinstance(csv_dir, str) and csv_dir.strip():
|
||||
self.config.csv_save_dir = csv_dir.strip()
|
||||
|
||||
def _apply_panel_layout(self) -> None:
|
||||
setup = self.layout.panel_setup
|
||||
scale = self._layout_scale_factor()
|
||||
@@ -323,6 +375,14 @@ class FingerDashboardWindow(QMainWindow):
|
||||
self.config.export_dir = self.settings_panel.finger_export_dir()
|
||||
self.config.csv_save_dir = self.settings_panel.csv_save_dir() or "./outputs/csv"
|
||||
|
||||
if not self.config.video:
|
||||
self._set_play_pause_button("run")
|
||||
self.settings_panel.set_finger_export_dir_enabled(True)
|
||||
print("请先选择摄像机或视频文件。")
|
||||
return
|
||||
|
||||
self._save_preferences()
|
||||
|
||||
try:
|
||||
self.pipeline = FingerPipeline(self.config)
|
||||
self.pipeline.open()
|
||||
@@ -342,6 +402,7 @@ class FingerDashboardWindow(QMainWindow):
|
||||
self.timer.start(self.layout.timer_interval_ms)
|
||||
self._set_play_pause_button("pause")
|
||||
self.settings_panel.btn_reset_tracker.setEnabled(True)
|
||||
self.settings_panel.set_camera_controls_enabled(False)
|
||||
self.settings_panel.set_csv_controls_for_pipeline(True)
|
||||
print(
|
||||
f"▶ 启动 — 摄像机={self.config.video}, 配置={self.config.config}, "
|
||||
@@ -364,7 +425,9 @@ class FingerDashboardWindow(QMainWindow):
|
||||
self._set_play_pause_button("run")
|
||||
self.settings_panel.btn_reset_tracker.setEnabled(False)
|
||||
self.settings_panel.set_finger_export_dir_enabled(True)
|
||||
self.settings_panel.set_camera_controls_enabled(True)
|
||||
self.settings_panel.set_csv_controls_for_pipeline(False)
|
||||
self._update_play_enabled_for_source()
|
||||
|
||||
def _on_reset(self) -> None:
|
||||
if not self._running:
|
||||
@@ -459,6 +522,60 @@ class FingerDashboardWindow(QMainWindow):
|
||||
)
|
||||
)
|
||||
|
||||
def _refresh_cameras(self, announce: bool = True) -> None:
|
||||
"""Scan cameras and populate the settings dropdown."""
|
||||
keep_file = self.settings_panel.is_file_source()
|
||||
existing_file = self.settings_panel.video_source() if keep_file else ""
|
||||
|
||||
preferred = None
|
||||
current = self.settings_panel.selected_camera_source()
|
||||
saved = get_preferred_video_source(self._preferences)
|
||||
cli_video = str(self.config.video).strip()
|
||||
if current.isdigit():
|
||||
preferred = current
|
||||
elif saved and str(saved).isdigit():
|
||||
preferred = str(saved)
|
||||
elif cli_video.isdigit():
|
||||
preferred = cli_video
|
||||
|
||||
cameras = list_cameras()
|
||||
selected = pick_default_camera(cameras, preferred)
|
||||
|
||||
self.settings_panel.set_camera_options(cameras, selected)
|
||||
if keep_file and existing_file:
|
||||
self.settings_panel.set_video_source(existing_file)
|
||||
elif selected:
|
||||
self.settings_panel.set_video_source(selected)
|
||||
self.config.video = selected
|
||||
elif not keep_file:
|
||||
self.config.video = ""
|
||||
|
||||
self._update_play_enabled_for_source()
|
||||
self._save_preferences()
|
||||
if announce:
|
||||
if cameras:
|
||||
names = ", ".join(cam.label() for cam in cameras)
|
||||
print(f"已发现 {len(cameras)} 路摄像机:{names}")
|
||||
if selected and not keep_file:
|
||||
print(f"当前摄像机:{selected}")
|
||||
else:
|
||||
print("未发现可用摄像机。可点击 Refresh 重扫,或通过 … 选择视频文件。")
|
||||
|
||||
def _update_play_enabled_for_source(self) -> None:
|
||||
if self._running:
|
||||
return
|
||||
usable = self.settings_panel.has_usable_source()
|
||||
self.settings_panel.set_play_pause_state("run")
|
||||
self.settings_panel.btn_play_pause.setEnabled(usable)
|
||||
|
||||
def _on_camera_selection_changed(self, camera_id: str) -> None:
|
||||
camera_id = str(camera_id).strip()
|
||||
if not camera_id:
|
||||
return
|
||||
self.config.video = camera_id
|
||||
self._save_preferences()
|
||||
self._update_play_enabled_for_source()
|
||||
|
||||
def _select_camera(self) -> None:
|
||||
path, _ = QFileDialog.getOpenFileName(
|
||||
self,
|
||||
@@ -468,6 +585,9 @@ class FingerDashboardWindow(QMainWindow):
|
||||
)
|
||||
if path:
|
||||
self.settings_panel.set_video_source(path)
|
||||
self.config.video = path
|
||||
self._save_preferences()
|
||||
self._update_play_enabled_for_source()
|
||||
|
||||
def _select_config(self) -> None:
|
||||
path, _ = QFileDialog.getOpenFileName(
|
||||
@@ -478,6 +598,8 @@ class FingerDashboardWindow(QMainWindow):
|
||||
)
|
||||
if path:
|
||||
self.settings_panel.set_config_path(path)
|
||||
self.config.config = path
|
||||
self._save_preferences()
|
||||
|
||||
def _select_finger_assets(self) -> None:
|
||||
path = QFileDialog.getExistingDirectory(
|
||||
@@ -487,6 +609,8 @@ class FingerDashboardWindow(QMainWindow):
|
||||
)
|
||||
if path:
|
||||
self.settings_panel.set_finger_export_dir(path)
|
||||
self.config.export_dir = path
|
||||
self._save_preferences()
|
||||
|
||||
def _select_csv_dir(self) -> None:
|
||||
path = QFileDialog.getExistingDirectory(
|
||||
@@ -497,6 +621,7 @@ class FingerDashboardWindow(QMainWindow):
|
||||
if path:
|
||||
self.settings_panel.set_csv_save_dir(path)
|
||||
self.config.csv_save_dir = path
|
||||
self._save_preferences()
|
||||
|
||||
def _on_csv_record_toggled(self, start: bool) -> None:
|
||||
if start:
|
||||
@@ -556,6 +681,7 @@ class FingerDashboardWindow(QMainWindow):
|
||||
def closeEvent(self, event):
|
||||
self.timer.stop()
|
||||
self._stop_csv_recording(announce=True)
|
||||
self._save_preferences()
|
||||
self.mesh_viewport.close_renderer()
|
||||
self.pipeline.close()
|
||||
event.accept()
|
||||
|
||||
Reference in New Issue
Block a user