Skip to content

Commit fa1365b

Browse files
committed
Use display labels for multi-camera GUI
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.
1 parent 7c189d2 commit fa1365b

2 files changed

Lines changed: 26 additions & 4 deletions

File tree

dlclivegui/gui/main_window.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
scan_processor_package,
6666
)
6767
from ..services.dlc_processor import DLCLiveProcessor, PoseResult
68-
from ..services.multi_camera_controller import MultiCameraController, MultiFrameData, get_camera_id
68+
from ..services.multi_camera_controller import MultiCameraController, MultiFrameData, get_camera_id, get_display_id
6969
from ..utils.display import BBoxColors, compute_tile_info, create_tiled_frame, draw_bbox, draw_pose
7070
from ..utils.settings_store import DLCLiveGUISettingsStore, ModelPathStore
7171
from ..utils.stats import format_dlc_stats
@@ -164,6 +164,7 @@ def __init__(self, config: ApplicationSettings | None = None):
164164
# Multi-camera state
165165
self._multi_camera_mode = False
166166
self._multi_camera_frames: dict[str, np.ndarray] = {}
167+
self._multi_camera_display_ids: dict[str, str] = {} # camera_id -> display_id (for labeling)
167168
# DLC pose rendering info for tiled view
168169
self._dlc_tile_offset: tuple[int, int] = (0, 0) # (x, y) offset in tiled frame
169170
self._dlc_tile_scale: tuple[float, float] = (1.0, 1.0) # (scale_x, scale_y)
@@ -1379,6 +1380,7 @@ def _on_multi_frame_processing_ready(self, frame_data: MultiFrameData) -> None:
13791380
2. Recording (queued writes, non-blocking)
13801381
"""
13811382
self._multi_camera_frames = frame_data.frames
1383+
self._multi_camera_display_ids = frame_data.display_ids or {}
13821384
src_id = frame_data.source_camera_id
13831385
if src_id:
13841386
self._fps_tracker.note_frame(src_id) # Track FPS
@@ -1439,6 +1441,7 @@ def _on_multi_frame_display_ready(self, frame_data: MultiFrameData) -> None:
14391441
Called at GUI_MAX_DISPLAY_FPS, not at camera capture FPS for performance reasons.
14401442
"""
14411443
self._multi_camera_frames = frame_data.frames
1444+
self._multi_camera_display_ids = frame_data.display_ids or {}
14421445
self._display_dirty = True
14431446

14441447
def _on_multi_camera_started(self) -> None:
@@ -1459,6 +1462,7 @@ def _on_multi_camera_stopped(self) -> None:
14591462
self.stop_preview_button.setEnabled(False)
14601463
self._current_frame = None
14611464
self._multi_camera_frames.clear()
1465+
self._multi_camera_display_ids.clear()
14621466
self.video_label.setPixmap(QPixmap())
14631467
self.video_label.setText("Camera preview not started")
14641468
self.statusBar().showMessage("Multi-camera preview stopped", 3000)
@@ -1593,6 +1597,7 @@ def _start_preview(self) -> None:
15931597
self._raw_frame = None
15941598
self._last_pose = None
15951599
self._multi_camera_frames.clear()
1600+
self._multi_camera_display_ids.clear()
15961601
self._fps_tracker.clear()
15971602
self._last_display_time = 0.0
15981603

@@ -1735,7 +1740,7 @@ def _update_display_from_pending(self) -> None:
17351740
self._display_dirty = False
17361741

17371742
# Create tiled frame on demand (moved from camera thread for performance)
1738-
tiled = create_tiled_frame(self._multi_camera_frames)
1743+
tiled = create_tiled_frame(self._multi_camera_frames, labels=self._multi_camera_display_ids)
17391744
if tiled is not None:
17401745
self._current_frame = tiled
17411746
self._update_video_display(tiled)
@@ -1751,10 +1756,11 @@ def _update_metrics(self) -> None:
17511756
active_cams = self._config.multi_camera.get_active_cameras()
17521757
lines = []
17531758
for cam in active_cams:
1754-
cam_id = get_camera_id(cam) # e.g., "opencv:0" or "pylon:1"
1759+
cam_id = get_camera_id(cam)
1760+
display_id = get_display_id(cam)
17551761
fps = self._fps_tracker.fps(cam_id)
17561762
# Make a compact label: name [backend:index] @ fps
1757-
label = f"{cam.name or cam_id} [{cam.backend}:{cam.index}]"
1763+
label = f"{display_id} [{cam.backend}:{cam.index}]"
17581764
if fps > 0:
17591765
lines.append(f"{label} @ {fps:.1f} fps")
17601766
else:

dlclivegui/services/multi_camera_controller.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,22 @@ def _log_trigger_wait_throttled(self, exc: BaseException) -> None:
207207

208208

209209
def get_display_id(settings: CameraSettings) -> str:
210+
"""Return the human-friendly camera label used for GUI display.
211+
Intentionally different from get_camera_id(), which should return a stable
212+
internal, reliable and unambiguous identity and may contain serials or machine paths.
213+
"""
214+
name = str(getattr(settings, "name", "") or "").strip()
215+
if name:
216+
return name
217+
218+
backend = (settings.backend or "").lower()
219+
props = settings.properties if isinstance(settings.properties, dict) else {}
220+
ns = props.get(backend, {}) if isinstance(props.get(backend), dict) else {}
221+
222+
device_name = str(ns.get("device_name", "") or "").strip()
223+
if device_name:
224+
return device_name
225+
210226
return f"{settings.backend}:{settings.index}"
211227

212228

0 commit comments

Comments
 (0)