Skip to content

Commit

Permalink
more plumbing
Browse files Browse the repository at this point in the history
  • Loading branch information
ianohara committed Feb 24, 2025
1 parent 31e8a7b commit 6f8710d
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 65 deletions.
72 changes: 29 additions & 43 deletions software/control/core/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from control.microcontroller import Microcontroller
from control.piezo import PiezoStage
from squid.abc import AbstractStage, AbstractCamera, CameraAcquisitionMode
from squid.abc import AbstractStage, AbstractCamera, CameraAcquisitionMode, CameraFrame
import squid.logging

# qt libraries
Expand Down Expand Up @@ -197,7 +197,7 @@ def on_new_frame(self, frame: squid.abc.CameraFrame):
if self.track_flag and time_now - self.timestamp_last_track >= 1 / self.fps_track:
# track is a blocking operation - it needs to be
# @@@ will cropping before emitting the signal lead to speedup?
self.packet_image_for_tracking.emit(image_cropped, frame.frame_ID, frame.timestamp)
self.packet_image_for_tracking.emit(image_cropped, frame.frame_id, frame.timestamp)
self.timestamp_last_track = time_now

self.handler_busy = False
Expand Down Expand Up @@ -559,7 +559,9 @@ def set_illumination(self, illumination_source, intensity, update_channel_settin
time.sleep(ZABER_EMISSION_FILTER_WHEEL_DELAY_MS / 1000)
else:
time.sleep(
max(0, ZABER_EMISSION_FILTER_WHEEL_DELAY_MS / 1000 - self.camera.strobe_delay_us / 1e6)
max(
0, ZABER_EMISSION_FILTER_WHEEL_DELAY_MS / 1000 - self.camera.get_strobe_time() / 1e3
)
)
except Exception as e:
print("not setting emission filter position due to " + str(e))
Expand All @@ -581,7 +583,7 @@ def set_illumination(self, illumination_source, intensity, update_channel_settin
time.sleep(OPTOSPIN_EMISSION_FILTER_WHEEL_DELAY_MS / 1000)
elif self.trigger_mode == TriggerMode.HARDWARE:
time.sleep(
max(0, OPTOSPIN_EMISSION_FILTER_WHEEL_DELAY_MS / 1000 - self.camera.strobe_delay_us / 1e6)
max(0, OPTOSPIN_EMISSION_FILTER_WHEEL_DELAY_MS / 1000 - self.camera.get_strobe_time() / 1e3)
)
except Exception as e:
print("not setting emission filter position due to " + str(e))
Expand Down Expand Up @@ -1015,7 +1017,6 @@ def run_autofocus(self):
image = self.camera.read_frame()
elif self.liveController.trigger_mode == TriggerMode.HARDWARE:
if "Fluorescence" in self.liveController.currentConfiguration.name and ENABLE_NL5 and NL5_USE_DOUT:
self.camera.image_is_ready = False # to remove
self.microscope.nl5.start_acquisition()
# TODO(imo): This used to use the "reset_image_ready_flag=False" arg, but oinly the toupcam camera implementation had the
# "reset_image_ready_flag" arg, so this is broken for all other cameras.
Expand Down Expand Up @@ -1119,7 +1120,7 @@ def autofocus(self, focus_map_override=False):
self.was_live_before_autofocus = False

# temporarily disable call back -> image does not go through streamHandler
if self.camera.callback_is_enabled:
if self.camera.get_callbacks_enabled():
self.callback_was_enabled_before_autofocus = True
self.camera.enable_callbacks(False)
else:
Expand Down Expand Up @@ -1757,27 +1758,22 @@ def acquire_camera_image(self, config, file_ID, current_path, current_round_imag
self.wait_till_operation_is_completed()

# trigger acquisition (including turning on the illumination) and read frame
camera_illumination_time = self.camera.get_exposure_time()
if self.liveController.trigger_mode == TriggerMode.SOFTWARE:
self.liveController.turn_on_illumination()
self.wait_till_operation_is_completed()
self.camera.send_trigger()
image = self.camera.read_frame()
camera_illumination_time = None
elif self.liveController.trigger_mode == TriggerMode.HARDWARE:
if "Fluorescence" in config.name and ENABLE_NL5 and NL5_USE_DOUT:
self.camera.image_is_ready = False # to remove
# TODO(imo): This used to use the "reset_image_ready_flag=False" on the read_frame, but oinly the toupcam camera implementation had the
# "reset_image_ready_flag" arg, so this is broken for all other cameras. Also this used to do some other funky stuff like setting internal camera flags.
# I am pretty sure this is broken!
self.microscope.nl5.start_acquisition()
# TODO(imo): This used to use the "reset_image_ready_flag=False" arg, but oinly the toupcam camera implementation had the
# "reset_image_ready_flag" arg, so this is broken for all other cameras.
image = self.camera.read_frame()
else:
self.microcontroller.send_hardware_trigger(
control_illumination=True, illumination_on_time_us=self.camera.get_exposure_time() * 1000
)
image = self.camera.read_frame()
else: # continuous acquisition
image = self.camera.read_frame()

if image is None:
self.camera.send_trigger(illumination_time=camera_illumination_time)
camera_frame = self.camera.read_camera_frame()
image = camera_frame.frame
if not camera_frame or image is None:
self._log.warning("self.camera.read_frame() returned None")
return

Expand All @@ -1795,7 +1791,7 @@ def acquire_camera_image(self, config, file_ID, current_path, current_round_imag
self.image_to_display.emit(image_to_display)
self.image_to_display_multi.emit(image_to_display, config.illumination_source)

self.save_image(image, file_ID, config, current_path)
self.save_image(image, file_ID, config, current_path, camera_frame.is_color())
self.update_napari(image, config.name, k)

current_round_images[config.name] = np.copy(image)
Expand Down Expand Up @@ -1823,14 +1819,9 @@ def acquire_rgb_image(self, config, file_ID, current_path, current_round_images,
# TODO(imo): use illum controller
self.liveController.turn_on_illumination()
self.wait_till_operation_is_completed()
self.camera.send_trigger()

elif self.liveController.trigger_mode == TriggerMode.HARDWARE:
self.microcontroller.send_hardware_trigger(
control_illumination=True, illumination_on_time_us=self.camera.get_exposure_time() * 1000
)

# read camera frame
self.camera.send_trigger(illumination_time=self.camera.get_exposure_time())
image = self.camera.read_frame()
if image is None:
print("self.camera.read_frame() returned None")
Expand Down Expand Up @@ -1870,15 +1861,15 @@ def acquire_spectrometer_data(self, config, file_ID, current_path):
)
np.savetxt(saving_path, data, delimiter=",")

def save_image(self, image, file_ID, config, current_path):
def save_image(self, image: np.ndarray, file_ID, config, current_path, is_color: bool):
if image.dtype == np.uint16:
saving_path = os.path.join(current_path, file_ID + "_" + str(config.name).replace(" ", "_") + ".tiff")
else:
saving_path = os.path.join(
current_path, file_ID + "_" + str(config.name).replace(" ", "_") + "." + Acquisition.IMAGE_FORMAT
)

if self.camera.is_color:
if is_color:
if "BF LED matrix" in config.name:
if MULTIPOINT_BF_SAVING_OPTION == "RGB2GRAY":
image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
Expand Down Expand Up @@ -2322,7 +2313,7 @@ def run_acquisition(self):
self.liveController_was_live_before_multipoint = False

# disable callback
if self.camera.callback_is_enabled:
if self.camera.get_callbacks_enabled():
self.camera_callback_was_enabled_before_multipoint = True
self.camera.enable_callbacks(False)
else:
Expand Down Expand Up @@ -2616,9 +2607,9 @@ def start_tracking(self):
self.was_live_before_tracking = False

# disable callback
if self.camera.callback_is_enabled:
if self.camera.get_callbacks_enabled():
self.camera_callback_was_enabled_before_tracking = True
self.camera.enable_callbacs(False)
self.camera.enable_callbacks(False)
else:
self.camera_callback_was_enabled_before_tracking = False

Expand Down Expand Up @@ -2878,9 +2869,10 @@ def run(self):
self.microcontroller.wait_till_operation_is_completed()
self.liveController.turn_on_illumination() # keep illumination on for single configuration acqusition
self.microcontroller.wait_till_operation_is_completed()
t = time.time()
self.camera.send_trigger()
image = self.camera.read_frame()
camera_frame = self.camera.read_camera_frame()
image = camera_frame.frame
t = camera_frame.timestamp
if self.number_of_selected_configurations > 1:
self.liveController.turn_off_illumination() # keep illumination on for single configuration acqusition
# image crop, rotation and flip
Expand Down Expand Up @@ -2913,7 +2905,7 @@ def run(self):
self.image_to_display_multi.emit(image_to_display_, config_.illumination_source)
# save image
if self.trackingController.flag_save_image:
if self.camera.is_color:
if camera_frame.is_color():
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
self.image_saver.enqueue(image_, tracking_frame_counter, str(config_.name))

Expand Down Expand Up @@ -4928,11 +4920,9 @@ def _verify_spot_alignment(self) -> bool:
self.microcontroller.turn_on_AF_laser()
self.microcontroller.wait_till_operation_is_completed()

# TODO: create a function to get the current image (taking care of trigger mode checking and laser on/off switching)
"""
self.camera.send_trigger()
current_image = self.camera.read_frame()
"""

self._get_laser_spot_centroid()
current_image = self.image

Expand Down Expand Up @@ -4986,11 +4976,7 @@ def _get_laser_spot_centroid(self) -> Optional[Tuple[float, float]]:
for i in range(self.laser_af_properties.laser_af_averaging_n):
try:
# send camera trigger
if self.liveController.trigger_mode == TriggerMode.SOFTWARE:
self.camera.send_trigger()
elif self.liveController.trigger_mode == TriggerMode.HARDWARE:
# self.microcontroller.send_hardware_trigger(control_illumination=True,illumination_on_time_us=self.camera.exposure_time*1000)
pass # to edit
self.camera.send_trigger(illumination_time=self.camera.get_exposure_time())

# read camera frame
image = self.camera.read_frame()
Expand Down
7 changes: 1 addition & 6 deletions software/control/gui_hcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,9 +475,6 @@ def setupHardware(self):
self.camera.add_frame_callback(self.streamHandler.on_new_frame)
self.camera.enable_callbacks(enabled=True)

if CAMERA_TYPE == "Toupcam":
self.camera.set_reset_strobe_delay_function(self.liveController.reset_strobe_arugment)

if SUPPORT_LASER_AUTOFOCUS:
self.camera_focus.set_acquisition_mode(
CameraAcquisitionMode.SOFTWARE_TRIGGER
Expand Down Expand Up @@ -998,7 +995,7 @@ def connect_objective_changed_laser_af():
self.piezoWidget.update_displacement_um_display
)

self.camera.set_callback(self.streamHandler.on_new_frame)
self.camera.add_frame_callback(self.streamHandler.on_new_frame)

def setup_movement_updater(self):
# We provide a few signals about the system's physical movement to other parts of the UI. Ideally, they other
Expand Down Expand Up @@ -1460,12 +1457,10 @@ def closeEvent(self, event):
self.stitcherWidget.closeEvent(event)
if SUPPORT_LASER_AUTOFOCUS:
self.liveController_focus_camera.stop_live()
self.camera_focus.close()
self.imageDisplayWindow_focus.close()

self.liveController.stop_live()
self.camera.stop_streaming()
self.camera.close()

if HOMING_ENABLED_X and HOMING_ENABLED_Y:
# TODO(imo): Why do we move forward 0.1, then move to 30? AKA why not just move to 30?
Expand Down
26 changes: 10 additions & 16 deletions software/control/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,7 @@ def __init__(
):

super().__init__(*args, **kwargs)
self._log = squid.logging.get_logger(self.__class__.__name__)
self.camera: AbstractCamera = camera
self.add_components(
include_gain_exposure_time, include_camera_temperature_setting, include_camera_auto_wb_setting
Expand Down Expand Up @@ -969,21 +970,14 @@ def add_components(

self.camera_layout.addLayout(blacklevel_line)

if include_camera_auto_wb_setting:
is_color = False
try:
is_color = CameraPixelFormat.is_color_format(self.camera.get_pixel_format())
except AttributeError:
pass

if is_color is True:
# auto white balance
self.btn_auto_wb = QPushButton("Auto White Balance")
self.btn_auto_wb.setCheckable(True)
self.btn_auto_wb.setChecked(False)
self.btn_auto_wb.clicked.connect(self.toggle_auto_wb)
if include_camera_auto_wb_setting and CameraPixelFormat.is_color_format(self.camera.get_pixel_format()):
# auto white balance
self.btn_auto_wb = QPushButton("Auto White Balance")
self.btn_auto_wb.setCheckable(True)
self.btn_auto_wb.setChecked(False)
self.btn_auto_wb.clicked.connect(self.toggle_auto_wb)

self.camera_layout.addLayout(self.btn_auto_wb)
self.camera_layout.addLayout(self.btn_auto_wb)

self.setLayout(self.camera_layout)

Expand Down Expand Up @@ -1046,7 +1040,7 @@ def set_temperature(self):
try:
self.camera.set_temperature(float(self.entry_temperature.value()))
except AttributeError:
pass
self._log.warning("Cannot set temperature - not supported.")

def update_measured_temperature(self, temperature):
self.label_temperature_measured.setNum(temperature)
Expand Down Expand Up @@ -1086,7 +1080,7 @@ def update_blacklevel(self, blacklevel):
try:
self.camera.set_black_level(blacklevel)
except AttributeError:
pass
self._log.warning("Cannot set black level - not supported.")


class ProfileWidget(QFrame):
Expand Down

0 comments on commit 6f8710d

Please sign in to comment.