Skip to content

Commit 3bb4763

Browse files
Merge pull request #976 from annie-xd-wang/973-expansion-microscope
973 expansion microscope
2 parents 4087237 + d1200f6 commit 3bb4763

26 files changed

+604
-253
lines changed

src/navigate/config/config.py

Lines changed: 66 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ def verify_experiment_config(manager, configuration):
360360
"is_centered": True,
361361
"center_x": 1024,
362362
"center_y": 1024,
363+
"readout_time": 0,
363364
}
364365
if (
365366
"CameraParameters" not in configuration["experiment"]
@@ -371,58 +372,73 @@ def verify_experiment_config(manager, configuration):
371372
"CameraParameters",
372373
camera_parameters_dict_sample,
373374
)
374-
camera_setting_dict = configuration["experiment"]["CameraParameters"]
375-
for k in camera_parameters_dict_sample:
376-
if k not in camera_setting_dict.keys():
377-
camera_setting_dict[k] = camera_parameters_dict_sample[k]
378-
# binning
379-
if camera_setting_dict["binning"] not in ["1x1", "2x2", "4x4"]:
380-
camera_setting_dict["binning"] = "1x1"
381-
# x_pixels and y_pixels
382-
try:
383-
camera_setting_dict["x_pixels"] = int(camera_setting_dict["x_pixels"])
384-
except ValueError:
385-
camera_setting_dict["x_pixels"] = camera_parameters_dict_sample["x_pixels"]
386-
387-
try:
388-
camera_setting_dict["y_pixels"] = int(camera_setting_dict["y_pixels"])
389-
except ValueError:
390-
camera_setting_dict["y_pixels"] = camera_parameters_dict_sample["y_pixels"]
391-
392-
# image width and height
393-
if camera_setting_dict["x_pixels"] <= 0:
394-
camera_setting_dict["x_pixels"] = camera_parameters_dict_sample["x_pixels"]
395-
if camera_setting_dict["y_pixels"] <= 0:
396-
camera_setting_dict["y_pixels"] = camera_parameters_dict_sample["y_pixels"]
397-
x_binning = int(camera_setting_dict["binning"][0])
398-
y_binning = int(camera_setting_dict["binning"][2])
399-
img_x_pixels = camera_setting_dict["x_pixels"] // x_binning
400-
img_y_pixels = camera_setting_dict["y_pixels"] // y_binning
401-
camera_setting_dict["img_x_pixels"] = img_x_pixels
402-
camera_setting_dict["img_y_pixels"] = img_y_pixels
403-
if camera_setting_dict["is_centered"]:
404-
camera_setting_dict["center_x"] = camera_setting_dict["x_pixels"] // 2
405-
camera_setting_dict["center_y"] = camera_setting_dict["y_pixels"] // 2
406-
407-
# sensor mode
408-
if camera_setting_dict["sensor_mode"] not in ["Normal", "Light-Sheet"]:
409-
camera_setting_dict["sensor_mode"] = "Normal"
410-
if camera_setting_dict["readout_direction"] not in [
411-
"Top-to-Bottom",
412-
"Bottom-to-Top",
413-
"Bidirectional",
414-
"Rev. Bidirectional",
415-
]:
416-
camera_setting_dict["readout_direction"] = "Top-to-Bottom"
417-
418-
# databuffer_size, number_of_pixels
419-
for k in ["databuffer_size", "number_of_pixels", "frames_to_average"]:
375+
microscope_names = [""] + list(configuration["configuration"]["microscopes"].keys())
376+
for microscope_name in microscope_names:
377+
camera_setting_dict = configuration["experiment"]["CameraParameters"]
378+
if microscope_name:
379+
if (
380+
microscope_name not in camera_setting_dict
381+
or type(camera_setting_dict[microscope_name]) is not DictProxy
382+
):
383+
update_config_dict(
384+
manager,
385+
camera_setting_dict,
386+
microscope_name,
387+
camera_parameters_dict_sample,
388+
)
389+
camera_setting_dict = camera_setting_dict[microscope_name]
390+
391+
for k in camera_parameters_dict_sample:
392+
if k not in camera_setting_dict.keys():
393+
camera_setting_dict[k] = camera_parameters_dict_sample[k]
394+
# binning
395+
if camera_setting_dict["binning"] not in ["1x1", "2x2", "4x4"]:
396+
camera_setting_dict["binning"] = "1x1"
397+
# x_pixels and y_pixels
420398
try:
421-
camera_setting_dict[k] = int(camera_setting_dict[k])
399+
camera_setting_dict["x_pixels"] = int(camera_setting_dict["x_pixels"])
422400
except ValueError:
423-
camera_setting_dict[k] = camera_parameters_dict_sample[k]
424-
if camera_setting_dict[k] < 1:
425-
camera_setting_dict[k] = camera_parameters_dict_sample[k]
401+
camera_setting_dict["x_pixels"] = camera_parameters_dict_sample["x_pixels"]
402+
403+
try:
404+
camera_setting_dict["y_pixels"] = int(camera_setting_dict["y_pixels"])
405+
except ValueError:
406+
camera_setting_dict["y_pixels"] = camera_parameters_dict_sample["y_pixels"]
407+
408+
# image width and height
409+
if camera_setting_dict["x_pixels"] <= 0:
410+
camera_setting_dict["x_pixels"] = camera_parameters_dict_sample["x_pixels"]
411+
if camera_setting_dict["y_pixels"] <= 0:
412+
camera_setting_dict["y_pixels"] = camera_parameters_dict_sample["y_pixels"]
413+
x_binning = int(camera_setting_dict["binning"][0])
414+
y_binning = int(camera_setting_dict["binning"][2])
415+
img_x_pixels = camera_setting_dict["x_pixels"] // x_binning
416+
img_y_pixels = camera_setting_dict["y_pixels"] // y_binning
417+
camera_setting_dict["img_x_pixels"] = img_x_pixels
418+
camera_setting_dict["img_y_pixels"] = img_y_pixels
419+
if camera_setting_dict["is_centered"]:
420+
camera_setting_dict["center_x"] = camera_setting_dict["x_pixels"] // 2
421+
camera_setting_dict["center_y"] = camera_setting_dict["y_pixels"] // 2
422+
423+
# sensor mode
424+
if camera_setting_dict["sensor_mode"] not in ["Normal", "Light-Sheet"]:
425+
camera_setting_dict["sensor_mode"] = "Normal"
426+
if camera_setting_dict["readout_direction"] not in [
427+
"Top-to-Bottom",
428+
"Bottom-to-Top",
429+
"Bidirectional",
430+
"Rev. Bidirectional",
431+
]:
432+
camera_setting_dict["readout_direction"] = "Top-to-Bottom"
433+
434+
# databuffer_size, number_of_pixels
435+
for k in ["databuffer_size", "number_of_pixels", "frames_to_average"]:
436+
try:
437+
camera_setting_dict[k] = int(camera_setting_dict[k])
438+
except ValueError:
439+
camera_setting_dict[k] = camera_parameters_dict_sample[k]
440+
if camera_setting_dict[k] < 1:
441+
camera_setting_dict[k] = camera_parameters_dict_sample[k]
426442

427443
# stage parameters
428444
stage_dict_sample = {}

src/navigate/controller/controller.py

Lines changed: 76 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -312,11 +312,18 @@ def update_buffer(self):
312312
Size dictated by x_pixels, y_pixels, an number_of_frames in
313313
configuration file.
314314
"""
315+
microscope_name = self.configuration["experiment"]["MicroscopeState"][
316+
"microscope_name"
317+
]
315318
img_width = int(
316-
self.configuration["experiment"]["CameraParameters"]["img_x_pixels"]
319+
self.configuration["experiment"]["CameraParameters"][microscope_name][
320+
"img_x_pixels"
321+
]
317322
)
318323
img_height = int(
319-
self.configuration["experiment"]["CameraParameters"]["img_y_pixels"]
324+
self.configuration["experiment"]["CameraParameters"][microscope_name][
325+
"img_y_pixels"
326+
]
320327
)
321328
if img_width == self.img_width and img_height == self.img_height:
322329
return
@@ -325,11 +332,6 @@ def update_buffer(self):
325332
self.img_width = img_width
326333
self.img_height = img_height
327334

328-
# virtual microscopes
329-
for microscope_name in list(self.additional_microscopes.keys()):
330-
self.destroy_virtual_microscope(microscope_name)
331-
self.additional_microscopes = {}
332-
333335
def update_acquire_control(self):
334336
"""Update the acquire control based on the current experiment parameters."""
335337
self.view.acqbar.stop_stage.config(
@@ -356,6 +358,7 @@ def change_microscope(self, microscope_name, zoom=None):
356358
self.stage_controller.initialize()
357359
self.channels_tab_controller.initialize()
358360
self.camera_setting_controller.update_camera_device_related_setting()
361+
self.camera_setting_controller.populate_experiment_values()
359362
self.camera_setting_controller.calculate_physical_dimensions()
360363
self.camera_view_controller.update_snr()
361364

@@ -451,10 +454,15 @@ def update_experiment_setting(self):
451454
452455
"""
453456
warning_message = self.camera_setting_controller.update_experiment_values()
457+
microscope_name = self.configuration["experiment"]["MicroscopeState"][
458+
"microscope_name"
459+
]
454460

455461
# set waveform template
456462
if self.acquire_bar_controller.mode in ["live", "single", "z-stack"]:
457-
camera_setting = self.configuration["experiment"]["CameraParameters"]
463+
camera_setting = self.configuration["experiment"]["CameraParameters"][
464+
microscope_name
465+
]
458466
if camera_setting["sensor_mode"] == "Light-Sheet" and camera_setting[
459467
"readout_direction"
460468
] in ["Bidirectional", "Rev. Bidirectional"]:
@@ -482,6 +490,13 @@ def update_experiment_setting(self):
482490
# TODO: validate experiment dict
483491

484492
warning_message += self.channels_tab_controller.verify_experiment_values()
493+
494+
# additional microscopes
495+
for microscope_name in self.additional_microscopes_configs:
496+
if hasattr(self, f"{microscope_name.lower()}_camera_setting_controller"):
497+
getattr(
498+
self, f"{microscope_name.lower()}_camera_setting_controller"
499+
).update_experiment_values()
485500
if warning_message:
486501
return warning_message
487502
return ""
@@ -557,6 +572,14 @@ def set_mode_of_sub(self, mode):
557572
self.camera_setting_controller.set_mode(mode)
558573
self.mip_setting_controller.set_mode(mode)
559574
self.waveform_tab_controller.set_mode(mode)
575+
576+
# additional microscopes
577+
for microscope_name in self.additional_microscopes_configs:
578+
if hasattr(self, f"{microscope_name.lower()}_camera_setting_controller"):
579+
getattr(
580+
self, f"{microscope_name.lower()}_camera_setting_controller"
581+
).set_mode(mode)
582+
560583
if mode == "stop":
561584
# GUI Failsafe
562585
self.acquire_bar_controller.stop_acquire()
@@ -987,15 +1010,18 @@ def capture_image(self, command, mode, *args):
9871010
return
9881011
self.acquire_bar_controller.view.acquire_btn.configure(text="Stop")
9891012
self.acquire_bar_controller.view.acquire_btn.configure(state="normal")
1013+
microscope_name = self.configuration["experiment"]["MicroscopeState"][
1014+
"microscope_name"
1015+
]
9901016

9911017
self.camera_view_controller.initialize_non_live_display(
9921018
self.configuration["experiment"]["MicroscopeState"],
993-
self.configuration["experiment"]["CameraParameters"],
1019+
self.configuration["experiment"]["CameraParameters"][microscope_name],
9941020
)
9951021

9961022
self.mip_setting_controller.initialize_non_live_display(
9971023
self.configuration["experiment"]["MicroscopeState"],
998-
self.configuration["experiment"]["CameraParameters"],
1024+
self.configuration["experiment"]["CameraParameters"][microscope_name],
9991025
)
10001026

10011027
self.stop_acquisition_flag = False
@@ -1076,11 +1102,15 @@ def capture_image(self, command, mode, *args):
10761102
def launch_additional_microscopes(self):
10771103
"""Launch additional microscopes."""
10781104

1079-
def display_images(camera_view_controller, show_img_pipe, data_buffer):
1105+
def display_images(
1106+
microscope_name, camera_view_controller, show_img_pipe, data_buffer
1107+
):
10801108
"""Display images from additional microscopes.
10811109
10821110
Parameters
10831111
----------
1112+
microscope_name : str
1113+
Microscope name
10841114
camera_view_controller : CameraViewController
10851115
Camera View Controller object.
10861116
show_img_pipe : multiprocessing.Pipe
@@ -1091,9 +1121,8 @@ def display_images(camera_view_controller, show_img_pipe, data_buffer):
10911121
configuration file.
10921122
"""
10931123
camera_view_controller.initialize_non_live_display(
1094-
data_buffer,
10951124
self.configuration["experiment"]["MicroscopeState"],
1096-
self.configuration["experiment"]["CameraParameters"],
1125+
self.configuration["experiment"]["CameraParameters"][microscope_name],
10971126
)
10981127
images_received = 0
10991128
while True:
@@ -1122,72 +1151,51 @@ def display_images(camera_view_controller, show_img_pipe, data_buffer):
11221151
break
11231152
images_received += 1
11241153

1125-
# destroy unnecessary additional microscopes
1126-
temp = []
1127-
for microscope_name in self.additional_microscopes:
1128-
if microscope_name not in self.additional_microscopes_configs:
1129-
temp.append(microscope_name)
1130-
for microscope_name in temp:
1154+
# destroy all additional microscopes
1155+
for microscope_name in list(self.additional_microscopes.keys()):
11311156
self.destroy_virtual_microscope(microscope_name)
1157+
self.additional_microscopes = {}
11321158

11331159
# show additional camera view popup
11341160
for microscope_name in self.additional_microscopes_configs:
1135-
if microscope_name not in self.additional_microscopes:
1136-
show_img_pipe = self.model.create_pipe(
1137-
f"{microscope_name}_show_img_pipe"
1138-
)
1139-
data_buffer = self.model.launch_virtual_microscope(
1140-
microscope_name,
1141-
self.additional_microscopes_configs[microscope_name],
1142-
)
1161+
show_img_pipe = self.model.create_pipe(f"{microscope_name}_show_img_pipe")
1162+
data_buffer = self.model.launch_virtual_microscope(
1163+
microscope_name,
1164+
self.additional_microscopes_configs[microscope_name],
1165+
)
11431166

1144-
self.additional_microscopes[microscope_name] = {
1145-
"show_img_pipe": show_img_pipe,
1146-
"data_buffer": data_buffer,
1147-
}
1148-
if (
1149-
self.additional_microscopes[microscope_name].get(
1150-
"camera_view_controller", None
1151-
)
1152-
is None
1153-
):
1154-
popup_window = CameraViewPopupWindow(self.view, microscope_name)
1155-
camera_view_controller = CameraViewController(
1156-
popup_window.camera_view, self
1157-
)
1158-
camera_view_controller.data_buffer = self.additional_microscopes[
1159-
microscope_name
1160-
]["data_buffer"]
1161-
popup_window.popup.bind("<Configure>", camera_view_controller.resize)
1162-
self.additional_microscopes[microscope_name][
1163-
"popup_window"
1164-
] = popup_window
1165-
self.additional_microscopes[microscope_name][
1166-
"camera_view_controller"
1167-
] = camera_view_controller
1168-
popup_window.popup.protocol(
1169-
"WM_DELETE_WINDOW",
1170-
combine_funcs(
1171-
popup_window.popup.dismiss,
1172-
lambda: self.additional_microscopes[microscope_name].pop(
1173-
"camera_view_controller"
1174-
),
1167+
self.additional_microscopes[microscope_name] = {
1168+
"show_img_pipe": show_img_pipe,
1169+
"data_buffer": data_buffer,
1170+
}
1171+
popup_window = CameraViewPopupWindow(self.view, microscope_name)
1172+
camera_view_controller = CameraViewController(
1173+
popup_window.camera_view, self
1174+
)
1175+
camera_view_controller.data_buffer = self.additional_microscopes[
1176+
microscope_name
1177+
]["data_buffer"]
1178+
camera_view_controller.microscope_name = microscope_name
1179+
popup_window.popup.bind("<Configure>", camera_view_controller.resize)
1180+
self.additional_microscopes[microscope_name]["popup_window"] = popup_window
1181+
self.additional_microscopes[microscope_name][
1182+
"camera_view_controller"
1183+
] = camera_view_controller
1184+
popup_window.popup.protocol(
1185+
"WM_DELETE_WINDOW",
1186+
combine_funcs(
1187+
popup_window.popup.dismiss,
1188+
lambda: self.additional_microscopes[microscope_name].pop(
1189+
"camera_view_controller"
11751190
),
1176-
)
1177-
1178-
# clear show_img_pipe
1179-
show_img_pipe = self.additional_microscopes[microscope_name][
1180-
"show_img_pipe"
1181-
]
1182-
while show_img_pipe.poll():
1183-
image_id = show_img_pipe.recv()
1184-
if image_id == "stop":
1185-
break
1191+
),
1192+
)
11861193

11871194
# start thread
11881195
capture_img_thread = threading.Thread(
11891196
target=display_images,
11901197
args=(
1198+
microscope_name,
11911199
self.additional_microscopes[microscope_name][
11921200
"camera_view_controller"
11931201
],

0 commit comments

Comments
 (0)