Add basic output format wiring and settings (mono support)#82
Draft
C-Achard wants to merge 15 commits into
Draft
Add basic output format wiring and settings (mono support)#82C-Achard wants to merge 15 commits into
C-Achard wants to merge 15 commits into
Conversation
Extract the RecorderStats dataclass from dlclivegui/services/video_recorder.py into dlclivegui/utils/stats.py and add the needed dataclasses import. Update imports to reflect the new location in dlclivegui/gui/recording_manager.py, dlclivegui/services/video_recorder.py, and tests/tests/gui/test_rec_manager.py. Also add imports for REC_DO_LOG_TIMING and WorkerTimingStats in video_recorder.py. No behavioral changes intended—this is a refactor to centralize recorder-related stats.
Basler backend: add preserve_mono support and configure the pypylon converter to output Mono8 when the camera source PixelFormat is Mono* and preserve_mono is enabled; fall back to BGR8 otherwise. Log the first decoded frame and expose per-backend timing flag BASLER_DO_LOG_TIMING. Update defaults for global timing flags and add REC_DO_LOG_TIMING. Camera settings: add preserve_mono flag and include it in __repr__. RecordingManager: pass convert_grayscale_to_rgb based on the camera preserve_mono setting. VideoRecorder: add convert_grayscale_to_rgb option, avoid unnecessary grayscale->RGB expansion when disabled, forward pixel-format/size hints to WriteGear, add WorkerTimingStats for recorder processing and writer, instrument preprocessing/queue/write steps, log the first frame, and improve frame-size mismatch handling and error reporting. These changes reduce memory/CPU overhead for mono cameras and add better timing/diagnostics for recording.
Introduce a preserve_mono capability and related properties to CameraBackend (actual_pixel_format, recommended_preserve_mono). Add a Preserve Mono checkbox to the camera config UI, persist/load its value, include it in probe detection logic (detect pixel format and apply recommended preserve_mono when supported), and treat changes to preserve_mono as restart-triggering. Update Basler static capabilities test to advertise preserve_mono support and add VideoRecorder tests to verify grayscale frames are preserved when requested and expanded by default. This enables preserving single-channel camera output to reduce bandwidth/overhead for monochrome cameras.
Expose the camera source pixel format via actual_pixel_format and add recommended_preserve_mono to suggest preserving mono images when the source format starts with "Mono". Add "preserve_mono" to reported capability levels. Implement _read_source_pixel_format to centralize reading the PixelFormat feature and call it from _configure_converter when needed so the backend always knows the source format before configuring conversion.
Rename internal source pixel format to _camera_pixel_format and centralize pixel-format handling. Add actual_pixel_format and actual_output_format properties, plus helpers (_read_camera_pixel_format, _is_camera_mono, _should_output_mono) to determine if the camera is mono and whether the backend should output mono frames. Update _configure_converter to use these helpers (emit Mono8 when preserve_mono + mono camera), remove the _output_is_mono flag and the old _read_source_pixel_format, and improve log messages. Also ensure the camera pixel format is read during startup after gain detection.
Add UI and backend support for reporting the camera backend's detected output format and pixel format. Introduce a detected output label with tooltip and move/rename the "preserve mono" checkbox into an Output row. Store/clear detected_output_format and detected_pixel_format in camera props, read actual_output_format from backends during probing, and set detected_output_format when pixel format indicates Mono. Add a mono indicator to camera list entries and update probe early-return logic to require both resolution and output format before skipping probing.
Expose actual_pixel_format and actual_output_format across backends and track the camera-reported formats for UI/telemetry. Aravis: add actual_pixel_format/actual_output_format properties and record _camera_pixel_format when setting pixel format. GenTL: initialize _camera_pixel_format/_actual_output_format, add _output_format_for_frame to infer output format from numpy frames, populate _actual_output_format on read, and record detected camera pixel format in several places. OpenCV: add actual_pixel_format (None) and actual_output_format (BGR8). These changes provide a consistent way to report native and emitted pixel formats to callers.
Replace the manual QWidget/QHBoxLayout construction for the "Output" settings row with the reusable make_two_field_row helper. This simplifies and standardizes the layout while preserving the same widgets (cam_preserve_mono_checkbox and detected_output_format_label) and applies key_width=60 and gap=40 before adding the row to dlg.settings_form.
Add human-friendly display IDs for multi-camera support. Introduce get_display_id(settings) which prefers settings.name, then properties[backend].device_name, and falls back to backend:index. Main window now stores per-camera display IDs, clears them on stop, passes labels to create_tiled_frame, and uses the display label when building the compact camera status lines. This separates internal camera IDs from user-facing labels for clearer UI.
Adjust tests to reflect new human-friendly display_id values and add a fallback case. Updated expectations in tests to assert display_id equals "GenTL cam" / "GenTL Cam" / "C1" where applicable, and added a unit test to verify get_display_id falls back to the backend index (e.g. "gentl:3") when camera name is empty. Also added assertions in the controller test to ensure the stable camera id is present in frames and correctly mapped to the display id. Files changed: tests/gui/test_rec_manager.py, tests/services/test_multicam_controller.py.
Delete the internal _create_tiled_frame implementation and the public frame accessors (get_frame, get_all_frames, get_tiled_frame) from MultiCameraController. This removes the tiled canvas construction logic and convenience getters for retrieving camera frames; update any callers to use the controller's new/alternate APIs or access frames via the updated code paths.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces end-to-end wiring for preserving monochrome (single-channel) frames through the GUI → backend → recording pipeline (initially for the Basler backend) to avoid costly Mono8→BGR expansion, and adds backend-reported pixel/output format telemetry to the camera configuration UI.
Changes:
- Add
preserve_monocamera setting and UI controls/telemetry for detected pixel/output formats. - Add Basler backend support for emitting Mono8 frames when requested, and pass mono-preservation intent into recording.
- Update camera display labeling to use a human-friendly
get_display_id()distinct from stable internal camera IDs, plus tests.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/services/test_video_recorder.py | Adds coverage for grayscale preservation vs default expansion in the recorder. |
| tests/services/test_multicam_controller.py | Updates expectations for display IDs and validates frame metadata carries display labels. |
| tests/gui/test_rec_manager.py | Adjusts RecorderStats import and display ID expectations in recording manager tests. |
| tests/cameras/backends/test_basler_backend.py | Extends Basler capability test to include mono preservation support. |
| dlclivegui/utils/stats.py | Moves RecorderStats into shared stats utilities. |
| dlclivegui/services/video_recorder.py | Adds convert_grayscale_to_rgb option and timing instrumentation around preprocess/write paths. |
| dlclivegui/services/multi_camera_controller.py | Implements get_display_id() and removes unused tiling/frame getter helpers. |
| dlclivegui/gui/recording_manager.py | Wires camera preserve_mono into recorder grayscale conversion behavior. |
| dlclivegui/gui/main_window.py | Uses display IDs for labeling tiles/metrics and threads display-id mapping through frame updates. |
| dlclivegui/gui/camera_config/ui_blocks.py | Adds preserve-mono checkbox and detected output format display row. |
| dlclivegui/gui/camera_config/camera_config_dialog.py | Persists preserve_mono, displays detected pixel/output formats, and adds probe-based recommendation logic. |
| dlclivegui/config.py | Adds preserve_mono setting and new timing flags for recorder/Basler. |
| dlclivegui/cameras/base.py | Adds preserve_mono capability flag and base telemetry properties for pixel format recommendation. |
| dlclivegui/cameras/backends/opencv_backend.py | Reports fixed output format telemetry (BGR8) for OpenCV backend. |
| dlclivegui/cameras/backends/gentl_backend.py | Adds output format inference and pixel-format telemetry plumbing. |
| dlclivegui/cameras/backends/basler_backend.py | Adds converter configuration for Mono8 vs BGR8 and exposes pixel/output format + recommendations. |
| dlclivegui/cameras/backends/aravis_backend.py | Adds pixel/output format properties and records requested pixel format. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Collect and propagate runtime camera info to improve recorder FPS selection and logging. - Disabled some verbose timing flags in config (REC_DO_LOG_TIMING, BASLER_DO_LOG_TIMING). - MultiCameraController: added runtime_info signal, stores per-camera runtime info, logs it, and exposes actual_fps_by_camera_id(). Workers emit backend runtime properties on open. - MainWindow: pass actual_fps_by_camera to RecordingManager when starting recordings. - RecordingManager: added backend namespace helper and _resolve_recording_fps(cam, cam_id, frame_rates) to prefer measured FPS, then backend-detected FPS, then requested cam.fps (or auto). Use resolved recorder_fps when creating VideoRecorder and log chosen values. - VideoRecorder: if frame_rate is missing/zero, fall back to 30 FPS and emit a warning; added startup info log; removed/commented the old pix_fmt/output_dimensions branch. These changes make recording frame rates more accurate by preferring runtime-measured FPS and provide clearer logging and safe fallbacks when FPS is unknown.
Fix the video encoding error path in VideoRecorder by replacing _process_timing with _writer_timing so encoding failures are recorded and logged against the correct timing object. This ensures error timing and maybe_log are invoked on the writer timing tracker rather than the wrong object.
Add _camera_pixel_format and _actual_output_format attributes to the Aravis backend and update the GenTL backend to set _camera_pixel_format (replacing the previous _actual_pixel_format assignment). This unifies pixel-format state handling across camera backends and prepares for explicit output format tracking.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Scope
This PR adds support for preserving monochrome camera frames through the GUI/backend/recording pipeline, with an initial implementation for the Basler backend.
The main goal is to avoid unnecessary Mono8 → BGR8 expansion for monochrome cameras, which caused large runtime costs for high-bandwidth setups (e.g. 4x100+FPS).
It also adds backend-reported pixel/output format telemetry to the camera configuration UI so users can see what the camera is producing and what format the backend emits. This is implemented for all backends.
TODO