Skip to content

Upgrade PySide6 multi-camera GUI#38

Draft
C-Achard wants to merge 109 commits intomasterfrom
cy/pre-release-fixes-2.0
Draft

Upgrade PySide6 multi-camera GUI#38
C-Achard wants to merge 109 commits intomasterfrom
cy/pre-release-fixes-2.0

Conversation

@C-Achard
Copy link

@C-Achard C-Achard commented Jan 30, 2026

Finalizing the PySide6+multi-camera GUI

Further refinement of GUI added in #35 by @arturoptophys

Features

  • Full project file tree refactor for more granularity and ease of use
  • Typed configs
  • Improved settings UX/UI Works as is, delayed
  • Theme/UI alignment with DLC, icons, colors, etc
  • Improved camera loading UX and validation
  • Many fixes to OpenCV backend
  • Finish config refactor
  • Fixes all issues in Pre-release fixes & improvements checklist #37
  • Fixes all issues in Feedback thread for PySide6 GUI #40
  • Figure out a proper multi-platform, multi-device OpenCV backend design

Also tweaks error handling, UI and UX.


Additional TODOs

  • Documentation overhaul ->see Create 2.0 documentation #39
  • Comprehensive unit and GUI test suite, >80% coverage (49% current)
    • In particular, video recording coverage is very low currently¨
    • Camera backends unit/smoke test

arturoptophys and others added 30 commits October 21, 2025 11:22
…modern-python-and-pyqt6

Add Basler and GenTL camera backends for modular capture
…camera-functionality

Rework layout and camera handling controls
…r integration

- Implemented `get_device_count` method in `GenTLCameraBackend` to retrieve the number of GenTL devices detected.
- Added `max_devices` configuration option in `CameraSettings` to limit device probing.
- Introduced `BoundingBoxSettings` for bounding box visualization, integrated into the main GUI.
- Enhanced `DLCLiveProcessor` to accept a processor instance during configuration.
- Updated GUI to support processor selection and auto-recording based on processor commands.
- Refactored camera properties handling and removed deprecated advanced properties editor.
- Improved error handling and logging for processor connections and recording states.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Delete the setuptools-based setup.py since we have pyproject.toml now
Remove legacy dlclivegui/config.py and switch to typed models in dlclivegui.utils.config_models (rename ApplicationSettings, CameraSettings, DLCProcessorSettings, MultiCameraSettings, RecordingSettings to ApplicationSettingsModel, CameraSettingsModel, DLCProcessorSettingsModel, MultiCameraSettingsModel, RecordingSettingsModel). Update package exports and camera/main_window imports accordingly. Move ModelPathStore into dlclivegui.utils.settings_store (add QSettings-based persistence, path normalization and helpers) and import it from main_window. Also add is_model_file usage and Path handling in the new settings store.
Move dlclivegui/utils/config_models.py -> dlclivegui/config.py and rename Pydantic model types (e.g. CameraSettingsModel -> CameraSettings, MultiCameraSettingsModel -> MultiCameraSettings, DLCProcessorSettingsModel -> DLCProcessorSettings, RecordingSettingsModel -> RecordingSettings, BoundingBoxSettingsModel -> BoundingBoxSettings, VisualizationSettingsModel -> VisualizationSettings, ApplicationSettingsModel -> ApplicationSettings). Update imports, type hints and factory/controller/GUI code to use the new module and class names, adjust DEFAULT_CONFIG, and update tests accordingly. This is a refactor to centralize config models under dlclivegui.config and propagate the new names throughout the codebase.
Add a menu action and UI button to open the recording folder in the system file explorer.
Also comment out the previous automatic loading of myconfig.json (replace FIXME with NOTE/TODO) to avoid silently loading config on startup.
Combine container/codec UI into a compact row, use RecordingSettings.crf as the default CRF and add a tooltip. Add a "Record video with overlays" checkbox and implement _render_overlays_for_recording to draw pose and bounding-box overlays into frames sent to the recorder; _on_multi_frame_ready now applies this when the checkbox is checked. Consolidate and extend test fixtures (fake DLCLive/backend factories, window fixture, recording helpers, and patched recording/video writer), add tests for overlay rendering and recording behavior, and adjust several GUI/service/unit tests with appropriate pytest marks.
Prevent the recording path preview from being squished and refactor the container/codec/CRF controls into a single responsive grid row with explicit labels, tooltips, size policies, column stretches, spacing and minimum content lengths. Set CRF spinbox range/value and tooltip, keep platform-specific codec lists, and move the "Open recording folder" button below the recording controls to avoid layout shifting. Also remove the unused bbox_color argument from the drawing call in _build_bbox_group.
Add GitHub Actions CI workflow to run unit and smoke tests across Ubuntu, macOS, and Windows for Python 3.10–3.12, cache tox environments, append coverage summary, and upload coverage to Codecov. Introduce tox.ini to standardize test and lint environments (py310/311/312 plus a ruff lint env), run pytest excluding hardware-marked tests, and set CI-friendly environment variables. Add .coveragerc to configure coverage (branch, source dlclivegui, and omit hardware SDK shim backends). Update pyproject.toml test markers to add a "hardware" marker and comment out the previous "slow" marker.
Add comprehensive tests for camera backends: aravis and OpenCV (tests/cameras/backends/*). Introduce a backend-specific pytest conftest that detects optional dependencies, provides --run-hardware gating, and supplies fixtures to reset registry or force fake/unavailable SDKs. Include extensive fake Aravis/OpenCV helpers to exercise read/open/close/configure paths. Also apply two tiny tweaks: add a file-identifying comment in dlclivegui/cameras/factory.py and remove an unused bbox_color parameter from tests/conftest.py.
Add comprehensive unit tests for dlclivegui.utils.display and dlclivegui.utils.stats, covering tiling geometry, tiled frame creation, drawing utilities (bbox, keypoints, pose), and stats formatting. Introduce property-based tests using Hypothesis for recorder and DLC stats formatting and several exact-case tests. Also update pyproject.toml to include hypothesis>=6.0 in dev and test dependencies.
Rename QtSettingsStore to DLCLiveGUISettingsStore and add recording-related settings: get/set for session_name and get/set for use_timestamp (with robust parsing of stored types). Also add comprehensive unit tests: tests for the settings store (including snapshot save/load and model path store behaviors) and many utility tests (is_model_file, sanitize_name, timestamp_string, split_stem_ext, run indexing, build_run_dir, build_recording_plan, and FPSTracker). Includes an InMemoryQSettings test helper.
Introduce DLCLiveGUISettingsStore and use it throughout the GUI to persist/load settings (session name, timestamp preference, last config path, full config snapshot). Replace ad-hoc QSettings helpers in main_window with calls to the new store, save snapshots/last-path when loading/saving configs, and wire session/timestamp persistence to the store. Replace internal DLC stats formatting with shared format_dlc_stats util. Add logging/debug messages and safer path normalization to ModelPathStore. Add pragma markers for coverage around OneEuroFilter in dlc_processor_socket. Update GUI tests to isolate QSettings (use INI in tmp) and disable modal dialogs during tests to avoid native crashes in CI.
Reword the comment describing potential issues when a QTimer-triggered validation opens a modal QMessageBox while the parent window is closing. Replace the Windows-specific phrasing with a more general note about errors with unpredictable timing (heap corruption / access violations). No functional change; tests/CI mitigation guidance remains.
Add support for persisting original DeepLabCut pose data as an HDF5 alongside the existing .pkl save. Introduces a dlc_cfg attribute and set_dlc_cfg() on BaseProcessorSocket, a save_original_pose() helper that builds a pandas DataFrame (with MultiIndex columns when bodyparts are present) and writes to <name>_DLC.hdf5, and includes dlc_cfg in the saved payload. The processor.save() flow now pops original_pose out of the pickle and delegates HDF5 writing when save_original is enabled. DLCLiveProcessor now passes its cfg to the processor during initialization. Tests updated/added to validate HDF5 creation, labeled/unlabeled columns, and dlc_cfg inclusion.
@C-Achard C-Achard mentioned this pull request Feb 5, 2026
6 tasks
@C-Achard C-Achard added the help wanted Extra attention is needed label Feb 5, 2026
@C-Achard C-Achard marked this pull request as ready for review February 5, 2026 15:44
@C-Achard C-Achard requested a review from deruyter92 February 5, 2026 15:44
@C-Achard
Copy link
Author

C-Achard commented Feb 5, 2026

@arturoptophys I cannot request your review directly, but if you have time to have a look would be much appreciated !
An early docs draft is also available at #39

Make the recording path preview interactive: disable word wrap, show as gray HTML preview, set pointing-hand cursor and tooltip, and copy the cleaned path to clipboard on click (with a transient "Copied path" tooltip). Compute a full_hint for the preview and update the tooltip to show a wildcarded path. Add required Qt imports (QGuiApplication, QFontMetrics, QCursor, QToolTip) and bind mouseReleaseEvent to a new _copy_path_on_click handler. (Also adds an import for sympy.re present in the diff.)
Introduce ElidingPathLabel (dlclivegui/gui/misc/elidinglabel.py): a QLabel subclass that stores full text, shows an elided representation, exposes set_full_text/full_text, keeps a plain-text tooltip, and copies the full path on click. Replace the old recording path preview QLabel in the main window with ElidingPathLabel, update the preview-generation to call set_full_text, and simplify related layout/settings code (use QFormLayout growth policies and remove the manual click handler). Add comprehensive tests for the new widget (tests/gui/test_misc.py) and update recording-path tests to use the new full_text attribute. Remove the now-duplicated splash test file and tidy .coveragerc (remove a commented backend entry).
@C-Achard C-Achard mentioned this pull request Feb 5, 2026
4 tasks
Introduce logging and better diagnostics around camera backend discovery and resolution.

- dlclivegui/cameras/base.py: add a module logger and emit a debug message when a backend is registered.
- dlclivegui/cameras/factory.py: add a logger and a _BACKEND_IMPORT_ERRORS map to record import failures; log successful backend module loads and log exceptions with traceback when imports fail. Provide an opt-in strict import mode via DLC_CAMERA_BACKENDS_STRICT_IMPORT to raise on import errors.
- Record and surface import failures to aid debugging: expose CameraFactory.backend_import_errors() and improve CameraFactory._resolve_backend() to show available backends and any backend module import errors with a helpful tip.
- Minor change: sanitize settings before probing a backend instance (settings = _sanitize_for_probe(settings)).

These changes make it easier to debug why optional/misconfigured camera backends did not register and provide a path for stricter CI/dev behavior.
Introduce a small OpenCV camera discovery utility and dynamic backend loader, and wire them into the OpenCVCameraBackend. Added dlclivegui/cameras/backends/utils/opencv_discovery.py (enumeration, selection, open-with-fallbacks, and mode verification) and backend_loader.py (dynamic import + error reporting), plus a simple CLI script. Updated dlclivegui/cameras/backends/opencv_backend.py to use list_cameras/select_camera/open_with_fallbacks and apply_mode_with_verification for resolution/fps negotiation, and commented out older Windows-specific normalization/fallback code to centralize logic in the new utilities. Added tests for the new utilities and adjusted existing backend tests to use test factories; updated pyproject to require cv2-enumerate-cameras. These changes make camera discovery and mode negotiation more deterministic, testable, and platform-aware.
Introduce a typed OpenCVOptions pydantic model and wire per-backend options through CameraBackend and CameraFactory. OpenCVCameraBackend now parses and validates an "opencv" options namespace (OPTIONS_KEY), persists discovered device_id, and uses the typed options for behavior like fast_start, alt_index_probe, api, and prefer_mjpg. CameraBackend gained helpers (OPTIONS_KEY, options_key, parse_options, options_schema, sanitize_for_probe) to standardize option handling and produce a lightweight probe-safe settings copy. CameraFactory was updated to load backend modules robustly, validate backend options early, and call sanitize_for_probe for availability probing. Adjustments in OpenCVCameraBackend also avoid overwriting settings resolution/fps during fast_start/verification and tweak when MJPG attempts occur. Tests updated to use the new "opencv" options namespace and to assert fast_start no longer mutates requested resolution.
Record backend import failures, ensure backends are loaded before use, and add OpenCV rebind helper.

- dlclivegui/cameras/backends/utils/opencv_discovery.py: Add TYPE_CHECKING import for CameraSettings and introduce _try_rebind_opencv to rebind an OpenCV camera using device_id, VID/PID or name and update settings with a chosen stable ID/index.
- dlclivegui/cameras/factory.py: On backend import failure, store the error in _BACKEND_IMPORT_ERRORS and log the exception; optionally raise on strict import via DLC_CAMERA_BACKENDS_STRICT_IMPORT. Ensure _ensure_backends_loaded() is called before CameraFactory.create, check_camera_available, and _resolve_backend to provide accurate error reporting when backends are missing.

These changes improve diagnostics for failing backend imports and add a utility to robustly select/rebind OpenCV cameras by stable identifiers.
Add support for selecting bounding-box colors in the GUI and introduce color utilities.

- Added BBoxColors enum and color utility functions (get_all_display_names, color_to_rgb) in dlclivegui/utils/display.py.
- Added a color combo with swatches to the Bounding Box Visualization group in dlclivegui/gui/main_window.py, including methods to populate the combo, set it from an existing color, and handle color changes (_populate_bbox_color_combo_with_swatches, _set_combo_from_color, _on_bbox_color_changed).
- Wire bbox color changes into the preview (updates _bbox_color and refreshes the displayed frame) and initialize the combo from current viz settings.
- Updated draw_bbox call sites to the new argument names (frame, bbox_xyxy, color_bgr) and cleaned up some imports.

This enables visually picking bbox colors in the UI and centralizes color definitions for consistent use across the app.
Add optional rich discovery and settings rebinding to camera backends and integrate into factory/GUI. Introduce CameraBackend.discover_devices and rebind_settings hooks (no-op by default) and implement them for the OpenCV backend to return DetectedCamera info and persist VID/PID/name into backend properties. CameraFactory now prefers backend-provided discovery (falling back to probing) and calls rebind_settings before quick presence checks and creation. GUI changes persist and show detected device identity, merge backend-updated settings after preview open, and avoid duplicate additions by stable identity. Tests updated to cover rich discovery, cancellation/progress callbacks, fallback behavior, and rebind semantics.
@C-Achard C-Achard marked this pull request as draft February 6, 2026 15:04
Rename misc/elidinglabel.py to misc/eliding_label.py and update all imports accordingly. Change ElidingPathLabel default elide_mode from Qt.ElideMiddle to Qt.ElideLeft. Adjust tests to import the new module path, create the label without an explicit parent, and use qtbot.waitExposed(lbl) for reliable exposure instead of a fixed sleep. These changes align module naming, tweak default eliding behavior, and make tests more robust.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request help wanted Extra attention is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants