99import time
1010from pathlib import Path
1111
12- os .environ ["PYLON_CAMEMU" ] = "2"
13-
12+ # NOTE @C-Achard: his could be added in settings eventually
13+ # Forces pypylon to create 2 emulation virtual cameras,
14+ # mostly for testing. This shold not be enabled for release.
15+ # os.environ["PYLON_CAMEMU"] = "2"
1416import cv2
1517import numpy as np
1618from PySide6 .QtCore import QRect , QSettings , Qt , QTimer , QUrl
7274from ..utils .stats import format_dlc_stats
7375from ..utils .utils import FPSTracker
7476from .camera_config .camera_config_dialog import CameraConfigDialog
77+ from .misc import color_dropdowns as color_ui
78+ from .misc import layouts as lyts
7579from .misc .drag_spinbox import ScrubSpinBox
7680from .misc .eliding_label import ElidingPathLabel
7781from .recording_manager import RecordingManager
@@ -306,7 +310,7 @@ def _setup_ui(self) -> None:
306310 controls_layout .addWidget (self ._build_camera_group ())
307311 controls_layout .addWidget (self ._build_dlc_group ())
308312 controls_layout .addWidget (self ._build_recording_group ())
309- controls_layout .addWidget (self ._build_bbox_group ())
313+ controls_layout .addWidget (self ._build_viz_group ())
310314
311315 # Preview/Stop buttons at bottom of controls - wrap in widget
312316 button_bar_widget = QWidget ()
@@ -378,7 +382,7 @@ def _build_menus(self) -> None:
378382 self ._init_theme_actions ()
379383
380384 def _build_camera_group (self ) -> QGroupBox :
381- group = QGroupBox ("Camera settings " )
385+ group = QGroupBox ("Camera" )
382386 form = QFormLayout (group )
383387
384388 # Camera config button - opens dialog for all camera configuration
@@ -397,7 +401,7 @@ def _build_camera_group(self) -> QGroupBox:
397401 return group
398402
399403 def _build_dlc_group (self ) -> QGroupBox :
400- group = QGroupBox ("DLCLive settings " )
404+ group = QGroupBox ("DLCLive" )
401405 form = QFormLayout (group )
402406
403407 path_layout = QHBoxLayout ()
@@ -443,7 +447,7 @@ def _build_dlc_group(self) -> QGroupBox:
443447 # form.addRow("Additional options", self.additional_options_edit)
444448 self .dlc_camera_combo = QComboBox ()
445449 self .dlc_camera_combo .setToolTip ("Select which camera to use for pose inference" )
446- form .addRow ("Inference Camera " , self .dlc_camera_combo )
450+ form .addRow ("Inference camera " , self .dlc_camera_combo )
447451
448452 # Wrap inference buttons in a widget to prevent shifting
449453 inference_button_widget = QWidget ()
@@ -461,9 +465,9 @@ def _build_dlc_group(self) -> QGroupBox:
461465 inference_buttons .addWidget (self .stop_inference_button )
462466 form .addRow (inference_button_widget )
463467
464- self .show_predictions_checkbox = QCheckBox ("Display pose predictions" )
465- self .show_predictions_checkbox .setChecked (True )
466- form .addRow (self .show_predictions_checkbox )
468+ # self.show_predictions_checkbox = QCheckBox("Display pose predictions")
469+ # self.show_predictions_checkbox.setChecked(True)
470+ # form.addRow(self.show_predictions_checkbox)
467471
468472 self .allow_processor_ctrl_checkbox = QCheckBox ("Allow processor-based control" )
469473 self .allow_processor_ctrl_checkbox .setChecked (False )
@@ -495,15 +499,19 @@ def _build_recording_group(self) -> QGroupBox:
495499 # Session + run name
496500 self .session_name_edit = QLineEdit ()
497501 self .session_name_edit .setPlaceholderText ("e.g. mouseA_day1" )
498- form .addRow ("Session name" , self .session_name_edit )
502+ # form.addRow("Session name", self.session_name_edit)
499503
500504 self .use_timestamp_checkbox = QCheckBox ("Use timestamp for run folder name" )
501505 self .use_timestamp_checkbox .setChecked (True )
502506 self .use_timestamp_checkbox .setToolTip (
503507 "If checked, run folder will be run_YYYYMMDD_HHMMSS_mmm.\n "
504508 "If unchecked, run folder will be run_0001, run_0002, ..."
505509 )
506- form .addRow ("" , self .use_timestamp_checkbox )
510+ # form.addRow("", self.use_timestamp_checkbox)
511+ session_opts = lyts .make_two_field_row (
512+ "Session name" , self .session_name_edit , None , self .use_timestamp_checkbox , key_width = 100
513+ )
514+ form .addRow (session_opts )
507515
508516 # Show recording path preview
509517
@@ -575,7 +583,7 @@ def _build_recording_group(self) -> QGroupBox:
575583
576584 ## CRF
577585 crf_label = QLabel ("CRF" )
578- crf_label .setSizePolicy (QSizePolicy .Fixed , QSizePolicy .Preferred )
586+ crf_label .setSizePolicy (QSizePolicy .MinimumExpanding , QSizePolicy .Preferred )
579587 grid .addWidget (crf_label , 0 , 4 )
580588
581589 self .crf_spin = QSpinBox ()
@@ -618,24 +626,55 @@ def _build_recording_group(self) -> QGroupBox:
618626
619627 return group
620628
621- def _build_bbox_group (self ) -> QGroupBox :
622- group = QGroupBox ("Bounding Box Visualization" )
629+ def _build_viz_group (self ) -> QGroupBox :
630+ group = QGroupBox ("Visualization" )
623631 form = QFormLayout (group )
632+ self .show_predictions_checkbox = QCheckBox ("Display pose predictions" )
633+ self .show_predictions_checkbox .setChecked (True )
634+
635+ self .cmap_combo = QComboBox ()
636+ self .cmap_combo .setSizePolicy (QSizePolicy .Minimum , QSizePolicy .Preferred )
637+ self .cmap_combo .setToolTip ("Select colormap to use when displaying keypoints (bodypart-based coloring)" )
638+ color_ui .populate_colormap_combo (
639+ self .cmap_combo ,
640+ current = self ._colormap ,
641+ favorites_first = ["turbo" , "jet" , "hsv" ],
642+ exclude_reversed = True ,
643+ filters = {"cet_" : 5 }, # include only first 5 colormaps from the 'cet_' family to avoid redundant options
644+ )
645+ lyts .enable_combo_shrink_to_current (self .cmap_combo , min_width = 80 , max_width = 200 )
646+
647+ keypoints_settings = lyts .make_two_field_row (
648+ "Keypoint colormap: " ,
649+ self .cmap_combo ,
650+ None ,
651+ self .show_predictions_checkbox ,
652+ key_width = None ,
653+ left_stretch = 0 ,
654+ right_stretch = 0 ,
655+ )
656+ form .addRow (keypoints_settings )
624657
625- row_widget = QWidget ()
626- checkbox_layout = QHBoxLayout (row_widget )
627- checkbox_layout .setContentsMargins (0 , 0 , 0 , 0 )
628658 self .bbox_enabled_checkbox = QCheckBox ("Show bounding box" )
629659 self .bbox_enabled_checkbox .setChecked (False )
630- checkbox_layout .addWidget (self .bbox_enabled_checkbox )
631- checkbox_layout .addWidget (QLabel ("Color:" ))
632660
633661 self .bbox_color_combo = QComboBox ()
634- self ._populate_bbox_color_combo_with_swatches ()
662+ self .bbox_color_combo .setToolTip ("Select color for bounding box" )
663+ self .bbox_color_combo .setSizePolicy (QSizePolicy .Minimum , QSizePolicy .Preferred )
664+ color_ui .populate_bbox_color_combo (self .bbox_color_combo , BBoxColors , current_bgr = self ._bbox_color )
635665 self .bbox_color_combo .setCurrentIndex (0 )
636- checkbox_layout .addWidget (self .bbox_color_combo )
637- checkbox_layout .addStretch (1 )
638- form .addRow (row_widget )
666+ lyts .enable_combo_shrink_to_current (self .bbox_color_combo , min_width = 80 , max_width = 200 )
667+
668+ bbox_settings = lyts .make_two_field_row (
669+ "Bounding box color: " ,
670+ self .bbox_color_combo ,
671+ None ,
672+ self .bbox_enabled_checkbox ,
673+ key_width = None ,
674+ left_stretch = 0 ,
675+ right_stretch = 0 ,
676+ )
677+ form .addRow (bbox_settings )
639678
640679 bbox_layout = QHBoxLayout ()
641680 self .bbox_x0_spin = ScrubSpinBox ()
@@ -679,7 +718,10 @@ def _connect_signals(self) -> None:
679718 # Camera config dialog
680719 self .config_cameras_button .clicked .connect (self ._open_camera_config_dialog )
681720
682- # Connect bounding box controls
721+ # Visualization settings
722+ ## Colormap change
723+ self .cmap_combo .currentIndexChanged .connect (self ._on_colormap_changed )
724+ ## Connect bounding box controls
683725 self .bbox_enabled_checkbox .stateChanged .connect (self ._on_bbox_changed )
684726 self .bbox_x0_spin .valueChanged .connect (self ._on_bbox_changed )
685727 self .bbox_y0_spin .valueChanged .connect (self ._on_bbox_changed )
@@ -760,9 +802,11 @@ def _apply_config(self, config: ApplicationSettings) -> None:
760802 viz = config .visualization
761803 self ._p_cutoff = viz .p_cutoff
762804 self ._colormap = viz .colormap
805+ if hasattr (self , "cmap_combo" ):
806+ color_ui .set_cmap_combo_from_name (self .cmap_combo , self ._colormap , fallback = "viridis" )
763807 self ._bbox_color = viz .get_bbox_color_bgr ()
764808 if hasattr (self , "bbox_color_combo" ):
765- self . _set_combo_from_color ( self ._bbox_color )
809+ color_ui . set_bbox_combo_from_bgr ( self . bbox_color_combo , self ._bbox_color )
766810
767811 # Update DLC camera list
768812 self ._refresh_dlc_camera_list ()
@@ -1050,11 +1094,16 @@ def _on_use_timestamp_changed(self, _state: int) -> None:
10501094 self ._settings_store .set_use_timestamp (self .use_timestamp_checkbox .isChecked ())
10511095 self ._update_recording_path_preview ()
10521096
1097+ def _on_colormap_changed (self , _index : int ) -> None :
1098+ self ._colormap = color_ui .get_cmap_name_from_combo (self .cmap_combo , fallback = self ._colormap )
1099+ if self ._current_frame is not None :
1100+ self ._display_frame (self ._current_frame , force = True )
1101+
10531102 def _on_bbox_color_changed (self , _index : int ) -> None :
1054- enum_item = self .bbox_color_combo . currentData ( )
1055- if enum_item is None :
1103+ bgr = color_ui . get_bbox_bgr_from_combo ( self .bbox_color_combo , fallback = self . _bbox_color )
1104+ if bgr is None :
10561105 return
1057- self ._bbox_color = enum_item . value
1106+ self ._bbox_color = bgr
10581107 if self ._current_frame is not None :
10591108 self ._display_frame (self ._current_frame , force = True )
10601109
0 commit comments