autoemxsp.core.EM_particle_finder module

Automated Electron Microscopy (EM) Particle Analysis Toolkit

This module provides the EM_Particle_Finder class for particle detection, selection of X-ray spectra (EDS, WDS) acquisition spots, and particle size/statistics analysis. It is designed to interface with an EM driver and an EM_Controller object to streamline the workflow from image acquisition to data export.

Currently only supports SEM.

Main Class

EM_Particle_Finder

Automates particle detection, mask generation, and X-ray spectra spot selection on detected particles. Supports both fully automated and manual (user-guided) collection modes. Provides methods for collecting particle statistics and managing frame navigation.

Example Usage

# 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)

Notes

  • Requires an initialised EM_Controller object, unless used in development mode

  • Requires a working EM_driver and appropriate hardware configuration, with the following API functions:
    • is_at_EM

      Boolean attribute; True if running at the actual electron microscope.

    • get_image_data(width, height, channel)

      Acquire an image from the microscope with specified dimensions and channels.

    • get_frame_width()

      Get the current field of view/frame width (in mm).

    • move_to(x, y)

      Move the microscope stage to the specified (x, y) position.

Created on Wed Jul 31 09:28:07 2024

@author: Andrea

class autoemxsp.core.EM_particle_finder.EM_Particle_Finder(EM_controller, powder_meas_cfg: PowderMeasurementConfig, is_manual_particle_selection: bool = False, results_dir: str | None = None, verbose: bool = True, development_mode: bool = True)[source]

Bases: object

Automated particle analysis and X-ray spectra (EDS, WDS) acquisition in an electron microscope (EM).

This class provides methods for particle detection, selection of X-ray spectra (EDS, WDS) acquisition spots, and particle size/statistics analysis. It is designed to interface with an EM driver and an EM_Controller object to streamline the workflow from image acquisition to data export.

Main Methods

initialise_SEM()

Wakes up the SEM microscope, sets measurement parameters, and evaluates locations to scan for particles.

go_to_next_particle()

Locates and moves to the next detected particle.

get_XS_acquisition_spots_coord_list()

Determines X-ray spectra (EDS, WDS) acquisition spots on the currently detected particle.

get_particle_stats()

Scans the full sample, collecting particle size distribution statistics.

Examples

# 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)

EM

Reference to the parent EM_Controller instance (must be initialised before use).

Type:

EM_Controller

powder_meas_cfg

Configuration object for powder measurement (see dataclass for details).

Type:

PowderMeasurementConfig

is_manual_particle_selection

If True, prompts user to center image around next particle to analyse.

Type:

bool

results_dir

Directory for saving result images and data.

Type:

str or None

verbose

If True, print progress and information to the console.

Type:

bool

development_mode

If True, enables extra visualizations and debug image saving.

Type:

bool

Internal Attributes
-------------------
_sample_ID

Identifier for the sample. Inherited from EM_Controller.

Type:

str

_im_width

Image width in pixels. Inherited from EM_Controller.

Type:

int

_im_height

Image height in pixels. Inherited from EM_Controller.

Type:

int

tot_par_cntr

Counter for the total number of particles analyzed.

Type:

int

analyzed_pars

List storing tuple containing Particle ID, Frame ID and particles areas (in μm²) of each detected particle. Used only when collecting particles size distribution statistics

Type:

list(tuple(int, str, float))

Notes

  • This class assumes that an EM_Controller object is already initialised and passed as EM_controller.

  • All configuration validation is performed in the respective dataclasses.

  • Attributes with a leading underscore are for internal use and should not be accessed directly by users.

go_to_next_particle()[source]

Moves the microscope to the next particle, centering and zooming on it. It also re-adjusts brightness, contrast and focus.

In automated mode, this function finds the next particle in the current frame. If all particles in the frame have been analyzed, it advances to the next frame and searches for particles there. It then moves the stage to center the next particle and zooms in. In manual mode, it prompts the user for input.

Returns:

True if it could successfully move to a particle. False if no more particles are present in the sample or if execution is stopped by the user.

Return type:

bool

is_particle_at_frame_edge(stats, i)[source]

Determines whether a particle is located at or near the edge of the image frame.

A margin is used to account for detection tolerances. If any part of the particle’s bounding box is within pixel_margin pixels of the image border, it is considered to be at the edge.

Parameters:
  • stats (ndarray) – Connected components statistics array (as returned by OpenCV), where each row corresponds to a detected particle and columns to bounding box info (LEFT, TOP, WIDTH, HEIGHT, etc.).

  • i (int) – Index of the particle in the stats array.

Returns:

True if the particle is at or near the edge of the image frame, False otherwise.

Return type:

bool

prepare_mask_for_visualization(mask: ndarray) ndarray[source]

Prepare a segmentation mask for visualization.

Behavior: - Binary masks with values in {0, 1} are scaled to [0, 255]. - Binary masks with values in {0, 255} are returned unchanged. - Integer label masks have brightness reversed so higher labels are brighter,

with a minimum brightness of 30 for positive values. Background (0) remains black.

  • Floating-point masks are normalized to [0, 255] with the same rules for positive values and background.

get_XS_acquisition_spots_coord_list(n_tot_sp_collected, par_image=None, pixel_size_um=None, results_dir=None)[source]

Returns a list of coordinates (relative, in the current image) for X-ray spectrum spot collection on a particle.

The function finds a suitable particle mask, erodes the mask to avoid particle edges, finds bright regions (or peak spots), and selects up to powder_meas_cfg.max_spectra_per_par spots per particle with a minimum distance between them (determined through ‘powder_meas_cfg.par_mask_margin’). The selection strategy for features and spacing can be controlled via powder_meas_cfg.par_feature_selection and powder_meas_cfg.par_spot_spacing.

Parameters:
  • n_tot_sp_collected (int) – Counter for the total number of spectra collected (used for labeling).

  • par_image (ndarray, optional) – Grayscale image of the current frame. If not provided and running at the SEM, the image is acquired.

  • pixel_size_um (float, optional) – Pixel size in micrometers. Required if not running at the SEM.

  • results_dir (str, optional) – Directory to save result images.

Returns:

  • pts_rel_coords (ndarray) – Array of selected (x, y) spot coordinates in relative units (centered at 0).

    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)
    +————————-+
    | |
    | |
    | +(0,0) |—–> +x
    | |
    | |
    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.

  • Potential Improvements

  • ———————

  • - Select points to ensure all phases are individuated, biasing spot selection to ensure representation – of phases with different bright/dark contrast. Currently, only the brightest spots are picked, which may miss some phases.

  • - Add detection of both peaks and valleys to ensure both bright and dark spots are tested.

  • - Exclude points that are close to larger particles along the X-ray emission path to the EDS detector, – as these may absorb emitted X-rays and degrade spectral signal.

get_particle_stats(n_par_target)[source]

Analyze frames to collect and save statistics on particle sizes until a desired number of particles is reached.

This function is to be used on its own after microscope initialization. It iteratively analyzes frames, detects particles, filters and records their areas, and continues until n_par_target particles have been analyzed or no more frames are available. It saves both individual particle data and summary statistics, and generates a histogram of the size distribution.

Parameters:

n_par_target (int) – The desired number of particles to analyze.

Returns:

  • par_size_distr_df (pandas.DataFrame) – A single-row DataFrame containing summary statistics of the analyzed particle size distribution. The columns include:

    • ’measurement’str

      Description of the measurement (e.g., ‘equivalent particle diameter in μm’).

    • ’n_par_analysed’int

      Number of particles analyzed.

    • ’mean’float

      Mean equivalent particle diameter (μm).

    • ’stdev’float

      Standard deviation of the equivalent particle diameter (μm).

    • ’median’float

      Median equivalent particle diameter (μm).

    • ’max’float

      Maximum equivalent particle diameter (μm).

    • ’min’float

      Minimum equivalent particle diameter (μm).

    • ’D10’float

      10th percentile of the equivalent particle diameter (μm).

    • ’D25’float

      25th percentile of the equivalent particle diameter (μm).

    • ’D75’float

      75th percentile of the equivalent particle diameter (μm).

    • ’D90’float

      90th percentile of the equivalent particle diameter (μm).

    This DataFrame is also saved as a CSV file in the results directory.

  • Side Effects

  • ————

    • Updates self.analyzed_pars with new particle areas (in μm²), and corresponding frame_label.

  • - Saves a CSV file with all particle areas and equivalent diameters.

  • - Saves a CSV file with summary statistics (mean, stdev, median, percentiles).

  • - Saves a histogram plot of the equivalent diameters as a PNG file.

    • Prints information and warnings to the console if self.verbose is True.

Notes

  • The function relies on _move_and_get_particles_stats_in_frame() to process each frame and find new particles.

  • If no particles are found or frames are exhausted, the function will print a warning and exit early.

  • Equivalent diameters are computed assuming each particle is a circle of the same area.

  • The function sorts particle areas to facilitate percentile calculations.

  • The function handles cases where particles are very small or indistinguishable in area.

Potential Improvements / TODO

  • Ideally the software should autonomously measure different particle sizes at different frame widths.

    At the moment, it requires a specific range to be selected, and filters out particles outside this range.

  • Particles at frame edges are currently ignored. Ideally, they should be included by centering the stage around them, and

    recording their area

  • Add robust error handling for file I/O and plotting.

  • Optionally return summary statistics as a dictionary or DataFrame for further programmatic use.

save_particle_statistics(output_file_suffix='')[source]

Process particle area data, compute summary statistics, export results, and produce a particle size histogram.

This method: 1. Extracts particle areas (μm²) and associated frame labels. 2. Optionally warns if two smallest particles have identical area (potential imaging resolution issue). 3. Calculates equivalent diameters assuming circular particles. 4. Saves raw particle data to CSV. 5. Computes descriptive statistics and saves them to CSV. 6. Generates and saves a histogram plot of particle sizes.

Parameters:

output_file_suffix (str, optional) – String added to output file name

Returns:

DataFrame containing the calculated particle size statistics.

Return type:

pandas.DataFrame