Skip to content

Commit

Permalink
Merge pull request #141 from portugueslab/drift_preview
Browse files Browse the repository at this point in the history
Implementation of Drift Visualization Widget
  • Loading branch information
fedem-p committed Jul 10, 2022
2 parents 14bb522 + ea53315 commit ed79248
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 6 deletions.
105 changes: 105 additions & 0 deletions sashimi/gui/camera_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ def __init__(self, state: State, timer: QTimer, style: str):
self.refresh_display = True
self.is_first_frame = True
self.auto_contrast = True
self.is_exp_started = False
self.is_exp_ended = False
self.is_drift_active = False

s = self.get_fullframe_size()
self.image_shape = (1, s, s)
Expand All @@ -100,6 +103,22 @@ def __init__(self, state: State, timer: QTimer, style: str):
),
blending="translucent",
name="frame_layer",
visible=True,
)

# create drift layer and set it as not visible
self.drift_layer = self.viewer.add_image(
np.zeros(
[
1,
5,
5,
]
),
blending="additive",
name="drift_layer",
colormap="red",
visible=False,
)

# Add square ROI of size max image size:
Expand Down Expand Up @@ -135,8 +154,15 @@ def __init__(self, state: State, timer: QTimer, style: str):
self.contrast_range = ContrastSettings()
self.wid_contrast_range = ParameterGui(self.contrast_range)

self.active_drift_chk = QCheckBox("Activate Drift Reference")
self.display_drift_chk = QCheckBox("Visualize/Hide Drift Reference")
self.display_frame_chk = QCheckBox("Visualize/Hide Live View")

self.bottom_layout.addWidget(self.auto_contrast_chk)
self.bottom_layout.addWidget(self.wid_contrast_range)
self.bottom_layout.addWidget(self.active_drift_chk)
self.bottom_layout.addWidget(self.display_drift_chk)
self.bottom_layout.addWidget(self.display_frame_chk)

self.bottom_layout.addStretch()

Expand All @@ -148,6 +174,17 @@ def __init__(self, state: State, timer: QTimer, style: str):
self.auto_contrast_chk.stateChanged.connect(self.update_auto_contrast)
self.contrast_range.sig_param_changed.connect(self.set_manual_contrast)

# connect drift widget
self.active_drift_chk.clicked.connect(self.activate_drift_reference)
self.display_drift_chk.clicked.connect(self.display_drift_reference)
self.display_frame_chk.clicked.connect(self.display_frame_reference)

self.display_frame_chk.setChecked(True)
self.display_frame_chk.setEnabled(False)
self.display_drift_chk.setEnabled(
False
) # only enabled if drift reference is activated

self.auto_contrast_chk.setChecked(True)

self.state.camera_settings.sig_param_changed.connect(
Expand Down Expand Up @@ -210,6 +247,14 @@ def refresh_image(self):
self.frame_layer.data = current_image
# self.frame_layer.scale = [self.voxel_size[0] / self.voxel_size[1], 1.0, 1.0]

# If experiment is started/ended call the display drift function
if self.is_exp_started:
self.display_drift(frame=current_image, is_exp_running=True)
self.is_exp_started = False
elif self.is_exp_ended:
self.display_drift(is_exp_running=False)
self.is_exp_ended = False

# Check if anything changed in the image shape, which would mean that changes of the contrast
# are required (in case a parameter update was missed).
if self.is_first_frame or self.image_shape != current_image.shape:
Expand All @@ -229,8 +274,10 @@ def toggle_ndims(self):
"""
if self.ndisplay_button.isChecked():
self.frame_layer.scale = [self.voxel_size[0] / self.voxel_size[1], 1.0, 1.0]
self.drift_layer.scale = [self.voxel_size[0] / self.voxel_size[1], 1.0, 1.0]
else:
self.frame_layer.scale = [1.0, 1.0, 1.0]
self.drift_layer.scale = [1.0, 1.0, 1.0]

def update_current_plane(self, _):
self.state.current_plane = self.viewer.dims.current_step[0]
Expand All @@ -254,6 +301,64 @@ def update_auto_contrast(self, is_checked):
def set_manual_contrast(self):
self.frame_layer.contrast_limits = self.contrast_range.contrast_range

def activate_drift_reference(self) -> None:
"""
If active the first volume during the experiment
will be saved and overlayed to the viewer
"""
self.is_drift_active = not self.is_drift_active

def display_drift_reference(self) -> None:
"""
Toggles the visualization of the drift layer on/off
"""
# if not None or empty
if self.drift_layer.data is not None or np.any(self.drift_layer.data):
self.drift_layer.visible = not self.drift_layer.visible

def display_frame_reference(self) -> None:
"""
Toggles the visualization of the main layer on/off
"""
self.frame_layer.visible = not self.frame_layer.visible

def display_drift(self, frame=None, is_exp_running=False) -> None:
"""
If the conditions are right displays the drift layer,
else it will disable the buttons and reset the drift layer
Args:
frame (np.ndarray): current image used to refresh the viewer after the experiment started.
Defaults to None.
is_exp_running (bool): check to discriminate between start and end of the experiment.
Defaults to False.
"""
# if experiment started, button is selected and frame has been generated
if is_exp_running and self.is_drift_active and frame is not None:
# set layer data
self.drift_layer.data = frame
self.drift_layer.contrast_limits = self.frame_layer.contrast_limits
# set buttons
# -> drift is active -> all buttons on
self.display_drift_chk.setEnabled(True)
self.display_drift_chk.setChecked(True)
self.display_frame_chk.setChecked(True)
self.display_frame_chk.setEnabled(True)
# set layer visibility
self.drift_layer.visible = True
else:
# set buttons
# -> drift inactive all buttons off
self.display_drift_chk.setEnabled(False)
self.display_drift_chk.setChecked(False)
self.display_frame_chk.setChecked(True) # live view on
self.display_frame_chk.setEnabled(False)
# set layer visibility
self.drift_layer.visible = False
self.frame_layer.visible = True # live view on
# reset drift image
self.drift_layer.data = self.frame_layer.data * 0


class CameraSettingsWidget(QWidget):
"""Widget to modify parameters for the camera.
Expand Down
11 changes: 10 additions & 1 deletion sashimi/gui/main_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,18 +146,27 @@ def check_end_experiment(self):
# check if experiment started or ended and update gui enabling
if self.st.is_exp_started():
self.set_enabled_gui(enable=False)
# pass down to the display window the information
self.wid_display.is_exp_started = True

elif self.st.is_exp_ended():
self.set_enabled_gui(enable=True)
# pass down to the display window the information
self.wid_display.is_exp_ended = True

def set_enabled_gui(self, enable):
"""Disable all the gui elements during the experiment"""
"""
Disable all the gui elements during the experiment
and re-enables them after
"""
self.menuBar().setEnabled(enable)
self.wid_laser.setEnabled(enable)
self.wid_status.setEnabled(enable)
self.wid_scan.setEnabled(enable)
self.wid_camera.setEnabled(enable)
self.wid_save_options.setEnabled(enable)
self.wid_display.auto_contrast_chk.setEnabled(enable)
self.wid_display.active_drift_chk.setEnabled(enable)


class StatusWidget(QTabWidget):
Expand Down
18 changes: 13 additions & 5 deletions sashimi/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,8 +554,11 @@ def send_scansave_settings(self):
self.saver.saving_parameter_queue.put(self.save_params)
self.dispatcher.n_planes_queue.put(self.n_planes)

def start_experiment(self):
# TODO disable the GUI except the abort button
def start_experiment(self) -> None:
"""
Sets all the signals and cleans the queue
to trigger the start of the experiment
"""
self.current_exp_state = GlobalState.EXPERIMENT_RUNNING
self.logger.log_message("started experiment")
self.scanner.wait_signal.set()
Expand All @@ -566,7 +569,11 @@ def start_experiment(self):
time.sleep(0.01)
self.is_saving_event.set()

def end_experiment(self):
def end_experiment(self) -> None:
"""
Sets all the signals and cleans the queue
to trigger the end of the experiment
"""
self.logger.log_message("experiment ended")
self.is_saving_event.clear()
self.experiment_start_event.clear()
Expand All @@ -577,7 +584,7 @@ def end_experiment(self):
def is_exp_started(self) -> bool:
"""
check if the experiment has started:
looks for tha change in the value hold by current_exp_running
looks for tha change in the value hold by current_exp_state
Returns:
bool
Expand All @@ -594,7 +601,7 @@ def is_exp_started(self) -> bool:
def is_exp_ended(self) -> bool:
"""
check if the experiment has ended:
looks for tha change in the value hold by current_exp_running
looks for tha change in the value hold by current_exp_state
Returns:
bool
Expand Down Expand Up @@ -645,6 +652,7 @@ def obtain_noise_average(self, n_images=50):
self.dispatcher.calibration_ref_queue.put(self.calibration_ref)

def reset_noise_subtraction(self):

self.calibration_ref = None
self.noise_subtraction_active.clear()

Expand Down

0 comments on commit ed79248

Please sign in to comment.