Analysis (pylorenzmie.analysis)#
Hologram#
Normalized hologram image with pixel coordinates.
- class pylorenzmie.analysis.Hologram.Hologram(data, corner=(0.0, 0.0))[source]#
Bases:
objectNormalized hologram paired with pixel coordinates.
- Parameters:
data (numpy.ndarray) – Normalized hologram, shape
(ny, nx). Pixel values should be floating-point intensities normalized so the background level is approximately 1 (i.e.I(r) / I_0(r)).corner (tuple[float, float], optional) –
(left, top)pixel coordinates of the top-left corner of this image within the full camera frame. Default:(0., 0.).
Notes
Pixel coordinates are generated automatically from
data.shapeandcornerviameshgrid()and stored as a(2, ny, nx)array. Two flat views are provided for use by scattering models and numerical solvers:flat_data—data.ravel(), shape(npts,)flat_coordinates—coordinates.reshape(2, -1), shape(2, npts)
Both are numpy views (no copy, O(1)).
Coordinate-aware cropping:
crop = hologram[y0:y1, x0:x1]
returns a new
Hologramwhosecorneris updated so that its coordinates are consistent with those of the parent frame.
Mask#
- class pylorenzmie.analysis.Mask.Mask(shape=None, fraction=0.1, exclude=None)[source]#
Bases:
LMObjectPixel selection mask for subsampling a hologram during fitting.
Randomly selects a fraction of pixels for analysis, with optional exclusion of saturated, NaN, or infinite pixels. Regenerates automatically whenever
shape,fraction, orexcludeis changed.Inherits from
pylorenzmie.lib.LMObject.- Parameters:
shape (tuple[int, int], optional) –
(height, width)of the image. Default:None.fraction (float, optional) – Fraction of pixels to include. Default: 0.1.
exclude (numpy.ndarray of bool, optional) – Boolean array of pixels to force-exclude. Default:
None.
Notes
Call
update()to resample the mask without changing any parameter. Subclasses may override_select()to implement non-uniform sampling strategies.References
T. G. Dimiduk, R. W. Perry, J. Fung and V. N. Manoharan, “Random-subset fitting of digital holograms for fast three-dimensional particle tracking,” Applied Optics 53, G177–G183 (2014).
- property properties: dict[str, bool | int | float | str]#
fraction of pixels to sample.
- Type:
Mask configuration
- apply(hologram)[source]#
Apply mask to a hologram, returning flat data and coordinates.
This is the explicit 2D-to-flat boundary for numerical solvers.
- Parameters:
hologram (Hologram) – Normalized hologram to subsample.
- Return type:
tuple[GenericAlias[float] |GenericAlias[int],GenericAlias[float]]- Returns:
data (numpy.ndarray) – Selected pixel values, shape
(nselected,).coordinates (numpy.ndarray) – Selected pixel coordinates, shape
(2, nselected).
Notes
Each call draws a fresh random subsample from
hologram.shape.
RadialMask#
- class pylorenzmie.analysis.RadialMask.RadialMask(shape=None, fraction=0.1, exclude=None)[source]#
Bases:
MaskPixel selection mask with radially-weighted sampling probability.
Overrides
Mask._select()to sample pixels with a probability that varies with radial distance from the image center.When
fraction < 0.5the image center has probability zero of being selected; probability increases toward the edges, emphasizing the outer ring fringes of a holographic pattern. Whenfraction >= 0.5all pixels have a nonzero selection probability; the distribution becomes more uniform asfraction→ 1.Inherits all parameters from
Mask.
Localizer#
- class pylorenzmie.analysis.Localizer.Localizer(diameter=31, nfringes=20)[source]#
Bases:
LMObjectDetect and localize holographic features in a normalized image.
Uses
CircleTransformto enhance ring-like patterns, then callstrackpy.locate()to find feature centers. Bounding boxes are sized to enclose a specified number of fringes.Inherits from
pylorenzmie.lib.LMObject.- Parameters:
diameter (int, optional) – Nominal feature diameter passed to
trackpy.locate[pixels]. Default: 31.nfringes (int, optional) – Number of interference fringes to enclose in each bounding box. Default: 20.
- property properties: dict[str, bool | int | float | str]#
nfringes and diameter.
- Type:
Localization parameters
- localize(image, diameter=None, nfringes=None, **kwargs)[source]#
Localize features in a normalized holographic microscopy image.
- Parameters:
image (numpy.ndarray or list of numpy.ndarray) – Normalized hologram intensity.
diameter (int, optional) – Override
diameterfor this call.nfringes (int, optional) – Override
nfringesfor this call.**kwargs – Additional keyword arguments passed to
trackpy.locate.
- Return type:
- Returns:
predictions (pandas.DataFrame) – Columns:
x_p,y_p,bbox.bboxis((x0, y0), width, height).
- detect(image, diameter=None, nfringes=None, **kwargs)#
Localize features in a normalized holographic microscopy image.
- Parameters:
image (numpy.ndarray or list of numpy.ndarray) – Normalized hologram intensity.
diameter (int, optional) – Override
diameterfor this call.nfringes (int, optional) – Override
nfringesfor this call.**kwargs – Additional keyword arguments passed to
trackpy.locate.
- Return type:
- Returns:
predictions (pandas.DataFrame) – Columns:
x_p,y_p,bbox.bboxis((x0, y0), width, height).
BaseEstimator#
Abstract base class for hologram parameter estimators.
- class pylorenzmie.analysis.BaseEstimator.BaseEstimator[source]#
Bases:
LMObjectAbstract base for particle parameter estimators.
Subclasses must implement
estimate()and thepropertiesgetter inherited fromLMObject.See also
Estimatorconventional azimuthal-profile estimator.
DEEstimatorglobal differential-evolution estimator.
Estimator#
- class pylorenzmie.analysis.Estimator.Estimator(instrument, n_p=1.5, k_p=0.0)[source]#
Bases:
BaseEstimatorEstimate initial parameters of a holographic feature.
Uses the azimuthal average of a cropped hologram to estimate the axial position and radius of the scattering particle, providing initial values for
Optimizer.Inherits from
BaseEstimator.- Parameters:
instrument (Instrument) – Optical parameters of the microscope.
n_p (float, optional) – Particle refractive index. Default: 1.5. Cannot be estimated from the azimuthal profile; serves as an initial value for the optimizer.
k_p (float, optional) – Imaginary part of the refractive index. Default: 0.
Notes
Call
estimate()to populate all particle parameters. Results are available viapropertiesafterwards.predict()is a backward-compatibility alias forestimate().This class provides a lightweight conventional-algorithm baseline. For higher-quality initial estimates — including
n_p— use the CATCH deep neural network model [1] [2].References
- instrument: Instrument#
DEEstimator#
- class pylorenzmie.analysis.DEEstimator.DEEstimator(model, bounds=<factory>, fraction=0.02, exclude=None, popsize=10, seed=None, settings=<factory>)[source]#
Bases:
BaseEstimatorEstimate initial particle parameters by global search.
Uses differential evolution (DE) to minimize the sum-squared residual between the forward model and a subsampled hologram crop, providing robust initial values for
Optimizereven when the conventionalEstimatorfails to converge.Inherits from
BaseEstimator.- Parameters:
model (LorenzMie) – Generative scattering model shared with
Optimizer. The particle parameters on this model are updated in-place.bounds (dict, optional) – Mapping of parameter name to
(min, max)search range. Default:z_p(10, 600) pixels,a_p(0.25, 10.0) μm,n_p(1.0, 3.0).fraction (float, optional) – Fraction of pixels used for the DE objective function. Default: 0.02. A fixed random subsample is drawn once per call and held constant throughout the search so the objective is deterministic.
exclude (numpy.ndarray of bool, optional) – Boolean mask of pixels to force-exclude from sampling (e.g. saturated or dead pixels). Default:
None(no exclusions). Set viamaskwhen usingFeature.popsize (int, optional) – DE population size multiplier (population = popsize × len(bounds)). Default: 10.
seed (int or None, optional) – Random seed passed to
scipy.optimize.differential_evolution()for reproducibility. Default:None.
Notes
x_pandy_pare pinned to the pixel-coordinate means before the search begins; only the parameters listed inboundsare varied.For large particles (
a_p≳ 1 μm) the hologram fringe pattern is dense and the coarsely-sampled objective function becomes multi-modal. In that regime increasefraction(e.g. 0.05) andpopsize(e.g. 15) at the cost of longer run time, or supply tighterboundsto reduce the search volume.The model coordinates are temporarily overridden during the search and restored on exit, even if an exception occurs.
By default
settings['workers'] = -1distributes candidate evaluations across all CPU cores viamultiprocessing. On Linux (forkstart method) the speedup is near-linear with core count at negligible overhead. On macOS (spawnstart method) eachestimate()call pays a process-pool startup cost; on machines with many cores this is still a net win (~2× on a 10-core Mac). Setworkers=1to disable parallelism, e.g. when usingcupyLorenzMie(which holds GPU memory and is not picklable). The companion settingupdating='deferred'(also the default) is required forworkers != 1and suppresses a SciPy warning.Use
Estimatorfor a fast conventional estimate when the fringe pattern is clean. UseDEEstimatorwhen the conventional estimator produces starting points too far from the true solution forOptimizerto converge.- model: jaxLorenzMie#
RadialEstimator#
Global parameter estimator using the azimuthal radial profile.
- class pylorenzmie.analysis.RadialEstimator.RadialEstimator(model, bounds=<factory>, popsize=10, seed=None, settings=<factory>)[source]#
Bases:
BaseEstimatorEstimate particle parameters by global search on the azimuthal profile.
Computes the azimuthal average of the hologram once, then uses differential evolution (DE) to find the parameter set that minimises the residual between a 1-D radial model evaluation and that profile.
Because a sphere’s hologram is rotationally symmetric, the full 2-D pixel comparison in
DEEstimatorcan be reduced to a 1-D radial comparison with no loss of information about z_p, a_p, or n_p. This makes each DE objective evaluation roughly an order of magnitude cheaper thanDEEstimatorwhile retaining the robustness of global search and adding n_p estimation thatEstimatorcannot provide.Inherits from
BaseEstimator.- Parameters:
model (LorenzMie) – Generative scattering model shared with
Optimizer. The particle parameters on this model are updated in-place.bounds (dict, optional) – Mapping of parameter name to
(min, max)search range. Default:z_p(10, 600) pixels,a_p(0.25, 10.0) μm,n_p(1.0, 3.0).popsize (int, optional) – DE population size multiplier (population = popsize × len(bounds)). Default: 10.
seed (int or None, optional) – Random seed for
scipy.optimize.differential_evolution(). Default:None.
Notes
x_pandy_pare pinned to the pixel-coordinate means before the search begins; only the parameters listed inboundsare varied.The model coordinates are temporarily replaced by a 1-D radial spoke
(x_p + r, y_p)forr = 0, 1, …, n_radii - 1and restored on exit, even if an exception occurs.This estimator assumes the hologram is rotationally symmetric about the particle position, which holds for spherical particles. For non-spherical scatterers use
DEEstimatorinstead.The default
settings['workers'] = 1is appropriate here because each objective evaluation is inexpensive (~100 model points vs ~1000–2000 forDEEstimator). Setworkers=-1to distribute over all cores if you are running very large population sizes or tight tolerances.Use
Estimatorfor a fast conventional estimate when the fringe pattern is clean and n_p is known. Use this class when you need a robust estimate of n_p as well as z_p and a_p. UseDEEstimatorfor non-spherical particles or when rotational symmetry cannot be assumed.- model: jaxLorenzMie#
MLPEstimator#
Fast parameter estimator using a pre-trained radial-profile MLP.
- class pylorenzmie.analysis.MLPEstimator.MLPEstimator(model, weights=<factory>, n_features=100)[source]#
Bases:
BaseEstimatorFast particle parameter estimator using a pre-trained MLP.
Computes the azimuthal average of the hologram, pads or truncates it to a fixed length, and runs a single forward pass through a scikit-learn
MLPRegressorto predict z_p, a_p, and n_p in one shot. Inference takes < 1 ms regardless of image size.The MLP was trained on synthetic radial profiles generated by the 1-D radial trick:
LorenzMieevaluated at(r, 0)forr = 0 .. n_features-1, which equals the azimuthal average for a rotationally symmetric scatterer. Parameters are drawn log-uniformly over z_p ∈ [20, 500] px, a_p ∈ [0.2, 4] μm and uniformly over n_p ∈ [1.3, 2.5]. Each profile is randomly truncated during training so the network handles both large and small crops gracefully. Pre-trained weights cover the default instrument (447 nm laser, 0.048 μm/px, water). Retrain withdevel/train_mlp_estimator.pyfor other configurations.Inherits from
BaseEstimator.- Parameters:
model (LorenzMie) – Generative scattering model shared with
Optimizer. Particle parameters are updated in-place on eachestimate()call; instrument parameters are read but not modified.weights (Path or str, optional) – Path to a
joblib-serialized scikit-learnPipeline(StandardScaler→TransformedTargetRegressor(MLPRegressor)). Default: the pre-trained weights bundled with the package.n_features (int, optional) – Fixed input length passed to the MLP. Must match the value used during training. Default: 100.
Notes
x_pandy_pare pinned to the pixel-coordinate means of the hologram (same convention asDEEstimatorandRadialEstimator).The profile from
avg()is truncated to the first n_features values. Positions beyond the profile end are padded with0.0— a sentinel that is clearly outside the normalised hologram range (which is positive and O(1)). The training data uses the same sentinel after random truncation, so the network has seen this pattern and uses the zero tail to infer crop size.Predicted values are clipped to the training bounds before being written to the model; the
Optimizerwill refine them further.- model: jaxLorenzMie#
Optimizer#
- class pylorenzmie.analysis.Optimizer.Optimizer(model=None, mask=None, robust=False, fixed=None, settings=None, **kwargs)[source]#
Bases:
LMObjectFit a generative light-scattering model to holographic data.
Wraps
scipy.optimize.least_squares(). Themethodclass attribute must appear as a substring of the model’smethodstring for the pairing to be valid (e.g.'numpy'matches both'numpy'and'cupy numpy').- Parameters:
model (LorenzMie, optional) – Generative scattering model. Default:
LorenzMie().mask (Mask or None, optional) – Pixel-selection mask applied to the hologram before fitting.
None(default) uses all pixels viaflat_dataandflat_coordinates.robust (bool, optional) – Use robust Cauchy loss instead of standard least squares. Default:
False.fixed (list[str], optional) – Names of model properties held constant during fitting. Default: all instrument parameters plus
k_p(wavelength,magnification,numerical_aperture,n_m,noise,k_p), leaving only the five particle parameters (x_p,y_p,z_p,a_p,n_p) free.settings (dict, optional) – Keyword arguments forwarded to
scipy.optimize.least_squares. Defaults to sensible values for holographic particle fitting.**kwargs – Forwarded to
LorenzMie()whenmodelis not supplied.
- result#
Fitted values and uncertainties after
optimize()has run;Nonebefore the first call.- Type:
pandas.Series or None
- metadata#
Fixed model properties and optimizer settings.
- Type:
- property properties: dict[str, bool | int | float | str]#
settings and fixed parameter list.
- Type:
Optimizer configuration
- property settings: dict[str, bool | int | float | str]#
Settings forwarded to
scipy.optimize.least_squares.Notes
method:'lm'(Levenberg-Marquardt, default),'trf', or'dogbox'. Only'lm'supportsloss='linear'.loss:'linear'(standard LS),'cauchy','huber','soft_l1', or'arctan'.x_scale:'jac'for dynamic rescaling, or an explicit array of scales matched to the free parameters.
- property fraction: float#
Fraction of pixels used for fitting.
Setting this creates a
Maskif one does not exist.1.0(all pixels) when no mask is set.
- property result: Series | None#
Fitted values, uncertainties, and statistics.
Returns
Nonebeforeoptimize()has been called. Each fitted parameterpappears alongsided``+``p(its uncertainty). Also includessuccess,npix, andredchi.
cupyOptimizer#
- class pylorenzmie.analysis.cupyOptimizer.cupyOptimizer(*args, double_precision=True, **kwargs)[source]#
Bases:
OptimizerGPU-accelerated optimizer using CuPy.
Subclass of
Optimizerthat keeps hologram computation and residual evaluation on the GPU. Only the final residual vector is transferred to the CPU for scipy’s Levenberg-Marquardt solver.Inherits from
Optimizer.- Parameters:
double_precision (bool, optional) – If True (default), use double-precision arithmetic on the GPU.
*args, **kwargs – Passed to
Optimizer.
Notes
The
methodattribute is'cupy', which is a substring ofcupyLorenzMie.method = 'cupy numpy', satisfying the optimizer compatibility check.- property data#
Feature#
- class pylorenzmie.analysis.Feature.Feature(hologram, model=None, fixed=None)[source]#
Bases:
HologramA holographic feature associated with a single particle.
A Feature is a Hologram of a single particle augmented with an estimator and optimizer for localizing and characterizing the particle.
- Parameters:
hologram (Hologram) – Normalized hologram crop with pixel coordinates.
model (LorenzMie, optional) – Generative scattering model. Default:
LorenzMie().fixed (list[str], optional) – Model properties held constant during fitting. Default: the Optimizer default.
- property mask: Mask#
Shared pixel exclusion mask for estimator and optimizer.
Bad pixels (saturated, dead) set via
excludeare excluded from both the DE estimation and the LM optimization. Each component controls its own pixel fraction independently.
- property model: jaxLorenzMie#
Generative scattering model.
- estimate()[source]#
Estimate initial particle parameters from the hologram crop.
- Return type:
- Returns:
properties (pandas.Series) – Estimated particle properties.
- optimize()[source]#
Optimize particle parameters to fit the hologram crop.
- Return type:
- Returns:
result (pandas.Series) – Fitted values, uncertainties, and goodness-of-fit statistics.
Notes
When a mask with
fraction < 1.0is set, a fresh random pixel subsample is drawn on every call.
Frame#
- class pylorenzmie.analysis.Frame.Frame(data=None, corner=(0.0, 0.0), instrument=None, localizer=None)[source]#
Bases:
HologramFull-frame holographic microscopy analysis pipeline.
A Frame is a Hologram of the full camera field, augmented with a
Localizerand a sharedInstrument. Slicing a Frame returns aFeaturewith the correct corner coordinates and instrument already attached.- Parameters:
data (numpy.ndarray, optional) – Normalized hologram. Setting data clears previous results. Default:
None.corner (tuple[float, float], optional) – Top-left corner of this image within the full camera frame. Default:
(0., 0.).instrument (Instrument, optional) – Microscope parameters shared by all features. Default:
Instrument().localizer (Localizer, optional) – Feature detection backend. Default:
Localizer().
- results#
Optimized parameters from the most recent
optimize()oranalyze()call.- Type:
- property results: Series | DataFrame | list[Series | DataFrame]#
Optimized parameters from the most recent fit.
- detect()[source]#
Detect and localize features in
data.- Return type:
- Returns:
nfeatures (int) – Number of features found.
Trajectory#
- class pylorenzmie.analysis.Trajectory.Trajectory[source]#
Bases:
LMObjectAccumulate per-frame characterization results over time.
Each call to
append()stores one frame’s worth ofFrameoutput.datareturns the combined time series as a singlepandas.DataFrame.Inherits from
pylorenzmie.lib.LMObject.- property properties: dict[str, bool | int | float | str]#
Adjustable parameters of this object.
Returns a flat
dictmapping parameter names to their current values. Only parameters included here are visible to the serialization methods and toOptimizerduring fitting.Subclasses must override the getter using:
@ParentClass.properties.getter def properties(self) -> Properties: props = super().properties props.update(...) return props
The base-class getter returns an empty dict; the base-class setter iterates over the supplied dict and calls
setattrfor every key that already exists as an attribute. Unknown keys are silently ignored and logged at DEBUG level.
- append(results)[source]#
Append one frame of results.
- Parameters:
results (pandas.DataFrame or pandas.Series) – Output from
Frame.optimize()orFrame.analyze().- Return type: