API Reference
On this page:
Image import
Import images using import_image, which is good-mannered enough to tell you if the import succeeded and to provide you an image even in case of failure, which can be practical.
- pypendentdrop.import_image(file_path: str | None = None) Tuple[bool, ndarray]
Imports an image in grayscale.
Tries to import the image at file_path. Returns True and the image in grayscale if the import succeeded. Returns False and a random 128 x 128 matrix with values 0-255 if the import failed.
- Parameters:
file_path (str) – The path to the file to open. Can be None.
- Returns:
success (bool) – Whether of not the image could be imported.
data (ndarray) – The image in grayscale.
Contour detection
The detection of a drop contour is made by
Selecting a threshold value for the luminosity (manually or using
auto_threshold), andFinding the main contour (the one of the drop) using
detect_main_contour.
- pypendentdrop.auto_threshold(image: ndarray, roi: List[int | None] | None = None) float
Finds the most appropriate threshold for the image.
Trying to find Otsu’s most appropriate threshold for the image, falling back to 127 it it fails.
- Parameters:
image (ndarray)
roi (Roi, optional)
- Returns:
threshold
- Return type:
float
- pypendentdrop.detect_main_contour(image: ndarray, level: float, roi: List[int | None] | None = None) ndarray
Returns the main (longest) closed line enclosing a region in
imagethat is abovelevel.Finds the longest of all contour lines <pypendentdrop.detect_contourlines> above a specific level, and returns its transposition, so that it is of shape (2, N).
- Parameters:
image (ndarray)
level (float)
roi (Roi, optional)
- Returns:
lines – An ndarray of shape (2, N).
- Return type:
ndarray
- pypendentdrop.detect_contourlines(image: ndarray, level: float, roi: List[int | None] | None = None) List[ndarray]
Returns all the closed lines enclosing regions in
imagethat are abovelevel.Returns a collection of lines that each a contour of the level
levelof the image. Each line is in line-form, i.e. shape=(N,2).- Parameters:
image (ndarray)
level (float)
roi (Roi, optional)
- Returns:
lines – A collection of ndarrays of shape (N, 2).
- Return type:
array_like
Parameters estimation
One has to provide a reasonable estimation of the parameters describing the drop (angle of gravity, tip position, apex radius of curvature, capillary length) as initial condition for the optimization to converge to a relevant minimum in the parameters space.
All the drops parameters are handled using a Parameter object. An automatic estimation of these parameters can be obtained by using estimate_parameters and later modified using the methods of the Parameters class.
- pypendentdrop.estimate_parameters(image: ndarray, contour: ndarray, px_per_mm) Parameters
Provides a coarse estimation of the parameters using (hopefully) robust techniques.
- Parameters:
image (ndarray) – The image of the drop
contour (ndarray) – The contour of the drop, with shape (2, N)
px_per_mm (float) – The pixel density of the image.
- Returns:
parameters – An estimation of the parameters describing the drop.
- Return type:
- class pypendentdrop.Parameters
The parameters describing a drop.
This class stores the parameters describing the drop in the image (gravity angle, tip position in px, radius of curvation in px, capillary length in px). It also stores physically relevant informations, such as the pixel-to-mm conversion constant, the acceleration of gravity, the density ratio between the two fluids.
It can return all these parameters and equivalent ondes (bond number, surface tension) in different units.
Use
describeto print the values of the parameters.This class has no public attributes, you should use the (numerous) getter and setter methods to manipulate the variables.
This class has str and repr methods #todo add exemples of what this means here.
- can_estimate() bool
Decides if an auto-estimation of the parameters is possible.
- can_optimize() bool
Decides if an optimization of the parameters is possible.
- describe(printfn=<built-in function print>, descriptor=None) None
Prints the parameters in the console in a human-friendly fashion.
- Parameters:
printfn (function) – The function that will be used to print. By default, print, but you can feed it a logging or debug function.
descriptor (str) – A short description of this parameter object (‘estimated’, ‘guessed’, ‘optimized’ …)
- get_angleofgravity_deg() float
Get the angle of gravity, in degrees. Use
set_angleofgravity_degto set it.
- get_angleofgravity_rad() float
Get the angle of gravity, in radians. Use
set_angleofgravity_radto set it.
- get_bond()
Returns the Bond number (square of the (tip radius)/(capillary length) ratio)
- get_caplength_mm() float
Get the capillary length, in millimeters. Use
set_caplength_mmto set it.
- get_caplength_px() float
Get the capillary length, in pixels. Use
set_caplength_pxto set it.
- get_densitycontrast()
Get the density contrast between the fluids, in kg/L (typically 1 for water/air). Use
set_densitycontrastto set it.
- get_fitparams() List[float]
Returns the parameters in a
scipy.minimize-friendly way.
- get_gravityacc()
Get the acceleration of gravity, in m/s^2 (typically 9.81). Use
set_gravityaccto set it.
- get_px_density() float
Get the density of pixels, in px/mm. Use
set_px_densityto set it.
- get_px_spacing() float
Get the spacing between pixels, in mm. Use
set_px_spacingto set it.
- get_surface_tension_mN()
Returns the surface tension in mN (or None if it cannot be computed).
- get_tipradius_mm() float
Get the radius of curvature at the tip, in millimeters. Use
set_tipradius_mmto set it.
- get_tipradius_px() float
Get the radius of curvature at the tip, in pixels. Use
set_tipradius_pxto set it.
- get_xytippos_px() Tuple[float, float]
Get the (x, y) position of the tip, in pixels. Use
set_xytippos_pxto set it.
- get_ytippos_px() float
Get the y position of the tip, in pixels. Use
set_xytippos_pxto set it.
Parameters optimization
Using optimize_profile, one can find the parameters that fits best a given detected contour (in pixel coordinates). The contour is numerically integrated using compute_nondimensional_profile, and compared with the detected profile using compute_gap_dimensionless. The parameters are then varied to minimize the dimensionless total area of the gap between the two. This area between them can be computed in real-world units (squared pixels) using compute_gap_pixel. In order to plot the theoretical profile, integrated_contour allows one to obtain the contour integrated from the equations in pixel coordinates.
- pypendentdrop.compute_nondimensional_profile(tipRadius: float, ds: float = 0.001, approxLimit: float = 0.2, zMax: float | None = None) Tuple[ndarray, ndarray]
Computes the nondimensional profile, starting at the bottom and up to an height zMax.
About the default value of ds: The length in px of the contour is L. We want around 2 points per pixel, and the length of the dimensionless drop will be s = L / (px_per_mm * capillarylength_in_mm). Thus taking a typical 100 px/mm (microscopic resolution is 1000) and a capillary length of 2.5, we have ds = s / (2 * L) = 1 / (2 * 100 * 2.5) = 2e-3 To be safe, we take ds = 1e-3 by default. If using high resolution camera + excellent optics + optimal conditions, one might want it smaller.
About the solver : We use LSODA form LAPACK (scipy.integrate’s odeint). Good ol’ Fortran never dissapoints.
- Parameters:
tipRadius (float, optional) – The dimensionless tip radius r_0/l_c (square root of the Bond number).
ds (float, optional) – The dimensionless integration step. The default value (1e-3) should be enough for most applications.
approxLimit (float, optional) – The fraction of capillary length or tip radius (whichever is smaller) up to which we use the approximate solution. todo: compute the difference between “true” profile (approxLimit = 1e-3) and the others to see what is the maximum reasonable approxlimit.
zMax (float, optional) – The maximum height of the drop [useless]
- Returns:
R, Z – The right (R > 0) half of the dimensionless profile of the drop.
- Return type:
Tuple[ndarray]
- pypendentdrop.compute_gap_dimensionless(contour: ndarray, parameters: Parameters) float
The dimensionless area between the detected contour and the computed profile.
- Parameters:
contour (ndarray) – The pixel coordinates of the detected contour to be compared with the computed profile, shape=(2, N)
parameters (Parameters) – The parameters to compute the theoretical profile.
- Returns:
gap_dimensionless
- Return type:
float
- pypendentdrop.compute_gap_pixel(contour: ndarray, parameters: Parameters) float
The area between the detected contour and the computed profile, in squared pixels.
- Parameters:
contour (ndarray) – The pixel coordinates of the detected contour to be compared with the computed profile, shape=(2, N)
parameters (Parameters) – The parameters to compute the theoretical profile.
- Returns:
gap_in_squared_px
- Return type:
float
- pypendentdrop.optimize_profile(contour: ndarray, parameters_initialguess: Parameters, to_fit: List[bool] | None = None, maxiter: int | None = None, method: str | None = None) Tuple[bool, Parameters]
Computes the optimized parameters for the given
contour.Minimises the
dimensionless gapbetween the contour and the computed profile, using scipy’sminimize.- Parameters:
contour (ndarray) – The pixel coordinates of the detected contour to be compared with the computed profile, shape=(2, N)
parameters_initialguess (Parameters) – The initial guess of the parameters
to_fit (Tuple[bool, bool, bool, bool, bool], optional) – Whether of not to fit the parameters todo: better document this (SEE EXAMPLES)
maxiter (int, optional) – The maximum number of iterations. Depends on the method !
method (str, optional) – The method passed to
minimize. Must be a bound-constrained method. Nelder-Mead works quite well.
- pypendentdrop.integrated_contour(parameters: Parameters) ndarray
The computed profile in pixel coordinates.
- Parameters:
parameters (Parameters)
- Returns:
contour – The computed profile in pixel coordinates (shape 2, N).
- Return type:
Tuple[ndarray, ndarray]
Plotting
TODO