Coverage for src\pytribeam\image.py: 85%
277 statements
« prev ^ index » next coverage.py v7.5.1, created at 2025-03-04 17:41 -0800
« prev ^ index » next coverage.py v7.5.1, created at 2025-03-04 17:41 -0800
1"""
2Microscope Imaging Module
3=========================
5This module provides a set of functions for configuring and operating the microscope for imaging purposes.
6It includes functions for setting beam parameters, detector settings, and capturing images with custom
7or preset resolutions.
9Functions
10---------
11beam_angular_correction(microscope, dynamic_focus, tilt_correction, delay_s=0.5)
12 Uses auto mode to set tilt correction and dynamic focus.
14beam_current(beam, microscope, current_na, current_tol_na, delay_s=5.0)
15 Sets the current for the selected beam type, with inputs in units of nanoamps.
17beam_dwell_time(beam, microscope, dwell_us, delay_s=0.1)
18 Sets the dwell time for the selected beam, with inputs in units of microseconds.
20beam_hfw(beam, microscope, hfw_mm, delay_s=0.1)
21 Sets the horizontal field width for the selected beam, with inputs in units of millimeters.
23beam_ready(beam, microscope, delay_s=5.0, attempts=2)
24 Checks if the beam is on or blanked, and tries to turn it on and unblank it if possible.
26beam_scan_full_frame(beam, microscope)
27 Sets the beam scan mode to full frame.
29beam_scan_resolution(beam, microscope, resolution, delay_s=0.1)
30 Sets the scan resolution for the selected beam, with inputs in units of preset resolutions.
32beam_scan_rotation(beam, microscope, rotation_deg, delay_s=0.1)
33 Sets the scan rotation for the selected beam, with inputs in units of degrees.
35beam_voltage(beam, microscope, voltage_kv, voltage_tol_kv, delay_s=5.0)
36 Sets the voltage for a given beam type, with inputs in units of kilovolts.
38beam_working_dist(beam, microscope, wd_mm, delay_s=0.1)
39 Sets the working distance for the selected beam, with inputs in units of millimeters.
41collect_multiple_images(multiple_img_settings, num_frames)
42 Sets up scanning for multiple frames.
44collect_single_image(save_path, img_settings)
45 Collects a single frame image with defined image settings.
47detector_auto_cb(microscope, beam, settings, delay_s=0.1)
48 Runs the detector auto contrast-brightness function.
50detector_brightness(microscope, brightness, delay_s=0.1)
51 Sets the detector brightness with input from 0 to 1.
53detector_cb(microscope, detector_settings, beam)
54 Sets detector contrast and brightness.
56detector_contrast(microscope, contrast, delay_s=0.1)
57 Sets the detector contrast with input from 0 to 1.
59detector_mode(microscope, detector_mode, delay_s=0.1)
60 Sets the detector mode.
62detector_type(microscope, detector, delay_s=0.1)
63 Sets the detector type.
65grab_custom_resolution_frame(img_settings, save_path)
66 Captures a single frame image using custom resolutions and saves it to the specified path.
68grab_preset_resolution_frame(img_settings)
69 Captures a single frame image using preset resolutions.
71image_operation(step, image_settings, general_settings, slice_number)
72 Performs an image operation based on the specified settings.
74imaging_detector(img_settings)
75 Prepares the detector and inserts it if applicable.
77imaging_device(microscope, beam)
78 Prepares the imaging beam, viewing quad, and the beam voltage and current.
80imaging_scan(img_settings)
81 Sets all scan settings except for the resolution.
83prepare_imaging(img_settings)
84 Prepares various imaging settings.
86set_beam_device(microscope, device, delay_s=0.1)
87 Sets the active imaging device.
89set_view(microscope, quad)
90 Sets the active view to the specified quad.
92"""
94# Default python modules
95# from functools import singledispatch
96from pathlib import Path
97import time
98import warnings
99from typing import List
100import math
102# Local scripts
103import pytribeam.constants as cs
104import pytribeam.insertable_devices as devices
105import pytribeam.types as tbt
106import pytribeam.utilities as ut
109def beam_angular_correction(
110 microscope: tbt.Microscope,
111 dynamic_focus: bool,
112 tilt_correction: bool,
113 # correction_angle_deg: float = None,
114 delay_s: float = 0.5,
115) -> bool:
116 """
117 Uses auto mode to set tilt correction and dynamic focus.
119 This function configures the electron beam's angular correction mode to automatic,
120 sets the scan rotation to zero, and enables or disables dynamic focus and tilt correction
121 based on the provided parameters.
123 Parameters
124 ----------
125 microscope : tbt.Microscope
126 The microscope object to configure.
127 dynamic_focus : bool
128 If True, dynamic focus will be turned on. If False, dynamic focus will be turned off.
129 tilt_correction : bool
130 If True, tilt correction will be turned on. If False, tilt correction will be turned off.
131 delay_s : float, optional
132 The delay in seconds to wait after turning dynamic focus or tilt correction on or off (default is 0.5).
134 Returns
135 -------
136 bool
137 True if the configuration is successful, False otherwise.
139 Raises
140 ------
141 SystemError
142 If unable to turn dynamic focus or tilt correction on or off.
144 Examples
145 --------
146 >>> import pytribeam.types as tbt
147 >>> microscope = tbt.Microscope()
148 >>> microscope.connect("localhost")
149 Client connecting to [localhost:7520]...
150 Client connected to [localhost:7520]
151 >>> success = beam_angular_correction(microscope, dynamic_focus=True, tilt_correction=False)
152 >>> print(success)
153 True
154 """
155 angular_correction = microscope.beams.electron_beam.angular_correction
156 angular_correction.mode = tbt.AngularCorrectionMode.AUTOMATIC
157 # scan rotation must be zero for auto mode
158 microscope.beams.electron_beam.scanning.rotation.value = 0.0
160 # manual adjustment not implemented yet, only works at zero scan rotation
161 # if correction_angle_deg is not None:
162 # angular_correction.mode = tbt.AngularCorrectionMode.MANUAL
163 if dynamic_focus:
164 angular_correction.dynamic_focus.turn_on()
165 time.sleep(delay_s)
166 if not angular_correction.dynamic_focus.is_on:
167 raise SystemError("Unable to turn dynamic focus on.")
168 if (not dynamic_focus) or (dynamic_focus is None):
169 angular_correction.dynamic_focus.turn_off()
170 time.sleep(delay_s)
171 if angular_correction.dynamic_focus.is_on:
172 raise SystemError("Unable to turn dynamic focus off.")
174 if tilt_correction:
175 angular_correction.tilt_correction.turn_on()
176 time.sleep(delay_s)
177 if not angular_correction.tilt_correction.is_on:
178 raise SystemError("Unable to turn tilt correction on.")
179 if (not tilt_correction) or (tilt_correction is None):
180 angular_correction.tilt_correction.turn_off()
181 time.sleep(delay_s)
182 if angular_correction.tilt_correction.is_on:
183 raise SystemError("Unable to turn tilt correction off.")
186def beam_current(
187 beam: tbt.Beam,
188 microscope: tbt.Microscope,
189 current_na: float,
190 current_tol_na: float,
191 delay_s: float = 5.0,
192) -> bool:
193 """
194 Sets the current for the selected beam type, with inputs in units of nanoamps.
196 This function sets the beam current for the specified beam type on the microscope.
197 If the current difference exceeds the tolerance, it adjusts the beam current and
198 waits for the specified delay.
200 Parameters
201 ----------
202 beam : tbt.Beam
203 The beam type to configure.
204 microscope : tbt.Microscope
205 The microscope object to configure.
206 current_na : float
207 The desired beam current in nanoamps.
208 current_tol_na : float
209 The tolerance for the beam current in nanoamps.
210 delay_s : float, optional
211 The delay in seconds to wait after adjusting the beam current (default is 5.0).
213 Returns
214 -------
215 bool
216 True if the beam current is set successfully, False otherwise.
218 Raises
219 ------
220 ValueError
221 If the beam current cannot be adjusted within the specified tolerance.
223 Examples
224 --------
225 >>> import pytribeam.types as tbt
226 >>> microscope = tbt.Microscope()
227 >>> microscope.connect("localhost")
228 Client connecting to [localhost:7520]...
229 Client connected to [localhost:7520]
230 >>> beam = tbt.ElectronBeam(settings=None)
231 >>> success = beam_current(beam, microscope, current_na=1.0, current_tol_na=0.1)
232 >>> print(success)
233 True
234 """
235 selected_beam = ut.beam_type(beam, microscope)
237 exisiting_current_a = selected_beam.beam_current.value # amps
238 delta_current_na = abs(
239 exisiting_current_a * cs.Conversions.A_TO_NA - current_na
240 ) # nanoamps
241 if delta_current_na > current_tol_na:
242 warnings.warn(
243 "Requested beam current is not the current setting, imaging conditions may be non-ideal."
244 )
245 print("Adjusting beam current...")
246 selected_beam.beam_current.value = current_na * cs.Conversions.NA_TO_A
247 time.sleep(delay_s)
249 new_current_na = selected_beam.beam_current.value * cs.Conversions.A_TO_NA
250 current_diff_na = abs(new_current_na - current_na)
251 if current_diff_na > current_tol_na:
252 raise ValueError(
253 f"""Could not correctly adjust beam voltage,
254 requested {current_na} nA, current beam current is
255 {new_current_na} nA"""
256 )
258 return True
261def beam_dwell_time(
262 beam: tbt.Beam,
263 microscope: tbt.Microscope,
264 dwell_us: float,
265 delay_s: float = 0.1,
266) -> bool:
267 """
268 Sets the dwell time for the selected beam, with inputs in units of microseconds.
270 This function sets the dwell time for the specified beam type on the microscope.
271 It converts the dwell time from microseconds to seconds, sets the dwell time, and
272 waits for the specified delay.
274 Parameters
275 ----------
276 beam : tbt.Beam
277 The beam type to configure.
278 microscope : tbt.Microscope
279 The microscope object to configure.
280 dwell_us : float
281 The desired dwell time in microseconds.
282 delay_s : float, optional
283 The delay in seconds to wait after adjusting the dwell time (default is 0.1).
285 Returns
286 -------
287 bool
288 True if the dwell time is set successfully, False otherwise.
290 Raises
291 ------
292 ValueError
293 If the dwell time cannot be adjusted correctly.
295 Examples
296 --------
297 >>> import pytribeam.types as tbt
298 >>> microscope = tbt.Microscope()
299 >>> microscope.connect("localhost")
300 Client connecting to [localhost:7520]...
301 Client connected to [localhost:7520]
302 >>> beam = tbt.ElectronBeam(settings=None)
303 >>> success = beam_dwell_time(beam, microscope, dwell_us=10.0)
304 >>> print(success)
305 True
306 """
307 selected_beam = ut.beam_type(beam, microscope)
308 dwell_s = dwell_us * cs.Conversions.US_TO_S
309 selected_beam.scanning.dwell_time.value = dwell_s
310 time.sleep(delay_s)
311 if not math.isclose(
312 selected_beam.scanning.dwell_time.value,
313 dwell_s,
314 rel_tol=cs.Constants.beam_dwell_tol_ratio,
315 ):
316 raise ValueError(
317 f"""Could not correctly adjust dwell time,
318 requested {dwell_s} seconds, current dwell time is
319 {selected_beam.scanning.dwell_time.value} seconds"""
320 )
322 return True
325def beam_hfw(
326 beam: tbt.Beam,
327 microscope: tbt.Microscope,
328 hfw_mm: float,
329 delay_s: float = 0.1,
330 hfw_tol_mm: float = 1e-6, # 1 nm of tolerance
331) -> bool:
332 """
333 Sets the horizontal field width for the selected beam, with inputs in units of millimeters.
335 This function sets the horizontal field width (HFW) for the specified beam type on the microscope.
336 It converts the HFW from millimeters to meters, sets the HFW, and waits for the specified delay.
337 This should be done after adjusting the working distance.
339 Parameters
340 ----------
341 beam : tbt.Beam
342 The beam type to configure.
343 microscope : tbt.Microscope
344 The microscope object to configure.
345 hfw_mm : float
346 The desired horizontal field width in millimeters.
347 delay_s : float, optional
348 The delay in seconds to wait after adjusting the HFW (default is 0.1).
350 Returns
351 -------
352 bool
353 True if the HFW is set successfully, False otherwise.
355 Raises
356 ------
357 ValueError
358 If the HFW cannot be adjusted correctly.
360 Examples
361 --------
362 >>> import pytribeam.types as tbt
363 >>> microscope = tbt.Microscope()
364 >>> microscope.connect("localhost")
365 Client connecting to [localhost:7520]...
366 Client connected to [localhost:7520]
367 >>> beam = tbt.ElectronBeam(settings=None)
368 >>> success = beam_hfw(beam, microscope, hfw_mm=1.0)
369 >>> print(success)
370 True
371 """
372 selected_beam = ut.beam_type(beam, microscope)
373 hfw_m = hfw_mm * cs.Conversions.MM_TO_M
374 selected_beam.horizontal_field_width.value = hfw_m
375 time.sleep(delay_s)
376 if not math.isclose(
377 selected_beam.horizontal_field_width.value,
378 hfw_m,
379 abs_tol=hfw_tol_mm
380 * cs.Conversions.MM_TO_M, # convert to meters for autoscript calls
381 ):
382 raise ValueError(
383 f"""Could not correctly adjust horizontal field width,
384 requested {hfw_mm} millimeters, current field with is
385 {selected_beam.horizontal_field_width.value*cs.Conversions.M_TO_MM} millimeters"""
386 )
388 return True
391def beam_ready(
392 beam: tbt.Beam,
393 microscope: tbt.Microscope,
394 delay_s: float = 5.0,
395 attempts: int = 2,
396) -> bool:
397 """
398 Checks if the beam is on or blanked, and tries to turn it on and unblank it if possible.
400 This function checks the vacuum state, ensures the beam is on, and unblanks the beam if it is blanked.
401 It makes multiple attempts to turn on and unblank the beam, waiting for the specified delay between attempts.
403 Parameters
404 ----------
405 beam : tbt.Beam
406 The beam type to check.
407 microscope : tbt.Microscope
408 The microscope object to check.
409 delay_s : float, optional
410 The delay in seconds to wait between attempts (default is 5.0).
411 attempts : int, optional
412 The number of attempts to turn on and unblank the beam (default is 2).
414 Returns
415 -------
416 bool
417 True if the beam is ready (on and unblanked), False otherwise.
419 Raises
420 ------
421 ValueError
422 If the vacuum is not pumped.
423 If the beam cannot be turned on after the specified number of attempts.
424 If the beam cannot be unblanked after the specified number of attempts.
426 Examples
427 --------
428 >>> import pytribeam.types as tbt
429 >>> microscope = tbt.Microscope()
430 >>> microscope.connect("localhost")
431 Client connecting to [localhost:7520]...
432 Client connected to [localhost:7520]
433 >>> beam = tbt.ElectronBeam(settings=None)
434 >>> success = beam_ready(beam, microscope)
435 >>> print(success)
436 True
437 """
438 selected_beam = ut.beam_type(beam, microscope)
440 # check vaccum
441 vacuum = microscope.vacuum.chamber_state
442 if vacuum != tbt.VacuumState.PUMPED.value:
443 raise ValueError(f'Vacuum is not pumped, current state is "{vacuum}"')
445 # check beam on
446 count: int = 0
447 while count < attempts:
448 beam_on = selected_beam.is_on
449 if not beam_on:
450 selected_beam.turn_on()
451 time.sleep(delay_s)
452 count += 1
453 if not beam_on:
454 raise ValueError(
455 f"Unable to turn on {beam.type} beam after {attempts} attempts."
456 )
458 # check beam blank
459 count: int = 0
460 while count < attempts:
461 beam_blank = selected_beam.is_blanked
462 if beam_blank:
463 selected_beam.unblank()
464 time.sleep(delay_s)
465 count += 1
466 if beam_blank:
467 raise ValueError(
468 f"Unable to unblank {beam.type} beam after {attempts} attempts."
469 )
471 return True
474def beam_scan_full_frame(
475 beam: tbt.Beam,
476 microscope: tbt.Microscope,
477) -> bool:
478 """
479 Set beam scan mode to full frame.
481 This function sets the scanning mode of the specified beam to full frame on the microscope.
483 Parameters
484 ----------
485 beam : tbt.Beam
486 The beam type to configure.
487 microscope : tbt.Microscope
488 The microscope object to configure.
490 Returns
491 -------
492 bool
493 True if the scan mode is set to full frame successfully, False otherwise.
495 Raises
496 ------
497 SystemError
498 If unable to set the scan mode to full frame.
500 Examples
501 --------
502 >>> import pytribeam.types as tbt
503 >>> microscope = tbt.Microscope()
504 >>> microscope.connect("localhost")
505 Client connecting to [localhost:7520]...
506 Client connected to [localhost:7520]
507 >>> beam = tbt.ElectronBeam(settings=None)
508 >>> success = beam_scan_full_frame(beam, microscope)
509 >>> print(success)
510 True
511 """
512 selected_beam = ut.beam_type(beam, microscope)
513 selected_beam.scanning.mode.set_full_frame()
514 scan_mode = selected_beam.scanning.mode.value
515 if not scan_mode == tbt.ScanMode.FULL_FRAME.value:
516 raise SystemError(
517 f"Unable to set imaging to full frame. Current scan mode is {scan_mode}."
518 )
519 return True
522def beam_scan_resolution(
523 beam: tbt.Beam,
524 microscope: tbt.Microscope,
525 resolution: tbt.Resolution,
526 delay_s: float = 0.1,
527) -> bool:
528 """
529 Sets the scan resolution for the selected beam, with inputs in units of preset resolutions.
531 This function sets the scan resolution for the specified beam type on the microscope.
532 It only works for preset resolutions and waits for the specified delay after setting the resolution.
534 Parameters
535 ----------
536 beam : tbt.Beam
537 The beam type to configure.
538 microscope : tbt.Microscope
539 The microscope object to configure.
540 resolution : tbt.Resolution
541 The desired scan resolution (must be a preset resolution).
542 delay_s : float, optional
543 The delay in seconds to wait after adjusting the resolution (default is 0.1).
545 Returns
546 -------
547 bool
548 True if the scan resolution is set successfully, False otherwise.
550 Raises
551 ------
552 ValueError
553 If a custom resolution is requested or if the resolution cannot be adjusted correctly.
555 Examples
556 --------
557 >>> import pytribeam.types as tbt
558 >>> import pytribeam.utility as ut
559 >>> microscope = tbt.Microscope()
560 >>> microscope.connect("localhost")
561 Client connecting to [localhost:7520]...
562 Client connected to [localhost:7520]
563 >>> beam = tbt.ElectronBeam(settings=None)
564 >>> resolution = tbt.PresetResolution.HIGH
565 >>> success = beam_scan_resolution(beam, microscope, resolution)
566 >>> print(success)
567 True
568 """
569 if not isinstance(resolution, tbt.PresetResolution):
570 raise ValueError(
571 f"Requested a custom resolution of {resolution.value}. Only preset resolutions allowed."
572 )
574 selected_beam = ut.beam_type(beam, microscope)
575 selected_beam.scanning.resolution.value = resolution.value
576 time.sleep(delay_s)
577 if selected_beam.scanning.resolution.value != resolution.value:
578 raise ValueError(
579 f"""Could not correctly adjust scan resolution,
580 requested {resolution}, current resolution is
581 {selected_beam.scanning.resolution.value}"""
582 )
584 return True
587def beam_scan_rotation(
588 beam: tbt.Beam,
589 microscope: tbt.Microscope,
590 rotation_deg: float,
591 delay_s: float = 0.1,
592) -> bool:
593 """
594 Sets the scan rotation for the selected beam, with inputs in units of degrees.
596 This function sets the scan rotation for the specified beam type on the microscope.
597 It converts the rotation from degrees to radians, sets the scan rotation, and waits for the specified delay.
599 Parameters
600 ----------
601 beam : tbt.Beam
602 The beam type to configure.
603 microscope : tbt.Microscope
604 The microscope object to configure.
605 rotation_deg : float
606 The desired scan rotation in degrees.
607 delay_s : float, optional
608 The delay in seconds to wait after adjusting the scan rotation (default is 0.1).
610 Returns
611 -------
612 bool
613 True if the scan rotation is set successfully, False otherwise.
615 Raises
616 ------
617 ValueError
618 If the scan rotation cannot be adjusted correctly.
620 Examples
621 --------
622 >>> import pytribeam.types as tbt
623 >>> microscope = tbt.Microscope()
624 >>> microscope.connect("localhost")
625 Client connecting to [localhost:7520]...
626 Client connected to [localhost:7520]
627 >>> beam = tbt.ElectronBeam(settings=None)
628 >>> success = beam_scan_rotation(beam, microscope, rotation_deg=45.0)
629 >>> print(success)
630 True
631 """
632 selected_beam = ut.beam_type(beam, microscope)
633 rotation_rad = rotation_deg * cs.Conversions.DEG_TO_RAD
634 selected_beam.scanning.rotation.value = rotation_rad
635 time.sleep(delay_s)
636 if selected_beam.scanning.rotation.value != rotation_rad:
637 raise ValueError(
638 f"""Could not correctly adjust scan rotation,
639 requested {rotation_rad} radians, current scan rotation is
640 {selected_beam.scanning.rotation.value} radians"""
641 )
643 return True
646def beam_voltage(
647 beam: tbt.Beam,
648 microscope: tbt.Microscope,
649 voltage_kv: float,
650 voltage_tol_kv: float,
651 delay_s: float = 5.0,
652) -> bool:
653 """
654 Sets the voltage for a given beam type, with inputs in units of kilovolts.
656 This function sets the beam voltage for the specified beam type on the microscope.
657 If the voltage difference exceeds the tolerance, it adjusts the beam voltage and waits for the specified delay.
659 Parameters
660 ----------
661 beam : tbt.Beam
662 The beam type to configure.
663 microscope : tbt.Microscope
664 The microscope object to configure.
665 voltage_kv : float
666 The desired beam voltage in kilovolts.
667 voltage_tol_kv : float
668 The tolerance for the beam voltage in kilovolts.
669 delay_s : float, optional
670 The delay in seconds to wait after adjusting the beam voltage (default is 5.0).
672 Returns
673 -------
674 bool
675 True if the beam voltage is set successfully, False otherwise.
677 Raises
678 ------
679 ValueError
680 If the beam voltage cannot be adjusted within the specified tolerance.
681 If the beam is not controllable.
683 Examples
684 --------
685 >>> import pytribeam.types as tbt
686 >>> microscope = tbt.Microscope()
687 >>> microscope.connect("localhost")
688 Client connecting to [localhost:7520]...
689 Client connected to [localhost:7520]
690 >>> beam = tbt.ElectronBeam(settings=None)
691 >>> success = beam_voltage(beam, microscope, voltage_kv=15.0, voltage_tol_kv=0.5)
692 >>> print(success)
693 True
694 """
695 selected_beam = ut.beam_type(beam, microscope)
697 exisiting_voltage_v = selected_beam.high_voltage.value # volts
698 delta_voltage_kv = abs(
699 exisiting_voltage_v * cs.Conversions.V_TO_KV - voltage_kv
700 ) # kilovolts
701 if delta_voltage_kv > voltage_tol_kv:
702 warnings.warn(
703 "Requested beam current is not the current setting, imaging conditions may be non-ideal."
704 )
705 beam_controllable = selected_beam.high_voltage.is_controllable
707 if not beam_controllable:
708 raise ValueError(
709 f"Unable to modify beam voltage, beam is not currently controllable."
710 )
711 print("Adjusting beam voltage...")
712 selected_beam.high_voltage.value = voltage_kv * cs.Conversions.KV_TO_V
713 time.sleep(delay_s)
714 new_voltage_kv = selected_beam.high_voltage.value * cs.Conversions.V_TO_KV
715 voltage_diff_kv = abs(new_voltage_kv - voltage_kv)
716 if voltage_diff_kv > voltage_tol_kv:
717 raise ValueError(
718 f"""Could not correctly adjust beam voltage,
719 requested {voltage_kv} kV, current beam voltage is
720 {new_voltage_kv} kV"""
721 )
723 return True
726def beam_working_distance(
727 beam: tbt.Beam,
728 microscope: tbt.Microscope,
729 wd_mm: float,
730 delay_s: float = 0.1,
731) -> bool:
732 """
733 Sets the working distance for the selected beam, with inputs in units of millimeters.
735 This function sets the working distance (WD) for the specified beam type on the microscope.
736 It converts the WD from millimeters to meters, sets the WD, and waits for the specified delay.
737 This should be done before adjusting the horizontal field width.
739 Parameters
740 ----------
741 beam : tbt.Beam
742 The beam type to configure.
743 microscope : tbt.Microscope
744 The microscope object to configure.
745 wd_mm : float
746 The desired working distance in millimeters.
747 delay_s : float, optional
748 The delay in seconds to wait after adjusting the working distance (default is 0.1).
750 Returns
751 -------
752 bool
753 True if the working distance is set successfully, False otherwise.
755 Raises
756 ------
757 ValueError
758 If the working distance cannot be adjusted correctly.
760 Examples
761 --------
762 >>> import pytribeam.types as tbt
763 >>> microscope = tbt.Microscope()
764 >>> microscope.connect("localhost")
765 Client connecting to [localhost:7520]...
766 Client connected to [localhost:7520]
767 >>> beam = tbt.ElectronBeam(settings=None)
768 >>> success = beam_working_dist(beam, microscope, wd_mm=5.0)
769 >>> print(success)
770 True
771 """
772 selected_beam = ut.beam_type(beam, microscope)
773 wd_m = wd_mm * cs.Conversions.MM_TO_M
774 selected_beam.working_distance.value = wd_m
775 time.sleep(delay_s)
776 if selected_beam.working_distance.value != wd_m:
777 raise ValueError(
778 f"""Could not correctly adjust working distance,
779 requested {wd_m} meters, current working distance is
780 {selected_beam.working_distance.value} meters"""
781 )
783 return True
786def detector_auto_cb(
787 microscope: tbt.Microscope,
788 beam: tbt.Beam,
789 settings: tbt.ScanArea,
790 delay_s: float = 0.1,
791) -> bool:
792 """
793 Detector auto contrast brightness. Currently only reduced scan area option is supported.
795 This function sets the scanning mode to reduced area, runs the auto contrast-brightness function,
796 and then sets the scanning mode back to full frame.
798 Parameters
799 ----------
800 microscope : tbt.Microscope
801 The microscope object to configure.
802 beam : tbt.Beam
803 The beam type to configure.
804 settings : tbt.ScanArea
805 The scan area settings for the reduced area.
806 delay_s : float, optional
807 The delay in seconds to wait after each operation (default is 0.1).
809 Returns
810 -------
811 bool
812 True if the auto contrast-brightness is completed successfully, False otherwise.
814 Raises
815 ------
816 SystemError
817 If unable to set the scan mode to reduced area or full frame.
819 Examples
820 --------
821 >>> import pytribeam.types as tbt
822 >>> microscope = tbt.Microscope()
823 >>> microscope.connect("localhost")
824 Client connecting to [localhost:7520]...
825 Client connected to [localhost:7520]
826 >>> beam = tbt.ElectronBeam(settings=None)
827 >>> auto_cb_settings = tbt.ScanArea(left=0.1, top=0.1, width=0.8, height=0.8)
828 >>> success = detector_auto_cb(microscope, beam, auto_cb_settings)
829 >>> print(success)
830 True
831 """
832 selected_beam = ut.beam_type(beam, microscope)
833 selected_beam.scanning.mode.set_reduced_area(
834 left=settings.left,
835 top=settings.top,
836 width=settings.width,
837 height=settings.height,
838 )
839 scan_mode = selected_beam.scanning.mode.value
840 if not scan_mode == tbt.ScanMode.REDUCED_AREA.value:
841 raise SystemError(
842 f"Unable to set imaging to reduced area before auto contrast-brightness. Current scan mode is {scan_mode}."
843 )
844 microscope.auto_functions.run_auto_cb()
845 time.sleep(delay_s)
846 selected_beam.scanning.mode.set_full_frame()
847 time.sleep(delay_s)
849 new_scan_mode = selected_beam.scanning.mode.value
850 if new_scan_mode != tbt.ScanMode.FULL_FRAME.value:
851 raise SystemError(
852 f"Unable to set imaging back to full frame after auto contrast-brightness. Current scan mode is {new_scan_mode}."
853 )
854 return True
857def detector_brightness(
858 microscope: tbt.Microscope,
859 brightness: float,
860 delay_s: float = 0.1,
861) -> bool:
862 """
863 Sets the detector brightness with input from 0 to 1.
865 This function sets the brightness for the detector on the microscope and waits for the specified delay.
867 Parameters
868 ----------
869 microscope : tbt.Microscope
870 The microscope object to configure.
871 brightness : float
872 The desired brightness value (from 0 to 1).
873 delay_s : float, optional
874 The delay in seconds to wait after adjusting the brightness (default is 0.1).
876 Returns
877 -------
878 bool
879 True if the brightness is set successfully, False otherwise.
881 Raises
882 ------
883 ValueError
884 If the brightness cannot be adjusted correctly.
886 Examples
887 --------
888 >>> import pytribeam.types as tbt
889 >>> microscope = tbt.Microscope()
890 >>> microscope.connect("localhost")
891 Client connecting to [localhost:7520]...
892 Client connected to [localhost:7520]
893 >>> success = detector_brightness(microscope, brightness=0.5)
894 >>> print(success)
895 True
896 """
897 microscope.detector.brightness.value = brightness
898 current_detector = microscope.detector.type.value
899 time.sleep(delay_s)
900 if not math.isclose(
901 microscope.detector.brightness.value,
902 brightness,
903 abs_tol=cs.Constants.contrast_brightness_tolerance,
904 ):
905 raise ValueError(
906 f"""Could not correctly adjust detector brightness,
907 requested {brightness} on {current_detector} detector,
908 current brightness is {microscope.detector.brightness.value}"""
909 )
910 return True
913def detector_contrast(
914 microscope: tbt.Microscope,
915 contrast: float,
916 delay_s: float = 0.1,
917) -> bool:
918 """
919 Sets the detector contrast with input from 0 to 1.
921 This function sets the contrast for the detector on the microscope and waits for the specified delay.
923 Parameters
924 ----------
925 microscope : tbt.Microscope
926 The microscope object to configure.
927 contrast : float
928 The desired contrast value (from 0 to 1).
929 delay_s : float, optional
930 The delay in seconds to wait after adjusting the contrast (default is 0.1).
932 Returns
933 -------
934 bool
935 True if the contrast is set successfully, False otherwise.
937 Raises
938 ------
939 ValueError
940 If the contrast cannot be adjusted correctly.
942 Examples
943 --------
944 >>> import pytribeam.types as tbt
945 >>> microscope = tbt.Microscope()
946 >>> microscope.connect("localhost")
947 Client connecting to [localhost:7520]...
948 Client connected to [localhost:7520]
949 >>> success = detector_contrast(microscope, contrast=0.5)
950 >>> print(success)
951 True
952 """
953 microscope.detector.contrast.value = contrast
954 current_detector = microscope.detector.type.value
955 time.sleep(delay_s)
956 if not math.isclose(
957 microscope.detector.contrast.value,
958 contrast,
959 abs_tol=cs.Constants.contrast_brightness_tolerance,
960 ):
961 raise ValueError(
962 f"""Could not correctly adjust detector contrast,
963 requested {contrast} on {current_detector} detector,
964 current contrast is {microscope.detector.contrast.value}"""
965 )
966 return True
969def detector_cb(
970 microscope: tbt.Microscope,
971 detector_settings: tbt.Detector,
972 beam: tbt.Beam,
973) -> bool:
974 """
975 Sets detector contrast and brightness.
977 This function sets the contrast and brightness for the detector on the microscope.
978 It also runs the auto contrast-brightness function if specified in the detector settings.
979 Supports initial settings of contrast and brightness with fixed values before auto adjustment.
981 Parameters
982 ----------
983 microscope : tbt.Microscope
984 The microscope object to configure.
985 detector_settings : tbt.Detector
986 The detector settings, including contrast, brightness, and auto contrast-brightness settings.
987 beam : tbt.Beam
988 The beam type to configure.
990 Returns
991 -------
992 bool
993 True if the contrast and brightness are set successfully, False otherwise.
995 Examples
996 --------
997 >>> import pytribeam.types as tbt
998 >>> microscope = tbt.Microscope()
999 >>> microscope.connect("localhost")
1000 Client connecting to [localhost:7520]...
1001 Client connected to [localhost:7520]
1002 >>> beam = tbt.ElectronBeam(settings=None)
1003 >>> detector_settings = tbt.Detector(contrast=None, brightness=None, auto_cb_settings=tbt.ScanArea(left=0.1, top=0.1, width=0.8, height=0.8))
1004 >>> success = detector_cb(microscope, detector_settings, beam)
1005 >>> print(success)
1006 True
1008 >>> detector_settings = tbt.Detector(contrast=0.2, brightness=0.3, auto_cb_settings=None)
1009 >>> success = detector_cb(microscope, detector_settings, beam)
1010 >>> print(success)
1011 True
1012 >>> beam_brightness = microscope.detector.brightness.value
1013 >>> print(beam_brightness)
1014 0.3
1015 >>> beam_contrast = microscope.detector.contrast.value
1016 >>> print(beam_contrast)
1017 0.2
1018 """
1019 ### cannot ensure detector is the active one, will overwrite mode settings, so following line is not used
1020 # microscope.detector.type.value = detector_settings.type.value
1021 contrast = detector_settings.contrast
1022 brightness = detector_settings.brightness
1023 if contrast is not None:
1024 detector_contrast(microscope=microscope, contrast=contrast)
1025 if brightness is not None:
1026 detector_brightness(microscope=microscope, brightness=brightness)
1028 null_scan = tbt.ScanArea(left=None, top=None, width=None, height=None)
1029 if not null_scan == detector_settings.auto_cb_settings:
1030 detector_auto_cb(
1031 microscope=microscope,
1032 settings=detector_settings.auto_cb_settings,
1033 beam=beam,
1034 )
1035 return True
1038def detector_mode(
1039 microscope: tbt.Microscope,
1040 detector_mode: tbt.DetectorMode,
1041 delay_s: float = 0.1,
1042) -> bool:
1043 """
1044 Sets the detector mode.
1046 This function sets the mode for the detector on the microscope and waits for the specified delay.
1048 Parameters
1049 ----------
1050 microscope : tbt.Microscope
1051 The microscope object to configure.
1052 detector_mode : tbt.DetectorMode
1053 The desired detector mode.
1054 delay_s : float, optional
1055 The delay in seconds to wait after setting the detector mode (default is 0.1).
1057 Returns
1058 -------
1059 bool
1060 True if the detector mode is set successfully, False otherwise.
1062 Raises
1063 ------
1064 ValueError
1065 If the detector mode cannot be set correctly.
1067 Examples
1068 --------
1069 >>> import pytribeam.types as tbt
1070 >>> microscope = tbt.Microscope()
1071 >>> microscope.connect("localhost")
1072 Client connecting to [localhost:7520]...
1073 Client connected to [localhost:7520]
1074 >>> mode = tbt.DetectorMode.SECONDARY_ELECTRONS
1075 >>> success = detector_mode(microscope, mode)
1076 >>> print(success)
1077 True
1078 """
1079 microscope.detector.mode.value = detector_mode.value
1080 time.sleep(delay_s)
1081 if microscope.detector.mode.value != detector_mode.value:
1082 raise ValueError(
1083 f"""Could not correctly set detector mode,
1084 requested {detector_mode}, current mode is
1085 {microscope.detector.mode.value}"""
1086 )
1087 return True
1090def detector_type(
1091 microscope: tbt.Microscope,
1092 detector: tbt.DetectorType,
1093 delay_s: float = 0.1,
1094) -> bool:
1095 """
1096 Sets the detector type.
1098 This function sets the type for the detector on the microscope and waits for the specified delay.
1100 Parameters
1101 ----------
1102 microscope : tbt.Microscope
1103 The microscope object to configure.
1104 detector : tbt.DetectorType
1105 The desired detector type.
1106 delay_s : float, optional
1107 The delay in seconds to wait after setting the detector type (default is 0.1).
1109 Returns
1110 -------
1111 bool
1112 True if the detector type is set successfully, False otherwise.
1114 Raises
1115 ------
1116 ValueError
1117 If the detector type cannot be set correctly.
1119 Examples
1120 --------
1121 >>> import pytribeam.types as tbt
1122 >>> microscope = tbt.Microscope()
1123 >>> microscope.connect("localhost")
1124 Client connecting to [localhost:7520]...
1125 Client connected to [localhost:7520]
1126 >>> detector = tbt.DetectorType.ETD
1127 >>> success = detector_type(microscope, detector)
1128 >>> print(success)
1129 True
1130 """
1131 microscope.detector.type.value = detector.value
1132 time.sleep(delay_s)
1133 if microscope.detector.type.value != detector.value:
1134 raise ValueError(
1135 f"""Could not correctly set detector type,
1136 requested {detector}, current detector is
1137 {microscope.detector.type.value}"""
1138 )
1139 return True
1142def grab_custom_resolution_frame(
1143 img_settings: tbt.ImageSettings,
1144 save_path: Path,
1145) -> bool:
1146 """
1147 Method for single frame imaging used with custom resolutions.
1149 This function captures a single frame image using custom resolutions and saves it to the specified path.
1151 Parameters
1152 ----------
1153 img_settings : tbt.ImageSettings
1154 The image settings, including the microscope and scan resolution.
1155 save_path : Path
1156 The path to save the captured image.
1158 Returns
1159 -------
1160 bool
1161 True if the image is captured and saved successfully, False otherwise.
1163 Examples
1164 --------
1165 >>> import pytribeam.types as tbt
1166 >>> from pathlib import Path
1167 >>> microscope = tbt.Microscope()
1168 >>> microscope.connect("localhost")
1169 Client connecting to [localhost:7520]...
1170 Client connected to [localhost:7520]
1171 >>> img_settings = tbt.ImageSettings(
1172 ... microscope=microscope,
1173 ... beam=tbt.ElectronBeam(settings=None),
1174 ... detector=tbt.Detector(),
1175 ... scan=tbt.Scan(resolution=tbt.Resolution(width=1024, height=768)),
1176 ... bit_depth=tbt.ColorDepth.BITS_8,
1177 ... )
1178 >>> save_path = Path("/path/to/save/image.tif")
1179 >>> success = grab_custom_resolution_frame(img_settings, save_path)
1180 >>> print(success)
1181 True
1182 """
1183 microscope = img_settings.microscope
1184 resolution = img_settings.scan.resolution
1185 microscope.imaging.grab_frame_to_disk(
1186 save_path.absolute().as_posix(),
1187 file_format=tbt.ImageFileFormat.TIFF.value,
1188 settings=tbt.GrabFrameSettings(
1189 resolution=f"{resolution.width}x{resolution.height}"
1190 ),
1191 )
1192 return True
1195def grab_preset_resolution_frame(
1196 img_settings: tbt.ImageSettings,
1197) -> tbt.AdornedImage:
1198 """
1199 Method for single frame imaging used with preset resolutions.
1201 This function captures a single frame image using preset resolutions.
1203 Parameters
1204 ----------
1205 img_settings : tbt.ImageSettings
1206 The image settings, including the microscope, beam, detector, and scan resolution.
1208 Returns
1209 -------
1210 tbt.AdornedImage
1211 The captured image.
1213 Examples
1214 --------
1215 >>> import pytribeam.types as tbt
1216 >>> microscope = tbt.Microscope()
1217 >>> microscope.connect("localhost")
1218 Client connecting to [localhost:7520]...
1219 Client connected to [localhost:7520]
1220 >>> img_settings = tbt.ImageSettings(
1221 ... microscope=microscope,
1222 ... beam=tbt.ElectronBeam(settings=None),
1223 ... detector=tbt.Detector(),
1224 ... scan=tbt.Scan(resolution=tbt.PresetResolution.PRESET_768X512),
1225 ... bit_depth=tbt.ColorDepth.BITS_8,
1226 ... )
1227 >>> image = grab_preset_resolution_frame(img_settings)
1228 >>> print(image)
1229 AdornedImage(width=768, height=512, bit_depth=8)
1230 """
1231 beam = img_settings.beam
1232 microscope = img_settings.microscope
1233 beam_scan_resolution(
1234 beam=beam,
1235 microscope=microscope,
1236 resolution=img_settings.scan.resolution,
1237 )
1238 return microscope.imaging.grab_frame(
1239 tbt.GrabFrameSettings(bit_depth=img_settings.bit_depth)
1240 )
1243def imaging_detector(img_settings: tbt.ImageSettings) -> bool:
1244 """
1245 Prepares the detector and inserts it if applicable.
1247 This function sets the detector type, inserts the detector if necessary, sets the detector mode,
1248 and adjusts the contrast and brightness settings. It is important to set detector mode settings
1249 right before contrast and brightness as any subsequent calls to a detector type can overwrite the mode.
1251 Parameters
1252 ----------
1253 img_settings : tbt.ImageSettings
1254 The image settings, including the microscope, beam, and detector settings.
1256 Returns
1257 -------
1258 bool
1259 True if the detector is prepared successfully, False otherwise.
1261 Examples
1262 --------
1263 >>> import pytribeam.types as tbt
1264 >>> microscope = tbt.Microscope()
1265 >>> microscope.connect("localhost")
1266 Client connecting to [localhost:7520]...
1267 Client connected to [localhost:7520]
1268 >>> img_settings = tbt.ImageSettings(
1269 ... microscope=microscope,
1270 ... beam=tbt.ElectronBeam(settings=None),
1271 ... detector=tbt.Detector(
1272 ... type=tbt.DetectorType.ETD,
1273 ... mode=tbt.DetectorMode.SECONDARY_ELECTRONS,
1274 ... brightness=0.4,
1275 ... contrast=0.2,
1276 ... ),
1277 ... scan=tbt.Scan(resolution=tbt.PresetResolution.PRESET_768X512),
1278 ... bit_depth=tbt.ColorDepth.BITS_8,
1279 ... )
1280 >>> success = imaging_detector(img_settings)
1281 >>> print(success)
1282 True
1283 """
1284 microscope = img_settings.microscope
1285 detector = img_settings.detector.type
1286 detector_type(
1287 microscope=microscope,
1288 detector=detector,
1289 )
1290 detector_state = devices.detector_state(
1291 microscope=microscope,
1292 detector=detector,
1293 )
1294 if detector_state is not None:
1295 devices.insert_detector(
1296 microscope=microscope,
1297 detector=detector,
1298 )
1299 detector_mode(
1300 microscope=microscope,
1301 detector_mode=img_settings.detector.mode,
1302 )
1303 detector_cb(
1304 microscope=microscope,
1305 detector_settings=img_settings.detector,
1306 beam=img_settings.beam,
1307 )
1308 return True
1311def imaging_device(
1312 microscope: tbt.Microscope,
1313 beam: tbt.Beam,
1314) -> bool:
1315 """
1316 Prepares the imaging beam, viewing quad, and the beam voltage and current.
1318 This function sets the beam device, ensures the beam is ready, sets the beam voltage and current,
1319 and applies angular correction if the beam type is electron.
1321 Parameters
1322 ----------
1323 microscope : tbt.Microscope
1324 The microscope object to configure.
1325 beam : tbt.Beam
1326 The beam type to configure, including its settings.
1328 Returns
1329 -------
1330 bool
1331 True if the imaging device is prepared successfully, False otherwise.
1332 """
1333 set_beam_device(microscope=microscope, device=beam.device)
1334 beam_ready(beam=beam, microscope=microscope)
1335 beam_voltage(
1336 beam=beam,
1337 microscope=microscope,
1338 voltage_kv=beam.settings.voltage_kv,
1339 voltage_tol_kv=beam.settings.voltage_tol_kv,
1340 )
1341 beam_current(
1342 beam=beam,
1343 microscope=microscope,
1344 current_na=beam.settings.current_na,
1345 current_tol_na=beam.settings.current_tol_na,
1346 )
1347 if beam.type == tbt.BeamType.ELECTRON:
1348 beam_angular_correction(
1349 microscope=microscope,
1350 dynamic_focus=beam.settings.dynamic_focus,
1351 tilt_correction=beam.settings.tilt_correction,
1352 )
1353 return True
1356def imaging_scan(img_settings: tbt.ImageSettings) -> bool:
1357 """
1358 Sets all scan settings except for the resolution.
1360 This function configures the scan settings for the specified image settings, including
1361 setting the scan mode to full frame, scan rotation, working distance, horizontal field width,
1362 and dwell time.
1364 Parameters
1365 ----------
1366 img_settings : tbt.ImageSettings
1367 The image settings, including the microscope, beam, and scan settings.
1369 Returns
1370 -------
1371 bool
1372 True if the scan settings are configured successfully, False otherwise.
1373 """
1374 microscope = img_settings.microscope
1375 beam = img_settings.beam
1376 beam_scan_full_frame(
1377 beam=beam,
1378 microscope=microscope,
1379 )
1380 beam_scan_rotation(
1381 beam=beam, microscope=microscope, rotation_deg=img_settings.scan.rotation_deg
1382 )
1383 beam_working_distance(
1384 beam=beam,
1385 microscope=microscope,
1386 wd_mm=img_settings.beam.settings.working_dist_mm,
1387 )
1388 beam_hfw(beam=beam, microscope=microscope, hfw_mm=img_settings.beam.settings.hfw_mm)
1389 beam_dwell_time(
1390 beam=beam, microscope=microscope, dwell_us=img_settings.scan.dwell_time_us
1391 )
1392 return True
1395def prepare_imaging(img_settings: tbt.ImageSettings) -> bool:
1396 """
1397 Prepares various imaging settings.
1399 This function prepares the imaging device, scan settings, and detector settings
1400 based on the specified image settings.
1402 Parameters
1403 ----------
1404 img_settings : tbt.ImageSettings
1405 The image settings, including the microscope, beam, scan, and detector settings.
1407 Returns
1408 -------
1409 bool
1410 True if the imaging settings are prepared successfully, False otherwise.
1411 """
1412 imaging_device(microscope=img_settings.microscope, beam=img_settings.beam)
1413 imaging_scan(img_settings=img_settings)
1414 imaging_detector(img_settings=img_settings)
1415 return True
1418def set_view(
1419 microscope: tbt.Microscope,
1420 quad: tbt.ViewQuad,
1421) -> bool:
1422 """
1423 Sets the active view to the specified quad.
1425 This function sets the active imaging view to the specified quad on the microscope.
1427 Parameters
1428 ----------
1429 microscope : tbt.Microscope
1430 The microscope object to configure.
1431 quad : tbt.ViewQuad
1432 The imaging view to select:
1433 - 1 is upper left
1434 - 2 is upper right
1435 - 3 is lower left
1436 - 4 is lower right
1438 Returns
1439 -------
1440 bool
1441 True if the active view is set successfully, False otherwise.
1442 """
1443 microscope.imaging.set_active_view(quad.value)
1446def set_beam_device(
1447 microscope: tbt.Microscope,
1448 device: tbt.Device,
1449 delay_s: float = 0.1,
1450) -> bool:
1451 """
1452 Sets the active imaging device.
1454 This function sets the active imaging device on the microscope and waits for the specified delay.
1456 Parameters
1457 ----------
1458 microscope : tbt.Microscope
1459 The microscope object to configure.
1460 device : tbt.Device
1461 The desired imaging device.
1462 delay_s : float, optional
1463 The delay in seconds to wait after setting the device (default is 0.1).
1465 Returns
1466 -------
1467 bool
1468 True if the active device is set successfully, False otherwise.
1470 Raises
1471 ------
1472 ValueError
1473 If the active device cannot be set correctly.
1474 """
1475 microscope.imaging.set_active_device(device)
1476 time.sleep(delay_s)
1477 curr_device = tbt.Device(microscope.imaging.get_active_device())
1478 if curr_device != device.value:
1479 raise ValueError(
1480 f"""Could not set active device,
1481 requested device {device.value} but current device is {curr_device}.
1482 Device list:
1483 {tbt.Device.ELECTRON_BEAM.value}: Electron Beam
1484 {tbt.Device.ION_BEAM.value}: Ion Beam
1485 {tbt.Device.CCD_CAMERA.value}: CCD Camera
1486 {tbt.Device.IR_CAMERA.value}: IR Camera
1487 {tbt.Device.NAV_CAM.value}: Nav Cam"""
1488 )
1489 return True
1492#################
1495def collect_single_image(
1496 save_path: Path,
1497 img_settings: tbt.ImageSettings,
1498) -> bool:
1499 """
1500 Collects a single frame image with defined image settings.
1502 This function prepares the imaging settings, sets the view, and captures a single frame image.
1503 It saves the image to the specified path. If a non-preset resolution is requested, the image
1504 will be saved at 8-bit color depth.
1506 Parameters
1507 ----------
1508 save_path : Path
1509 The path to save the captured image.
1510 img_settings : tbt.ImageSettings
1511 The image settings, including the microscope, beam, scan, and detector settings.
1513 Returns
1514 -------
1515 bool
1516 True if the image is captured and saved successfully, False otherwise.
1517 """
1518 beam = img_settings.beam
1519 microscope = img_settings.microscope
1520 set_view(microscope=microscope, quad=beam.default_view)
1521 prepare_imaging(img_settings=img_settings)
1523 resolution = img_settings.scan.resolution
1524 if isinstance(resolution, tbt.PresetResolution):
1525 img = grab_preset_resolution_frame(img_settings=img_settings)
1526 img.save(str(save_path))
1527 return True
1528 warnings.warn(
1529 f'Warning, non-preset resolution of "{img_settings.scan.resolution}" requested. Image will automatically be saved at 8-bit color depth'
1530 )
1531 if img_settings.bit_depth != tbt.ColorDepth.BITS_8:
1532 warnings.warn(
1533 f"Warning, non-preset resolution necessitates images be stored at 8-bit color depth, requested bit-depth of {img_settings.bit_depth.value} will be ignored."
1534 )
1535 grab_custom_resolution_frame(
1536 img_settings=img_settings,
1537 save_path=save_path,
1538 )
1539 return True
1542def collect_multiple_images(
1543 multiple_img_settings: List[tbt.ImageSettings], num_frames: int
1544) -> List[tbt.AdornedImage]:
1545 """
1546 Sets up scanning for multiple frames.
1548 This function is best used for collecting multiple segments on a single detector simultaneously.
1549 It is limited to preset resolutions only.
1551 Parameters
1552 ----------
1553 multiple_img_settings : List[tbt.ImageSettings]
1554 The list of image settings for each frame, including the microscope, beam, scan, and detector settings.
1555 num_frames : int
1556 The number of frames to collect.
1558 Returns
1559 -------
1560 List[tbt.AdornedImage]
1561 The list of captured images.
1563 Raises
1564 ------
1565 ValueError
1566 If a non-preset resolution is requested for simultaneous multiple frame imaging.
1568 Notes
1569 -----
1570 This method has not yet been tested.
1572 """
1573 # TODO test this
1574 warnings.warn("Method not yet tested")
1575 views = []
1576 for quad in range(1, num_frames + 1):
1577 img_settings = multiple_img_settings[quad]
1578 resolution = img_settings.scan.resolution
1579 if not isinstance(resolution, tbt.PresetResolution):
1580 raise ValueError(
1581 f'Only preset resolutions allowed for simultaneous multiple frame imaging, but resolution of "{resolution.width}x{resolution.height}" was requested.'
1582 )
1584 microscope = img_settings.microscope
1585 beam = img_settings.beam
1586 views.append(quad)
1587 set_view(microscope=microscope, quad=quad)
1588 prepare_imaging(microscope=microscope, beam=beam, img_settings=img_settings)
1589 frames = microscope.imaging.grab_multiple_frames(
1590 tbt.GrabFrameSettings(bit_depth=img_settings.bit_depth, views=views)
1591 )
1592 return frames
1595# TODO
1596# def image_method(dict):
1597# """determine imaging method and return associated function"""
1598# pass
1600# TODO
1601# def collect_tiling_image():
1602# for loop
1603# collect_standard_image
1604# #stage move
1607# TODO add more complex imaging behavior, determine method in this function
1608def image_operation(
1609 step: tbt.Step,
1610 image_settings: tbt.ImageSettings,
1611 general_settings: tbt.GeneralSettings,
1612 slice_number: int,
1613) -> bool:
1614 """
1615 Performs an image operation based on the specified settings.
1617 This function collects an image, saves it to the specified directory, and turns off tilt correction and dynamic focus.
1619 Parameters
1620 ----------
1621 step : tbt.Step
1622 The step information, including the name of the step.
1623 image_settings : tbt.ImageSettings
1624 The image settings, including the microscope, beam, scan, and detector settings.
1625 general_settings : tbt.GeneralSettings
1626 The general settings, including the experimental directory.
1627 slice_number : int
1628 The slice number for naming the saved image file.
1630 Returns
1631 -------
1632 bool
1633 True if the image operation is performed successfully, False otherwise.
1634 """
1635 print("\tCollecting image")
1636 # create folder in same directory as experimental directory
1637 image_directory = Path(general_settings.exp_dir).joinpath(step.name)
1638 image_directory.mkdir(parents=True, exist_ok=True)
1640 # TODO
1641 # determine_image_method()
1642 # collect_multiple_images()
1644 # single image process:
1645 save_path = image_directory.joinpath(f"{slice_number:04}.tif")
1646 collect_single_image(save_path=save_path, img_settings=image_settings)
1647 print(f"\tImage saved to {save_path}")
1649 # turn off tilt correction and dynamic focus
1650 beam_angular_correction(
1651 microscope=image_settings.microscope,
1652 dynamic_focus=False,
1653 tilt_correction=False,
1654 )
1656 return True