autoemxsp.core.EM_controller module
Automated Electron Microscopy (EM) Controller and Sample Image Analyzer
This module provides classes and functions for automated analysis and acquisition in scanning electron microscopy (SEM), including particle detection, stage navigation, X-ray spectra (EDS, WDS) acquisition, and sample management. It is designed to interface with an EM driver and streamline the workflow from image acquisition to data export.
Main Classes
- EM_Controller
Automates particle detection, mask generation, and X-ray spectra acquisition on detected particles. Supports both fully automated and manual (user-guided) collection modes. Provides methods for collecting particle statistics and managing frame navigation.
- EM_Sample_Finder
Provides utilities for locating and managing samples within the EM. Currently includes only the detection of the center of a Carbon tape.
Example Usage
# EDS spot acquisition workflow: >>> particle_finder = EM_Particle_Finder(…) >>> particle_finder.initialise_SEM() >>> while True: … particle_finder.go_to_next_particle() … xy_spot_list = particle_finder.get_XS_acquisition_spots_coord_list() … # Collect X-ray spectra at each (x, y) as needed
# Particle analysis workflow: >>> from em_analysis import EM_Particle_Finder, EM_Sample_Finder >>> microscope_cfg = {…} >>> measurement_cfg = {…} >>> holder_cfg = {…} >>> particle_finder = EM_Particle_Finder( … sample_ID=”Sample1”, … microscope_d=microscope_cfg, … measurement_d=measurement_cfg, … sample_holder_d=holder_cfg, … results_dir=”./results” … ) >>> particle_finder.initialise_SEM() >>> particle_finder.get_particle_stats(n_par_target=500)
# C tape detection workflow: >>> from em_analysis import EM_Sample_Finder >>> finder = EM_Sample_Finder(‘MySEM’, (0, 0), 3, 12, ‘./results’, verbose=True) >>> Ctape_coords = finder.detect_Ctape() >>> if Ctape_coords: … print(“Center (mm):”, Ctape_coords[0], “Half-width (mm):”, Ctape_coords[1])
Notes
Requires a working EM_driver and appropriate hardware configuration, with the following API functions:
- load_microscope_driver(microscope_ID)
Load and initialize the instrument-specific driver.
- activate()
Wake up and activate the electron microscope.
- to_SEM()
Switch the microscope to SEM (scanning electron microscopy) mode.
- set_electron_detector_mode(mode)
Set the electron detector mode (e.g., ‘All’, ‘BSD’).
- set_high_tension(voltage)
Set the accelerating voltage (high tension) for the electron beam.
- set_beam_current(current)
Set the electron beam current.
- get_range_frame_width()
Query the allowed minimum and maximum frame widths (in mm).
- set_frame_width(width)
Set the field of view/frame width (in mm).
- adjust_focus(wd)
Set the working distance/focus to a specific value (in mm).
- move_to(x, y)
Move the microscope stage to the specified (x, y) position.
- get_frame_width()
Get the current frame width (in mm).
- get_navigation_camera_image()
Acquire an image from the navigation camera.
- auto_focus()
Run the microscope’s autofocus routine and return the resulting working distance.
- auto_contrast_brightness()
Automatically adjust the microscope’s brightness and contrast.
- set_brightness(value)
Set the frame brightness to a specific value.
- set_contrast(value)
Set the frame contrast to a specific value. (NOTE: This may be a typo; check if the correct function is set_contrast.)
- get_EDS_analyser_object()
Create and return an EDS (energy-dispersive X-ray spectroscopy) analyzer object.
- acquire_XS_spectral_data(analyzer, x, y, max_time, target_counts)
Acquire an X-ray spectrum at the specified position with given analyzer and parameters.
- image_to_stage_coords_transform
Transformation matrix for converting image to stage coordinates.
- navcam_im_w_mm
Navigation camera image width in mm.
- navcam_x_offset
Navigation camera X offset.
- navcam_y_offset
Navigation camera Y offset.
- microscope_calib_dir
Directory containing microscope calibration files.
- is_at_EM
Boolean indicating if the code is running at the microscope.
- typical_wd
Typical working distance (mm).
- im_width
Image width in pixels.
- im_height
Image height in pixels.
Created on Wed Jul 31 09:28:07 2024
@author: Andrea
- class autoemxsp.core.EM_controller.EM_Controller(microscope_cfg: MicroscopeConfig, sample_cfg: SampleConfig, measurement_cfg: MeasurementConfig, sample_substrate_cfg: SampleSubstrateConfig, powder_meas_cfg: PowderMeasurementConfig, bulk_meas_cfg: BulkMeasurementConfig, init_fw: float = 0.5, results_dir: str | None = None, verbose: bool = True, development_mode: bool | None = False)[source]
Bases:
object- an_circle_key = 'circle'
- an_text_key = 'text'
Electron Microscope (EM) controller for automated particle analysis and X-ray spectra (EDS, WDS) acquisition.
This class provides methods for automated image acquisition, stage navigation, and X-ray spectral acquisition. It is designed to interface with a microscope driver (EM_driver) for stage movement and image capture.
- Configuration is provided via structured dataclasses:
MicroscopeConfig
SampleConfig
MeasurementConfig
SampleSubstrateConfig
- initialise_SEM()
Wakes up the SEM microscope, sets measurement parameters, and evaluates locations to scan for particles.
- initialise_XS_analyzer()
Gets EDS/WDS analyzer object from EM_driver, and optionally updates electron beam energy. Currently only EDS is supported.
- acquire_XS_spot_spectrum(x,y)
Acquire and return X-Ray spectral data in position (x,y) in current stage position. (x,y) are relative coordinates. See function description for more information. Currently only EDS spectra are supported.
# EDS spot acquisition workflow: >>> EM_controller = EM_Controller(…) >>> EM_controller.initialise_SEM() >>> particle_finder = EM_Particle_Finder(EM_controller, PowderMeasurementConfig, …) >>> while particle_finder.go_to_next_particle(): … xy_spot_list = particle_finder.get_XS_acquisition_spots_coord_list() … for (x,y) in xy_spot_list: … EM_controller.acquire_XS_spectrum()
# Particle analysis workflow: >>> EM_controller = EM_Controller(…) >>> EM_controller.initialise_SEM() >>> particle_finder = EM_Particle_Finder(EM_controller, PowderMeasurementConfig, results_dir=”./results”) >>> particle_finder.get_particle_stats(n_par_target=500)
- Attributes
- sample_cfgSampleConfig
Sample configuration (see dataclass for details).
- microscope_cfgMicroscopeConfig
Microscope configuration (see dataclass for details).
- measurement_cfgMeasurementConfig
Measurement/acquisition configuration (see dataclass for details).
- sample_substrate_cfgSampleSubstrateConfig
Sample substrate configuration (see dataclass for details).
- powder_meas_cfgPowderMeasurementConfig
Configuration for powder measurement.
- bulk_meas_cfgBulkMeasurementConfig
Configuration for measurements of bulk or bulk-like samples.
- init_wdfloat
Initial working distance in mm (used to limit autofocus range, set at EM driver).
- im_widthint
Image width in pixels (set at EM driver).
- im_heightint
Image height in pixels (set at EM driver).
- grid_search_fw_mmfloat
Frame width (in mm) used during initial grid search.
- pixel_size_umfloat or None
Pixel size in micrometers of current image.
- current_frame_labelstr
Label of currently analyzed frame. Initialized as an empty string for testing
- refresh_timefloat
Time in seconds after which autofocus and brightness are refreshed.
- frame_labelslist
List of frame labels or identifiers.
- results_dirstr or None
Directory for saving result images and data.
- verbosebool
If True, print progress and information to the console.
- development_mode (bool): Whether class is being used for testing image processing functions, without real-time acquisition.
Enables use of class outside microscope enviroment
- _center_postuple of float
Sample center position (x, y) on the microscope stage (from sample_cfg).
- _sample_hw_mmfloat
Half-width of the sample region in mm (from sample_substrate_cfg).
- _min_wdfloat
Minimum allowed working distance in mm.
- _max_wdfloat
Maximum allowed working distance in mm.
- _frame_cntrint
Counter for the number of frames analyzed.
- _current_postuple of float
Current (x, y) position in the sample coordinate system.
- _last_EM_adjustment_timefloat
Timestamp of the last EM adjustment (autofocus/brightness)
- _is_first_sprectrum_acqbool
Flag for indicating acquisition of first spectrum. Used to export .msa spectral file
This class assumes that the global EM_driver object is available and properly configured.
Configuration is provided via dataclasses. All validation of configuration fields is performed in the dataclasses.
Attributes with a leading underscore are for internal use and should not be accessed directly by users.
- initialise_SEM() None[source]
Activate and configure the Scanning Electron Microscope (SEM) for particle finding.
- This method performs the following steps:
Wakes up the SEM if necessary.
Switches to SEM mode.
Sets the electron detector mode to backscattered electrons (BSD).
Sets the beam voltage and current according to the current measurement mode calibration.
Initializes the EDS analyzer object.
Moves to sample center, sets frame width, and working distance.
Adjusts focus, brightness, and contrast.
Calculates frame centers for searching.
Initializes particle/frame counters.
- Raises:
KeyError – If the current measurement mode is not found in the calibration dictionary.
EMError – If an error occurs during SEM activation or configuration.
Notes
This method assumes that EM_driver is an initialized and accessible object that provides the necessary SEM control methods.
- Potential improvement for SEM initialization:
Fix initial brightness and contrast so that C tape is fully below threshold.
Go to first frame where it finds particles.
Go to first (or biggest) particle and adjust brightness and contrast.
Go to second, and cross-check values.
If equal, use these brightness and contrast values.
If encountering multiple contamination particles, repeat this.
Revert to these values every time large scale particle segmentation is needed.
Alternatively, brightness and contrast could be passed manually.
Initialize the sample navigator for automated spectra collection.
Only ‘powder’ and ‘bulk’ samples are currently supported for automated particle detection and navigation. For other sample types, use manual navigation, setting measurement_cfg.is_manual_navigation = True.
- Parameters:
EM_controller (EM_Controller object) – Required for analysis of samples of type = ‘powder’
exclude_sample_margin (bool, optional) – Whether to use a margin when calculating frame centers. Reduces explored sample area, but avoids sample edges, which may be contaminated, or affected by larger substrate signal. (default: True).
- Raises:
NotImplementedError – If the sample type is not ‘powder’ and manual navigation is not enabled.
- initialise_XS_analyzer(beam_voltage: float = None)[source]
Initialize the EDS (Energy Dispersive X-ray Spectroscopy) analyzer and optionally set the electron beam voltage.
If beam_voltage remains unspecified, uses current voltage initially set during EM initialization.
- Parameters:
beam_voltage (float, optional) – Desired EM beam voltage (in kilovolts, kV) for EDS acquisition. If provided, sets the high tension to this value. If not provided, the current beam voltage is used.
Notes
This method creates an EDS analyzer object via the EM driver.
The beam voltage should be specified in kV (e.g., 20.0 for 20 kV).
- get_XSp_coords(n_tot_sp_collected: int) Tuple[bool, List[Tuple[float, float]] | None, int | None][source]
Determine X-ray spectrum acquisition coordinates for the next spectrum.
Depending on the navigation mode, either prompts the user to select a spot manually, or automatically selects the next particle spot for ‘powder’ samples.
- Parameters:
n_tot_sp_collected (int) – The current total number of spectra collected (used for labeling and selection).
- Returns:
success (bool) – True if a spot was selected/found, False if user stopped or no more particles.
spots_xy_list (list of tuple[float, float] or None) – List of (x, y) coordinates for acquisition spots, or None if unsuccessful.
particle_cntr (int or None) – The particle counter/index, or None if not applicable.
Notes
For manual navigation, the user is prompted to select the spot.
For powder samples, the next particle is selected automatically.
Assumes required attributes (e.g., self.im_width, self.particle_finder) are initialized.
- convert_XS_coords_to_pixels(xy_coords)[source]
Convert XY coordinates from the XS coordinate system to pixel coordinates.
This function uses the EM_driver to transform coordinates relative to the frame into pixel positions based on the image width and height. The returned pixel coordinates are integer values.
- Parameters:
xy_coords (tuple(float, float)) – The XY coordinates in the XS coordinate system to be converted.
- Returns:
The corresponding (x, y) pixel coordinates as integers.
- Return type:
tuple(int, int)
- acquire_XS_spot_spectrum(x: float, y: float, max_acquisition_time: float, target_acquisition_counts: int) tuple[source]
Acquire an X-ray spectrum (EDS/WDS) at the specified (x, y) position.
- Parameters:
x (float) –
X, Y coordinates for spectrum acquisition (in relative image units, as required by EM_driver).
The coordinates are expressed in a normalized, aspect-ratio-correct system centered at the image center:
The origin (0, 0) is at the image center.
The x-axis is horizontal, increasing to the right, ranging from -0.5 (left) to +0.5 (right).
- The y-axis is vertical, increasing downward, and scaled by the aspect ratio (height/width):
Top edge: y = -0.5 × (height / width)
Bottom edge: y = +0.5 × (height / width)
(-0.5, -0.5*height/width) (0.5, -0.5*height/width)- v +y +————————-+
(-0.5, 0.5*height/width) (0.5, 0.5*height/width)
This ensures the coordinate system is always centered and aspect-ratio-correct, regardless of image size.
y (float) –
X, Y coordinates for spectrum acquisition (in relative image units, as required by EM_driver).
The coordinates are expressed in a normalized, aspect-ratio-correct system centered at the image center:
The origin (0, 0) is at the image center.
The x-axis is horizontal, increasing to the right, ranging from -0.5 (left) to +0.5 (right).
- The y-axis is vertical, increasing downward, and scaled by the aspect ratio (height/width):
Top edge: y = -0.5 × (height / width)
Bottom edge: y = +0.5 × (height / width)
(-0.5, -0.5*height/width) (0.5, -0.5*height/width)- v +y +————————-+
(-0.5, 0.5*height/width) (0.5, 0.5*height/width)
This ensures the coordinate system is always centered and aspect-ratio-correct, regardless of image size.
max_acquisition_time (float) – Maximum allowed acquisition time in seconds.
target_acquisition_counts (int) – Target total X-ray counts for the spectrum.
- Returns:
spectrum_data (Any) – The acquired spectrum data (format as returned by EM_driver).
background_data (Any) – The measured background data (format as returned by EM_driver).
real_time (float) – Real elapsed time for the acquisition (seconds).
live_time (float) – Detector live time for the acquisition (seconds).
- Raises:
EMError – If the spectrum acquisition fails.
- adjust_BCF() float[source]
Adjust brightness, contrast, and focus (BCF).
If automatic brightness and contrast adjustment is enabled (self.microscope_cfg.is_auto_BC), calls the automatic adjustment method. Otherwise, sets brightness and contrast to fixed values and then performs autofocus.
- Returns:
None
Updates
——-
self._last_EM_adjustment_time
- Raises:
EMError – If an error occurs during brightness, contrast, or focus adjustment.
- set_frame_width(frame_width)[source]
Set the frame width at the microscope and update the pixel size accordingly.
- Parameters:
frame_width (float) – The desired frame width in millimeters.
Updates
-------
self.pixel_size_um (float) – The image pixel size in micrometers, calculated as (frame_width / image width in pixels) * 1000.
- move_to_pos(pos)[source]
Move the EM stage to the specified (x, y) position and update the current position.
- Parameters:
pos (tuple of float) – Target (x, y) coordinates.
Updates
-------
self._current_pos (tuple of float) – The current position is set to the specified (x, y) coordinates.
- convert_pixel_pos_to_mm(pos_pixels)[source]
Convert a position from pixel coordinates in the current image to absolute stage coordinates in millimeters.
- Parameters:
pos_pixels (array-like of float) – Position in pixel coordinates (x, y).
- Returns:
pos_abs_mm – Absolute position in millimeters (x, y), suitable for EM stage movement.
- Return type:
ndarray of float
- go_to_next_frame()[source]
Moves the microscope to the next frame position in the current sample.
This function checks if there are remaining frames to analyze. If so, it moves the microscope stage to the next frame center, adjusts the frame width if necessary, and (optionally) updates EM brightness, contrast and focus. It also prints the current frame information if verbose mode is enabled.
- Returns:
True if moved to the next frame, False if no frames remain to be analysed.
- Return type:
bool
- save_frame_image(filename, im_annotations=None, frame_image=None, save_dir=None)[source]
Save an annotated and raw electron microscopy (EM) frame as a multi-page TIFF.
This function retrieves a raw grayscale EM image, generates an annotated RGB version with optional markers and a scale bar, and saves both images into a single multi-page TIFF file. The annotated image is stored as the first page, and the raw image as the second page.
- Parameters:
filename (str) – Name used for saved .tif image file
im_annotations (dict | list(dict) | None, optional) –
- A dictionary with the following keys:
- ’text’tuple(text, xy_coords)
text: str, text to print xy_coords : (int, int), coordinates in pixels where to place the text
- ’circle’tuple(radius, xy_center, is_filled, border_thickness)
radius : int, radius of circle, in pixels xy_center : (int, int), (x,y) coordinates of center, in pixels thickness : int, thickness of circle border. Set to -1 for filling
For multiple annotations, use a list of dictionaries. Do not include the relative key if that particular annotation is not desired.
frame_image (np.array | None, opt) – Frame image to save. Captures the current frame image if not provided
save_dir (str, optional) – Directory in which to save the TIFF file. Defaults to self.results_dir if available, otherwise it needs to be provided.
Notes
Images are saved as RGB to maximize compatibility across platforms.
- class autoemxsp.core.EM_controller.EM_Sample_Finder(microscope_ID: str, center_pos: ndarray | tuple | list, sample_half_width_mm: float, substrate_width_mm: float, development_mode: bool | None = False, results_dir: str | None = None, verbose: bool = False)[source]
Bases:
objectClass for locating and managing samples in an electron microscope (EM).
This class provides methods for detecting sample features (such as the center and size of a C tape) using the microscope’s navigation camera.
- microscope_ID
Identifier for the target microscope.
- Type:
str
- center_pos
Initial center position of sample as a NumPy array of shape (2,), representing [x, y] coordinates.
- Type:
np.ndarray
- results_dir
Directory path to save results, or None if not set.
- Type:
Optional[str]
- verbose
If True, enables detailed debug output.
- Type:
bool
- development_mode(bool)
Enables use of class outside microscope enviroment
- Type:
Whether class is being used for testing image processing functions, without real-time acquisition.
Example
>>> import numpy as np >>> sample_center = np.array([0.0, 0.0]) # stage coordinates in mm >>> finder = EM_Sample_Finder( ... microscope_ID='MySEM', ... center_pos=sample_center, ... sample_half_width_mm: 3, ... substrate_width_mm: 12, ... results_dir='./results', ... verbose=True ... ) >>> ctape_result = finder.detect_Ctape() Detecting position of C tape C tape detected. >>> if ctape_result is not None: ... center_pos, sample_hw_mm = ctape_result ... print("C tape center (mm):", center_pos) ... print("C tape half-width (mm):", sample_hw_mm) ... else: ... print("C tape detection failed.")
Notes
The navigation camera image can be provided directly (for offline testing) or acquired live from the microscope.
For successful detection, the microscope calibration file must include the attributes: ‘navcam_im_w_mm’, ‘navcam_x_offset’, ‘navcam_y_offset’.
The detected center and half-width (radius) can be used to configure automated acquisition grids or for quality control.
- detect_Ctape(navcam_im: ndarray | None = None) Tuple[ndarray, float] | None[source]
Detects the effective center position and radius of the C tape using the navigation camera image.
Uses navcam_im if provided (e.g., when testing function), or acquires it directly at microscope via EM_driver.get_navigation_camera_image()
- Return type:
(center_pos, sample_hw_mm) if successful, else None.
- normalise_img(img: ndarray, target_brightness: float = 128.0) ndarray[source]
Normalize brightness of an RGB image to a target brightness level.
- Parameters:
img (np.ndarray) – Input RGB image (uint8).
target_brightness (float) – Desired average brightness (0–255).
- Returns:
Brightness-normalized RGB image (uint8).
- Return type:
np.ndarray