Skip to content

Commit

Permalink
Merge pull request #134 from Alpaca233/laser_af_bug_fix
Browse files Browse the repository at this point in the history
laser autofocus UX improvement
  • Loading branch information
hongquanli authored Feb 26, 2025
2 parents 948644a + 7a0216a commit 399fbb2
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 11 deletions.
13 changes: 9 additions & 4 deletions software/control/core/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1601,7 +1601,7 @@ def acquire_at_position(self, region_id, current_path, fov):
print(f"Acquiring image: ID={file_ID}, Metadata={metadata}")

# laser af characterization mode
if LASER_AF_CHARACTERIZATION_MODE:
if self.microscope.laserAutofocusController.characterization_mode:
image = self.microscope.laserAutofocusController.get_image()
saving_path = os.path.join(current_path, file_ID + "_laser af camera" + ".bmp")
iio.imwrite(saving_path, image)
Expand Down Expand Up @@ -3748,9 +3748,11 @@ def update_laser_af_settings(self, objective: str, updates: Dict[str, Any]) -> N
self.autofocus_configurations[objective] = config.model_copy(update=updates)


class ConfigurationManager:
class ConfigurationManager(QObject):
"""Main configuration manager that coordinates channel and autofocus configurations."""

signal_profile_loaded = Signal()

def __init__(
self,
channel_manager: ChannelConfigurationManager,
Expand Down Expand Up @@ -3800,6 +3802,8 @@ def load_profile(self, profile_name: str) -> None:
if self.laser_af_manager:
self.laser_af_manager.load_configurations(objective)

self.signal_profile_loaded.emit()

def create_new_profile(self, profile_name: str) -> None:
"""Create a new profile using current configurations."""
new_profile_path = self.base_config_path / profile_name
Expand Down Expand Up @@ -4638,6 +4642,7 @@ def __init__(
self.piezo = piezo
self.objectiveStore = objectiveStore
self.laserAFSettingManager = laserAFSettingManager
self.characterization_mode = LASER_AF_CHARACTERIZATION_MODE

self.is_initialized = False

Expand Down Expand Up @@ -4991,8 +4996,8 @@ def set_reference(self) -> bool:

return True

def on_objective_changed(self) -> None:
"""Handle objective change event.
def on_settings_changed(self) -> None:
"""Handle objective change or profile load event.
This method is called when the objective changes. It resets the initialization
status and loads the cached configuration for the new objective.
Expand Down
22 changes: 19 additions & 3 deletions software/control/gui_hcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,11 @@ def makeConnections(self):
self.wellSelectionWidget.signal_wellSelected.connect(self.wellplateMultiPointWidget.update_well_coordinates)
self.objectivesWidget.signal_objective_changed.connect(self.wellplateMultiPointWidget.update_coordinates)

self.configurationManager.signal_profile_loaded.connect(
lambda: self.liveControlWidget.update_microscope_mode_by_name(
self.liveControlWidget.currentConfiguration.name
)
)
self.objectivesWidget.signal_objective_changed.connect(
lambda: self.liveControlWidget.update_microscope_mode_by_name(
self.liveControlWidget.currentConfiguration.name
Expand All @@ -990,12 +995,13 @@ def makeConnections(self):

if SUPPORT_LASER_AUTOFOCUS:

def connect_objective_changed_laser_af():
self.laserAutofocusController.on_objective_changed()
def slot_settings_changed_laser_af():
self.laserAutofocusController.on_settings_changed()
self.laserAutofocusControlWidget.update_init_state()
self.laserAutofocusSettingWidget.update_values()

self.objectivesWidget.signal_objective_changed.connect(connect_objective_changed_laser_af)
self.configurationManager.signal_profile_loaded.connect(slot_settings_changed_laser_af)
self.objectivesWidget.signal_objective_changed.connect(slot_settings_changed_laser_af)
self.laserAutofocusSettingWidget.signal_newExposureTime.connect(
self.cameraSettingWidget_focus_camera.set_exposure_time
)
Expand Down Expand Up @@ -1269,6 +1275,16 @@ def onDisplayTabChanged(self, index):
if hasattr(current_widget, "viewer"):
current_widget.activate()

# Stop focus camera live if not on laser focus tab
if SUPPORT_LASER_AUTOFOCUS:
is_laser_focus_tab = self.imageDisplayTabs.tabText(index) == "Laser-Based Focus"

if hasattr(self, "dock_wellSelection"):
self.dock_wellSelection.setVisible(not is_laser_focus_tab)

if not is_laser_focus_tab:
self.laserAutofocusSettingWidget.stop_live()

def onWellplateChanged(self, format_):
if isinstance(format_, QVariant):
format_ = format_.value()
Expand Down
17 changes: 13 additions & 4 deletions software/control/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ def __init__(self, streamHandler, liveController, laserAutofocusController, stre

self.spinboxes = {}
self.init_ui()
self.update_calibration_label()

def init_ui(self):
layout = QVBoxLayout()
Expand Down Expand Up @@ -479,7 +480,7 @@ def init_ui(self):
characterization_group = QFrame()
characterization_layout = QHBoxLayout()
self.characterization_checkbox = QCheckBox("Laser AF Characterization Mode")
self.characterization_checkbox.setChecked(False)
self.characterization_checkbox.setChecked(self.laserAutofocusController.characterization_mode)
characterization_layout.addWidget(self.characterization_checkbox)
characterization_group.setLayout(characterization_layout)

Expand All @@ -498,7 +499,7 @@ def init_ui(self):
self.analog_gain_spinbox.valueChanged.connect(self.update_analog_gain)
self.apply_button.clicked.connect(self.apply_settings)
self.run_spot_detection_button.clicked.connect(self.run_spot_detection)
self.characterization_checkbox.stateChanged.connect(self.toggle_characterization_mode)
self.characterization_checkbox.toggled.connect(self.toggle_characterization_mode)

def _add_spinbox(
self, layout, label: str, property_name: str, min_val: float, max_val: float, decimals: int
Expand Down Expand Up @@ -530,9 +531,13 @@ def toggle_live(self, pressed):
self.btn_live.setText("Start Live")
self.run_spot_detection_button.setEnabled(True)

def stop_live(self):
"""Used for stopping live when switching to other tabs"""
self.toggle_live(False)
self.btn_live.setChecked(False)

def toggle_characterization_mode(self, state):
global LASER_AF_CHARACTERIZATION_MODE
LASER_AF_CHARACTERIZATION_MODE = bool(state == Qt.Checked)
self.laserAutofocusController.characterization_mode = state

def update_exposure_time(self, value):
self.signal_newExposureTime.emit(value)
Expand All @@ -557,6 +562,8 @@ def update_values(self):
if index >= 0:
self.spot_mode_combo.setCurrentIndex(index)

self.update_calibration_label()

def apply_settings(self):
updates = {
"laser_af_averaging_n": int(self.spinboxes["laser_af_averaging_n"].value()),
Expand All @@ -578,7 +585,9 @@ def apply_settings(self):
self.laserAutofocusController.set_laser_af_properties(updates)
self.laserAutofocusController.initialize_auto()
self.signal_apply_settings.emit()
self.update_calibration_label()

def update_calibration_label(self):
# Show calibration result
# Clear previous calibration label if it exists
if hasattr(self, "calibration_label"):
Expand Down

0 comments on commit 399fbb2

Please sign in to comment.