Function Reference¶
Binarization¶
This module contains functions for thresholding greyscale images into binary images (i.e. True and False) indicating the phases.
-
porespy.binarization.simple_otsu(im, trim_solid=True)[source]¶ Uses Otsu’s method to find a threshold, then uses binary opening and closing to remove noise.
Parameters: im : ND-image
The greyscale image of the porous medium to be binarized.
trim_solid : Boolean
If True (default) then all solid voxels not connected to an image boundary are trimmed.
Returns: An ND-image the same size as
imbut with True and False valuesindicating the binarized or segmented phases.
Examples
>>> im = ps.generators.blobs([300, 300], porosity=0.5) >>> im = ps.generators.add_noise(im) >>> im = spim.gaussian_filter(im, sigma=1) >>> im = simple_otsu(im)
Filters¶
This module contains a variety of functions for altering image based on the structural characteristics, such as pore sizes.
-
porespy.filters.apply_chords(im, spacing=0, axis=0, trim_edges=True)[source]¶ Adds chords to the void space in the specified direction. The chords are separated by 1 voxel plus the provided spacing.
Parameters: im : ND-array
An image of the porous material with void marked as True.
spacing : int (default = 0)
Chords are automatically separated by 1 voxel and this argument increases the separation.
axis : int (default = 0)
The axis along which the chords are drawn.
trim_edges : bool (default = True)
Whether or not to remove chords that touch the edges of the image. These chords are artifically shortened, so skew the chord length distribution
Returns: An ND-array of the same size as
`im`with True values indicating thechords.
See also
-
porespy.filters.apply_chords_3D(im, spacing=0, trim_edges=True)[source]¶ Adds chords to the void space in all three principle directions. The chords are seprated by 1 voxel plus the provided spacing. Chords in the X, Y and Z directions are labelled 1, 2 and 3 resepctively.
Parameters: im : ND-array
A 3D image of the porous material with void space marked as True.
spacing : int (default = 0)
Chords are automatically separed by 1 voxel on all sides, and this argument increases the separation.
trim_edges : bool (default = True)
Whether or not to remove chords that touch the edges of the image. These chords are artifically shortened, so skew the chord length distribution
Returns: An ND-array of the same size as
`im`with values of 1 indicatingx-direction chords, 2 indicating y-direction chords, and 3 indicating
z-direction chords.
See also
Notes
The chords are separated by a spacing of at least 1 voxel so that tools that search for connected components, such as
scipy.ndimage.labelcan detect individual chords.
-
porespy.filters.local_thickness(im)[source]¶ For each voxel, this functions calculates the radius of the largest sphere that both engulfs the voxel and fits entirely within the foreground. This is not the same as a simple distance transform, which finds the largest sphere that could be centered on each voxel.
Parameters: im : array_like
A binary image with the phase of interest set to True
Returns: An image with the pore size values in each voxel
Notes
The term foreground is used since this function can be applied to both pore space or the solid, whichever is set to True.
-
porespy.filters.fill_blind_pores(im)[source]¶ Fills all pores that are not connected to the edges of the image.
Parameters: im : ND-array
The image of the porous material
Returns: A version of
imbut with all the disconnected pores removed.See also
-
porespy.filters.find_disconnected_voxels(im, conn=None)[source]¶ This identifies all pore (or solid) voxels that are not connected to the edge of the image. This can be used to find blind pores, or remove artifacts such as solid phase voxels that are floating in space.
Parameters: im : ND-image
A Boolean image, with True values indicating the phase for which disconnected voxels are sought.
conn : int
For 2D the options are 4 and 8 for square and diagonal neighbors, while for the 3D the options are 6 and 26, similarily for square and diagonal neighbors. The default is max
Returns: An ND-image the same size as
im, with True values indicating voxels ofthe phase of interest (i.e. True values in the original image) that are
not connected to the outer edges.
Notes
The returned array (e.g.
holes) be used to trim blind pores fromimusing:im[holes] = False
-
porespy.filters.flood()[source]¶ Floods/fills each region in an image with a single value based on the specific values in that region. The
modeargument is used to determine how the value is calculated. A region is defined as a connected cluster of voxels surrounded by 0’s for False’s.Parameters: im : array_like
An ND image with isolated regions containing 0’s elsewhere.
mode : string
Specifies how to determine which value should be used to flood each region. Options are:
*’max’* : Floods each region with the local maximum in that region
*’min’* : Floods each region the local minimum in that region
*’size’* : Floods each region with the size of that region
Returns: An ND-array the same size as
imwith new values placed in eachforground voxel based on the
mode.
-
porespy.filters.local_thickness(im)[source] For each voxel, this functions calculates the radius of the largest sphere that both engulfs the voxel and fits entirely within the foreground. This is not the same as a simple distance transform, which finds the largest sphere that could be centered on each voxel.
Parameters: im : array_like
A binary image with the phase of interest set to True
Returns: An image with the pore size values in each voxel
Notes
The term foreground is used since this function can be applied to both pore space or the solid, whichever is set to True.
-
porespy.filters.porosimetry(im, npts=25, sizes=None, inlets=None, access_limited=True)[source]¶ Performs a porosimetry simulution on the image
Parameters: im : ND-array
An ND image of the porous material containing True values in the pore space.
npts : scalar
The number of invasion points to simulate. Points will be generated spanning the range of sizes in the distance transform. The default is 25 points.
sizes : array_like
The sizes to invade. Use this argument instead of
nptsfor more control of the range and spacing of points.inlets : ND-array, boolean
A boolean mask with True values indicating where the invasion enters the image. By default all faces are considered inlets, akin to a mercury porosimetry experiment. Users can also apply solid boundaries to their image externally before passing it in, allowing for complex inlets like circular openings, etc.
access_limited : Boolean
This flag indicates if the intrusion should only occur from the surfaces (
access_limitedis True, which is the default), or if the invading phase should be allowed to appear in the core of the image. The former simulates experimental tools like mercury intrusion porosimetry, while the latter is useful for comparison to gauge the extent of shielding effects in the sample.Returns: An ND-image with voxel values indicating the sphere radius at which it
becomes accessible from the inlets. This image can be used to find
invading fluid configurations as a function of applied capillary pressure
by applying a boolean comparison:
inv_phase = im > rwhereristhe radius (in voxels) of the invading sphere. Of course,
rcan beconverted to capillary pressure using your favorite model.
-
porespy.filters.trim_extrema(im, h, mode='maxima')[source]¶ This trims local extrema in greyscale values by a specified amount, essentially decapitating peaks or flooding valleys, or both.
Parameters: im : ND-array
The image whose extrema are to be removed
h : scalar
The height to remove from each peak or fill in each valley
mode : string {‘maxima’ | ‘minima’ | ‘extrema’}
Specifies whether to remove maxima or minima or both
Returns: A copy of the input image with all the peaks and/or valleys removed.
Notes
This function is referred to as imhmax or imhmin in Mablab.
Generators¶
This module contains a variety of functions for generating artificial images of porous materials, generally for testing, validation, debugging, and illustration purposes.
-
porespy.generators.add_noise(im, u_void=0.8, u_solid=0.2, s_void=0.15, s_solid=0.15)[source]¶ Add some normally distributed noise values to the image. This is useful for testing binarization routines.
Parameters: im : ND-array
The image of the porous media, with 1’s or True’s denoting voids
u_solid : float
The mean greyscale value in the solid space (default is 0.2)
s_solid : float
The standard deviation of the greyscale values in the solid phase (the default is 0.15)
u_void: float
The mean greyscale value in the void space (default is 0.8)
s_void: float
The standard deviation of the greyscale values in the void phase (the default is 0.15)
Returns: A greyscale image with the same shape as
im, but normally distributednoise values in the void and solid phase. A histogram of the default image
should reveal to distinguishable but overlapping peaks. This can be
adjusted using the mean and standard deviation arguments.
-
porespy.generators.blobs(shape, porosity=0.5, blobiness=1)[source]¶ Generates an image containing amorphous blobs
Parameters: shape : list
The size of the image to generate in [Nx, Ny, Nz] where N is the number of voxels
porosity : float
If specified, this will threshold the image to the specified value prior to returning. If no value is given (the default), then the scalar noise field is returned.
blobiness : array_like (default = 1)
Controls the morphology of the blobs. A higher number results in a larger number of small blobs. If a vector is supplied then the blobs are anisotropic.
Returns: If porosity is given, then a boolean array with
Truevalues denotingthe pore space is returned. If not, then normally distributed and
spatially correlated randomly noise is returned.
See also
-
porespy.generators.bundle_of_tubes(shape, spacing)[source]¶ Create a 3D image of a bundle of tubes, in the form of a rectangular plate with randomly sized holes through it.
Parameters: shape : list
The size the image, with the 3rd dimension indicating the plate thickness. If the 3rd dimension is not given then a thickness of 1 voxel is assumed.
spacing : scalar
The center to center distance of the holes. The hole sizes will be randomly distributed between this values down to 3 voxels.
Returns: A boolean array with True values denoting the pore space
-
porespy.generators.circle_pack(shape, radius, offset=0, packing='square')[source]¶ Generates a 2D packing of circles
Parameters: shape : list
The size of the image to generate in [Nx, Ny] where N is the number of voxels in each direction
radius : scalar
The radius of circles in the packing (in pixels)
offset : scalar
The amount offset (+ or -) to add between pore centers (in pixels).
packing : string
Specifies the type of cubic packing to create. Options are ‘square’ (default) and ‘triangular’.
Returns: A boolean array with True values denoting the pore space
-
porespy.generators.cylinders(shape, radius, nfibers, phi_max=0, theta_max=90)[source]¶ Generates a binary image of overlapping cylinders. This is a good approximation of a fibrous mat.
Parameters: phi_max : scalar
A value between 0 and 90 that controls the amount that the fibers lie out of the XY plane, with 0 meaning all fibers lie in the XY plane, and 90 meaning that fibers are randomly oriented out of the plane by as much as +/- 90 degrees.
theta_max : scalar
A value between 0 and 90 that controls the amount rotation in the XY plane, with 0 meaning all fibers point in the X-direction, and 90 meaning they are randomly rotated about the Z axis by as much as +/- 90 degrees.
Returns: A boolean array with True values denoting the pore space
-
porespy.generators.line_segment(X0, X1)[source]¶ Calculate the voxel coordinates of a straight line between the two given end points
Parameters: X0 and X1 : array_like
The [x, y, z] coordinates of the start and end points of the line.
Returns: A list of lists containing the X, Y, and Z coordinates of all voxels
that should be drawn between the start and end points to create a solid line.
-
porespy.generators.noise(shape, porosity=None, octaves=3, frequency=32, mode='simplex')[source]¶ Generate a field of spatially correlated random noise using the Perlin noise algorithm, or the updated Simplex noise algorithm.
Parameters: shape : array_like
The size of the image to generate in [Nx, Ny, Nz] where N is the number of voxels.
porosity : float
If specified, this will threshold the image to the specified value prior to returning. If no value is given (the default), then the scalar noise field is returned.
octaves : int
Controls the texture of the noise, with higher octaves giving more complex features over larger length scales.
frequency : array_like
Controls the relative sizes of the features, with higher frequencies giving larger features. A scalar value will apply the same frequency in all directions, given an isotropic field; a vector value will apply the specified values along each axis to create anisotropy.
mode : string
Which noise algorithm to use, either ‘simplex’ (default) or ‘perlin’.
Returns: If porosity is given, then a boolean array with
Truevalues denotingthe pore space is returned. If not, then normally distributed and
spatially correlated randomly noise is returned.
See also
Notes
This method depends the a package called ‘noise’ which must be compiled. It is included in the Anaconda distribution, or a platform specific binary can be downloaded.
-
porespy.generators.norm_to_uniform(im, scale=None)[source]¶ Take an image with normally distributed greyscale values and converts it to a uniform (i.e. flat) distribution. It’s also possible to specify the lower and upper limits of the uniform distribution.
Parameters: im : ND-image
The image containing the normally distributed scalar field
scale : [low, high]
A list or array indicating the lower and upper bounds for the new randomly distributed data. The default is
None, which uses themaxandminof the original image as the the lower and upper bounds.Returns: An ND-image the same size as
imwith uniformly distributed greyscalevalues spanning the specified range, if given.
-
porespy.generators.overlapping_spheres(shape, radius, porosity)[source]¶ Generate a packing of overlapping mono-disperse spheres
Parameters: shape : list
The size of the image to generate in [Nx, Ny, Nz] where Ni is the number of voxels in the *i*th direction.
radius : scalar
The radius of spheres in the packing.
porosity : scalar
The porosity of the final image. This number is approximated by the method so the returned result may not have exactly the specified value.
Returns: A boolean array with True values denoting the pore space
Notes
This method can also be used to generate a dispersion of hollows by treating
porosityas solid volume fraction and inverting the returned image.
-
porespy.generators.polydisperse_spheres(shape, porosity, dist, nbins=5)[source]¶ Create an image of spheres with a distribution of radii.
Parameters: shape : list
The size of the image to generate in [Nx, Ny, Nz] where Ni is the number of voxels in each direction. If shape is only 2D, then an image of polydisperse disks is returns
porosity : scalar
The porosity of the image, defined as the number of void voxels divided by the number of voxels in the image. The specified value is only matched approximately, so it’s suggested to check this value after the image is generated.
dist : scipy.stats distribution object
This should be an initialized distribution the large number of options in the scipy.stats submodule. For instance, a normal distribution with a mean of 20 and a standard deviation of 10 can be obtain with
dist = scipy.stats.norm(loc=20, scale=10)nbins : scalar
The number of discrete sphere sizes that will be used to generate the image. This function generates
nbinsimages of monodisperse spheres that span 0.05 and 0.95 of the possible values produced by the provided distribution, then overlays them to get polydispersivity.Returns: A boolean array with True values denoting the pore space
-
porespy.generators.sphere_pack(shape, radius, offset=0, packing='sc')[source]¶ Generates a cubic packing of spheres
Parameters: shape : list
The size of the image to generate in [Nx, Ny, Nz] where N is the number of voxels in each direction.
radius : scalar
The radius of spheres in the packing
offset : scalar
The amount offset (+ or -) to add between pore centers.
packing : string
Specifies the type of cubic packing to create. Options are:
‘sc’ : Simple Cubic (default) ‘fcc’ : Face Centered Cubic ‘bcc’ : Body Centered Cubic
Returns: A boolean array with True values denoting the pore space
-
porespy.generators.voronoi_edges(shape, radius, ncells, flat_faces=True)[source]¶ Create an image of the edges in a Voronoi tessellation
Parameters: shape : array_like
The size of the image to generate in [Nx, Ny, Nz] where Ni is the number of voxels in each direction.
radius : scalar
The radius to which Voronoi edges should be dilated in the final image.
ncells : scalar
The number of Voronoi cells to include in the tesselation.
flat_faces : Boolean
Whether the Voronoi edges should lie on the boundary of the image (True), or if edges outside the image should be removed (False).
Returns: A boolean array with True values denoting the pore space
Metrics¶
A suite of tools for determine key metrics about an image. Typically these are applied to an image after applying a filter, but a few functions can be applied directly to the binary image.
-
porespy.metrics.chord_length_counts(im)[source]¶ Determines the length of each chord in the supplied image by looking at its size.
Parameters: im : ND-array
An image containing chords drawn in the void space.
Returns: A 1D array with one element for each chord, containing its length.
Notes
The returned array can be passed to
plt.histto plot the histogram,or to
sp.histogramto get the histogram data directly. Another usefulfunction is
sp.bincountwhich gives the number of chords of eachlength in a format suitable for
plt.plot.
-
porespy.metrics.chord_length_distribution(im, bins=25, log=False)[source]¶ Determines the distribution of chord lengths in a image containing chords.
Parameters: im : ND-image
An image with chords drawn in the pore space, as produced by
apply_chordsorapply_chords_3d.bins : scalar or array_like
If a scalar is given it is interpreted as the number of bins to use, and if an array is given they are used as the bins directly.
log : Boolean
If true, the logarithm of the chord lengths will be used, which can make the data more clear.
Returns: A tuple containing the
chord_length_bins, and four separate pieces ofinformation:
cumulative_chord_countandcumulative_chord_length,as well as the
differenial_chord_countanddifferential_chord_length.
-
porespy.metrics.pore_size_density(im, bins=10, voxel_size=1)[source]¶ Computes the histogram of the distance transform as an estimator of the pore sizes in the image.
Parameters: im : ND-array
Either a binary image of the pore space with
Trueindicating the pore phase (or phase of interest), or a pre-calculated distance transform which can save time.bins : int or array_like
This number of bins (if int) or the location of the bins (if array). This argument is passed directly to Scipy’s
histogramfunction so see that docstring for more information. The default is 10 bins, which reduces produces a relatively smooth distribution.voxel_size : scalar
The size of a voxel side in preferred units. The default is 1, so the user can apply the scaling to the returned results after the fact.
Returns: A tuple containing two 1D arrays: ``radius `` is the radius of the voxels,
and
countis the number of voxels that are within R of the solid.Notes
This function should not be taken as a pore size distribution in the explict sense, but rather an indicator of the sizes in the image.
References
[1] Torquato, S. Random Heterogeneous Materials: Mircostructure and Macroscopic Properties. Springer, New York (2002) - See page 292
-
porespy.metrics.pore_size_distribution(im)[source]¶ Calculate drainage curve based on the image produced by the
porosimetryfunction.Parameters: im : ND-array
The array of entry sizes as produced by the
porosimetryfunction.Returns: Rp, Snwp: Two arrays containing (a) the radius of the penetrating
sphere (in voxels) and (b) the volume fraction of pore phase voxels
that are accessible from the specfied inlets.
Notes
This function normalizes the invading phase saturation by total pore volume of the dry image, which is assumed to be all voxels with a value equal to 1. To do porosimetry on images with large outer regions, use the
`find_outer_region`function then set these regions to 0 in the input image. In future, this function could be adapted to apply this check by default.
-
porespy.metrics.porosity(im)[source]¶ Calculates the porosity of an image assuming 1’s are void space and 0’s are solid phase. All other values are ignored.
Parameters: im : ND-array
Image of the void space with 1’s indicating void space (or True) and 0’s indicating the solid phase (or False).
Returns: porosity : float
Calculated as the sum of all 1’s divided by the sum of all 1’s and 0’s.
Notes
This function assumes void is represented by 1 and solid by 0, and all other values are ignored. This is useful, for example, for images of cylindrical cores, where all voxels outside the core are labelled with 2.
Alternatively, images can be processed with
find_disconnected_voxelsto get an image of only blind pores. This can then be added to the orignal image such that blind pores have a value of 2, thus allowing the calculation of accessible porosity, rather than overall porosity.
-
porespy.metrics.representative_elementary_volume(im, npoints=1000)[source]¶ Calculates the porosity of the image as a function subdomain size. This function extracts a specified number of subdomains of random size, then finds their porosity.
Parameters: im : ND-array
The image of the porous material
npoints : int
The number of randomly located and sized boxes to sample. The default is 1000.
Returns: A tuple containing the ND-arrays: The subdomain volume and its
porosity. Each of these arrays is
npointslong. They can beconveniently plotted by passing the tuple to matplotlib’s
plotfunctionusing the * notation:
plt.plot(*the_tuple, 'b.'). The resulting plotis similar to the sketch given by Bachmat and Bear [1]
Notes
This function is frustratingly slow. Profiling indicates that all the time is spent on scipy’s
sumfunction which is needed to sum the number of void voxels (1’s) in each subdomain.Also, this function is primed for parallelization since the
npointsare calculated independenlty.References
[1] Bachmat and Bear. On the Concept and Size of a Representative Elementary Volume (Rev), Advances in Transport Phenomena in Porous Media (1987)
-
porespy.metrics.two_point_correlation_bf(im, spacing=10)[source]¶ Calculates the two-point correlation function using brute-force (see Notes)
Parameters: im : ND-array
The image of the void space on which the 2-point correlation is desired
spacing : int
The space between points on the regular grid that is used to generate the correlation (see Notes)
Returns: A tuple containing the x and y data for plotting the two-point correlation
function, using the *args feature of matplotlib’s plot function. The x
array is the distances between points and the y array is corresponding
probabilities that points of a given distance both lie in the void space.
The distance values are binned as follows:
bins = range(start=0, stop=sp.amin(im.shape)/2, stride=spacing)
Notes
The brute-force approach means overlaying a grid of equally spaced points onto the image, calculating the distance between each and every pair of points, then counting the instances where both pairs lie in the void space.
This approach uses a distance matrix so can consume memory very quickly for large 3D images and/or close spacing.
-
porespy.metrics.two_point_correlation_fft(im, pad=False)[source]¶ Calculates the two-point correlation function using fourier transforms
Parameters: im : ND-array
The image of the void space on which the 2-point correlation is desired
pad : bool
The image is padded with Trues or 1’s depending on dtype around border
Returns: A tuple containing the x and y data for plotting the two-point correlation
function, using the *args feature of matplotlib’s plot function. The x
array is the distances between points and the y array is corresponding
probabilities that points of a given distance both lie in the void space.
Notes
The fourier transform approach utilizes the fact that the autocorrelation function is the inverse FT of the power spectrum density. For background read the Scipy fftpack docs and for a good explanation see: http://www.ucl.ac.uk/~ucapikr/projects/KamilaSuankulova_BSc_Project.pdf
Tools¶
This module contains a variety of functions for manipulating images in ways that do NOT return a modified version of the original image.
-
porespy.tools.extend_slice(s, shape, pad=1)[source]¶ Adjust slice indices to include additional voxles around the slice. The key to this function is that is does bounds checking to ensure the indices don’t extend outside the image.
Parameters: s : list of slice objects
A list (or tuple) of N slice objects, where N is the number of dimensions in the image.
shape : array_like
The shape of the image into which the slice objects apply. This is used to check the bounds to prevent indexing beyond the image.
pad : int
The number of voxels to expand in each direction.
Returns: A list slice objects with the start and stop attributes respectively
incremented and decremented by 1, without extending beyond the image
boundaries.
Examples
>>> from scipy.ndimage import label, find_objects >>> from porespy.tools import extend_slice >>> im = sp.array([[1, 0, 0], [1, 0, 0], [0, 0, 1]]) >>> labels = label(im)[0] >>> s = find_objects(labels)
Using the slices returned by
find_objects, set the first label to 3>>> labels[s[0]] = 3 >>> print(labels) [[3 0 0] [3 0 0] [0 0 2]]
Next extend the slice, and use it to set the values to 4
>>> s_ext = extend_slice(s[0], shape=im.shape, pad=1) >>> labels[s_ext] = 4 >>> print(labels) [[4 4 0] [4 4 0] [4 4 2]]
As can be seen by the location of the 4s, the slice was extended by 1, and also handled the extension beyond the boundary correctly.
-
porespy.tools.extract_subsection(im, shape)[source]¶ Extracts the middle section of a image
Parameters: im : ND-array
Image from which to extract the subsection
shape : array_like
Can either specify the size of the extracted section or the fractional size of the image to extact.
Returns: An ND-array of size given by the
shapeargument, taken from the centerof the image.
Examples
>>> import scipy as sp >>> from porespy.tools import extract_subsection >>> im = sp.array([[1, 1, 1, 1], [1, 2, 2, 2], [1, 2, 3, 3], [1, 2, 3, 4]]) >>> print(im) [[1 1 1 1] [1 2 2 2] [1 2 3 3] [1 2 3 4]] >>> im = extract_subsection(im=im, shape=[2, 2]) >>> print(im) [[2 2] [2 3]]
-
porespy.tools.extract_cylinder(im, r=None, axis=0)[source]¶ Returns a cylindrical section of the image of specified radius. This is useful for making square images look like cylindrical cores such as those obtained from X-ray tomography.
Parameters: im : ND-array
The image of the porous material
r : scalr
The radius of the cylinder to extract. If none if given then the default is the largest cylinder that can fit inside the x-y plane.
axis : scalar
The axis along with the cylinder will be oriented.
Returns: An ND-image the same size
imwith True values indicating the void spacebut with the sample trimmed to a cylindrical section in the center of the
image. The region outside the cylindrical section is labeled with True
values since it is open space.
-
porespy.tools.find_outer_region(im, r=0)[source]¶ Finds regions of the image that are outside of the solid matrix. This function uses the rolling ball method to define where the outer region ends and the void space begins.
This function is particularly useful for samples that do not fill the entire rectangular image, such as cylindrical cores or samples with non- parallel faces.
Parameters: im : ND-array
Image of the porous material with 1’s for void and 0’s for solid
r : scalar
The radius of the rolling ball to use. If not specified then a value is calculated as twice maximum of the distance transform. The image size is padded by this amount in all directions, so the image can become quite large and unwieldy if too large a value is given.
Returns: A boolean mask the same shape as
im, containing True in all voxelsidentified as outside the sample.
-
porespy.tools.get_border(shape, thickness=1, mode='edges')[source]¶ Creates an array of specified size with corners, edges or faces labelled as True. This can be used as mask to manipulate values laying on the perimeter of an image.
Parameters: shape : array_like
The shape of the array to return. Can be either 2D or 3D.
thickness : scalar (default is 1)
The number of pixels/voxels to place along perimeter.
mode : string
The type of border to create. Options are ‘faces’, ‘edges’ (default) and ‘corners’. In 2D ‘faces’ and ‘edges’ give the same result.
Returns: An ND-array of specified shape with True values at the perimeter and False
elsewhere.
Examples
>>> import porespy as ps >>> import scipy as sp >>> mask = ps.tools.get_border(shape=[3, 3], mode='corners') >>> print(mask) [[ True False True] [False False False] [ True False True]] >>> mask = ps.tools.get_border(shape=[3, 3], mode='edges') >>> print(mask) [[ True True True] [ True False True] [ True True True]]
-
porespy.tools.get_slice(im, center, size, pad=0)[source]¶ Given a
centerlocation andradiusof a feature, returns the slice object into theimthat bounds the feature but does not extend beyond the image boundaries.Parameters: im : ND-image
The image of the porous media
center : array_like
The coordinates of the center of the feature of interest
size : array_like or scalar
The size of the feature in each direction. If a scalar is supplied, this implies the same size in all directions.
pad : scalar or array_like
The amount to pad onto each side of the slice. The default is 0. A scalar value will increase the slice size equally in all directions, while an array the same shape as
im.shapecan be passed to pad a specified amount in each direction.Returns: A list of slice objects, each indexing into one dimension of the image.
-
porespy.tools.make_contiguous(im)[source]¶ Take an image with arbitrary greyscale values and adjust them to ensure all values fall in a contiguous range starting at 0.
Parameters: im : array_like
An ND array containing greyscale values
Returns: An ND-array the same size as
imbut with all values in contiguousorders.
-
porespy.tools.randomize_colors(im, keep_vals=[0])[source]¶ Takes a greyscale image and randomly shuffles the greyscale values, so that all voxels labeled X will be labelled Y, and all voxels labeled Y will be labeled Z, where X, Y, Z and so on are randomly selected from the values in the input image.
This function is useful for improving the visibility of images with neighboring regions that are only incrementally different from each other, such as that returned by scipy.ndimage.label.
Parameters: im : array_like
An ND image of greyscale values.
keep_vals : array_like
Indicate which voxel values should NOT be altered. The default is [0] which is useful for leaving the background of the image untouched.
Returns: An image the same size and type as im but with the greyscale values
reassigned. The unique values in both the input and output images will
be identical.
Notes
If the greyscale values in the input image are not contiguous then the neither will they be in the output.
Examples
>>> import porespy as ps >>> import scipy as sp >>> sp.random.seed(0) >>> im = sp.random.randint(low=0, high=5, size=[4, 4]) >>> print(im) [[4 0 3 3] [3 1 3 2] [4 0 0 4] [2 1 0 1]] >>> im_rand = ps.tools.randomize_colors(im) >>> print(im_rand) [[2 0 4 4] [4 1 4 3] [2 0 0 2] [3 1 0 1]]
As can be seen, the 2’s have become 3, 3’s have become 4, and 4’s have become 2. 1’s remained 1 by random accident. 0’s remain zeros by default, but this can be controlled using the keep_vals argument.
-
porespy.tools.subdivide(im, divs=2)[source]¶ Returns slices into an image describing the specified number of sub-arrays. This function is useful for performing operations on smaller images for memory or speed. Note that most typical operations this will NOT work, since the image borders would cause artifacts (e.g.
distance_transform)Parameters: im : ND-array
The image of the porous media
divs : scalar or array_like
The number of sub-divisions to create in each axis of the image. If a scalar is given it is assume this value applies in all dimensions.
Returns: An ND-array containing slice objects for indexing into
imthat extractthe sub-divided arrays.
Notes
This method uses the array_split package which offers the same functionality as the
splitmethod of Numpy’s ND-array, but supports the splitting multidimensional arrays in all dimensions.Examples
>>> import porespy as ps >>> import matplotlib.pyplot as plt >>> im = ps.generators.blobs(shape=[200, 200]) >>> s = ps.tools.subdivide(im, divs=[2, 2])
scontains an array with the shape given bydivs. To access the first and last quadrants ofimuse: >>> print(im[s[0, 0]].shape) (100, 100) >>> print(im[s[1, 1]].shape) (100, 100)It can be easier to index the array with the slices by applying
flattenfirst: >>> s_flat = s.flatten() >>> for i in s_flat: ... print(im[i].shape) (100, 100) (100, 100) (100, 100) (100, 100)
Network Extraction¶
This module contains functions for extracting pore networks from images.
-
porespy.network_extraction.partition_pore_space(im, peaks)[source]¶ Applies a watershed segmentation to partition the distance transform into discrete pores.
Parameters: im : ND-array
Either the Boolean array of the pore space or a distance tranform. Passing in a pre-existing distance transform saves time, since one is calculated by the function if a Boolean array is passed.
peaks : ND-array
An array the same size as
dtindicating where the pore centers are. If boolean, the peaks are labeled; if numeric then it’s assumed that peaks have already been given desired labels.Returns: A ND-array the same size as
dtwith regions belonging to each peaklabelled. The region number is randomized so that neighboring regions
are contrasting colors for easier visualization.
See also
Notes
Find the appropriate
peaksarray is the tricky part. In principle, each local maxima in the distance transform is a pore center, but due to loss of fidelity in the voxel representation this leads to many extraneous peaks. Several functions are available to help select peaks which can then be passed to this function.
-
porespy.network_extraction.align_image_with_openpnm(im)[source]¶ Rotates an image to agree with the coordinates used in OpenPNM. It is unclear why they are not in agreement to start with. This is necessary for overlaying the image and the network in Paraview.
Parameters: im : ND-array
The image to be rotated. Can the Boolean image of the pore space or any other image of interest.
Returns: Returns the image rotated accordingly.
-
porespy.network_extraction.snow(im, r_max=4, sigma=0.4)[source]¶ This function partitions the void space into pore regions using a marker-based watershed algorithm. The key to this function is that true local maximum of the distance transform are found by trimming various types of extraneous peaks.
The SNOW network extraction algorithm (Sub-Network of an Over-segmented Watershed) was designed to handle to perculiarities of high porosity materials, but it applies well to other materials as well.
Parameters: im : array_like
Can be either (a) a boolean image of the domain, with
Trueindicating the pore space andFalseelsewhere, or (b) a distance transform of the domain calculated externally by the user. Option (b) is faster if a distance transform is already available.r_max : scalar
The radius of there spherical structuring element to use in the Maximum filter stage that is used to find peaks. The default is 4
sigma : scalar
The standard deviation of the Gaussian filter used in step 1. The default is 0.4. If 0 is given then the filter is not applied, which is useful if a distance transform is supplied as the
imargument that has already been processed.Returns: A tuple containing several arrays. This is a named tuple meaning that
each array can be accessed using the following attribute names:
im: The binary image of the void spacedt: The distance transform of the imagepeaks: The peaks of the distance transform after applying the
steps of the SNOW algorithm *
regions: The void space partitioned into pores using a marker based watershed with the peaks found by the SNOW algorithmReferences
[1] Gostick, J. “A versatile and efficient network extraction algorithm using marker-based watershed segmenation”. Physical Review E. (2017)
-
porespy.network_extraction.trim_saddle_points(peaks, dt, max_iters=10)[source]¶ Removes peaks that were mistakenly identified because they lied on a saddle or ridge in the distance transform that was not actually a true local peak.
Parameters: peaks : ND-array
A boolean image containing True values to mark peaks in the distance transform (
dt)dt : ND-array
The distance transform of the pore space for which the true peaks are sought.
max_iters : int
The maximum number of iterations to run while eroding the saddle points. The default is 10, which is usually not reached; however, a warning is issued if the loop ends prior to removing all saddle points.
Returns: An image with fewer peaks than was received.
-
porespy.network_extraction.trim_nearby_peaks(peaks, dt)[source]¶ Finds pairs of peaks that are nearer to each other than to the solid phase, and removes the peak that is closer to the solid.
Parameters: peaks : ND-array
A boolean image containing True values to mark peaks in the distance transform (
dt)dt : ND-array
The distance transform of the pore space for which the true peaks are sought.
Returns: An array the same size as
peakscontaining a subset of the peaks inthe original image.
Notes
Each pair of peaks is considered simultaneously, so for a triplet of peaks each pair is considered. This ensures that only the single peak that is furthest from the solid is kept. No iteration is required.
-
porespy.network_extraction.reduce_peaks_to_points(peaks)[source]¶ Any peaks that are broad or elongated are replaced with a single voxel that is located at the center of mass of the original voxels.
Parameters: peaks : ND-image
An image containing True values indicating peaks in the distance transform
Returns: An array with the same number of isolated peaks as the original image, but
fewer total voxels.
Notes
The center of mass of a group of voxels is used as the new single voxel, so if the group has an odd shape (like a horse shoe), the new voxel may not lie on top of the original set.
-
porespy.network_extraction.find_peaks(dt, r=4, footprint=None)[source]¶ Returns all local maxima in the distance transform
Parameters: dt : ND-array
The distance transform of the pore space. This may be calculated and filtered using any means desired.
r : scalar
The size of the structuring element used in the maximum filter. This controls the localness of any maxima. The default is 3 voxels.
footprint : ND-array
Specifies the shape of the structuring element used to define the neighborhood when looking for peaks. If none is specified then a spherical shape is used (or circular in 2D).
Returns: An ND-array of booleans with
Truevalues at the location of any localmaxima.
Notes
It is also possible ot the
peak_local_maxfunction from theskimage.featuremodule as follows:peaks = peak_local_max(image=dt, min_distance=r, exclude_border=0, indices=False)This automatically uses a square structuring element which is significantly faster than using a circular or spherical element.
-
porespy.network_extraction.extract_pore_network(im, dt=None, voxel_size=1)[source]¶ Analyzes an image that has been partitioned into pore regions and extracts the pore and throat geometry as well as network connectivity.
Parameters: im : ND-array
An image of the pore space partitioned into individual pore regions. Note that this image must have zeros indicating the solid phase.
dt : ND-array
The distance transform of the pore space. If not given it will be calculated, but it can save time to provide one if available.
voxel_size : scalar
The resolution of the image, expressed as the length of one side of a voxel, so the volume of a voxel would be voxel_size-cubed. The default is 1, which is useful when overlaying the PNM on the original image since the scale of the image is alway 1 unit lenth per voxel.
Returns: A dictionary containing all the pore and throat size data, as well as the
network topological information. The dictionary names use the OpenPNM
convention (i.e. ‘pore.coords’, ‘throat.conns’) so it may be converted
directly to an OpenPNM network object using the
updatecommand.
Simulations¶
This module contains classes that perform simulations directly on the images to obtain structural information
-
class
porespy.simulations.RandomWalk(im, walkers=1000, max_steps=5000, stride=10, start_frac=0.2)[source]¶ This class generates objects for performing random walk simulations on.
Parameters: im: ndarray of bool
2D or 3D image
walkers: int (default = 1000)
The number of walks to initially perform
max_steps: int (default = 5000)
The number of steps to attempt per walk
stride: int (default = 10)
The number of steps taken between each coordinate in path_data
st_frac: float (default = 0.2)
This fraction of the image (in the centre) is searched for a valid starting point for each walk
Examples
Creating a RandomWalk object:
>>> import porespy as ps >>> im = ps.generators.blobs(300) >>> rw = ps.simulations.RandomWalk(im, walkers=500, max_steps=3000)
Attributes
max_stepsndimpath_datasd_datashapestart_fracstepssterr_datastridetotal_walkersMethods
find_start_point(start_frac)Finds a random valid start point in a porous image, searching in the get_msd([direction])perform_walks(walkers)Adds the specified number of walkers to the path_data attribute save_path(walker, f_name)Saves the selected walkers path through pore space and free space show_msd([step_range, direction, showstderr])Graphs mean squared displacement in pore space and free space vs. show_path(walker)Shows the selected walkers path through pore space and free space walkThis function performs a single random walk through porous image. -
find_start_point(start_frac)[source]¶ Finds a random valid start point in a porous image, searching in the given fraction of the image
Parameters: start_frac: float
A value between 0 and 1. Determines what fraction of the image is randomly searched for a starting point
Returns: start_point: tuple
A tuple containing the index of a valid start point. If the image is 2D, start_point will have 0 as the first coord
-
perform_walks(walkers)[source]¶ Adds the specified number of walkers to the path_data attribute
Parameters: walkers: int
The number of walks to perform. This many rows will be added to each of the path_data arrays (path_data.pore_space and path_data.free_space)
Notes
This function will continue to use the max_steps and stride value stored on the object
-
save_path(walker, f_name)[source]¶ Saves the selected walkers path through pore space and free space
Parameters: walker: int
The walker whose path will be saved
f_name: string
A path to a filename. Note that this function will add the suffix pore_space and free_space to differentiate between paths
-
show_msd(step_range=None, direction=None, showstderr=True)[source]¶ Graphs mean squared displacement in pore space and free space vs. number of steps taken
Parameters: step_range: array_like (optional)
A sequence with the min and max range of steps to plot. If no argument is given, the range will be zero to max_steps
direction: int (optional)
The axis along which to show mean squared displacement in. If no argument is given, total msd is shown
showstderr: bool (optional)
If set to True, the graph will show error bars
Returns: out: namedtuple
-
show_path(walker)[source]¶ Shows the selected walkers path through pore space and free space using a matplotlib figure
Parameters: walker: int
The walker whose path will be shown
-
walk[source]¶ This function performs a single random walk through porous image. It returns an array containing the walker path in the image, and the walker path in free space.
Parameters: start_point: array_like
A sequence containing the indices of a valid starting point. If the image is 2D, the first coordinate needs to be zero
max_steps: int
The number of steps to attempt per walk
stride: int
Number of steps taken between each returned coordinate
Returns: paths: namedtuple
A tuple containing 2 arrays showing the paths taken by the walker: path.pore_space and path.free_space
Notes
This function only performs a single walk through the image. Use RandomWalk.-perform_walks() to add more
-
-
class
porespy.simulations.Porosimetry(im, voxel_size=1)[source]¶ Simulates a porosimetry experiment on a binary image. This function is equivalent to the morphological image opening and/or the full morphology approaches.
Parameters: im : ND-array
The Boolean image of the porous material, with True values indicating the pore space
Attributes
resultMethods
get_drainage_data()Calculate drainage curve based on the image produced by the porosimetryfunction.plot_drainage_curve([fig])plot_size_histogram([fig])run([npts, sizes, inlets, access_limited])Performs a porosimetry simulution on the image -
get_drainage_data()[source]¶ Calculate drainage curve based on the image produced by the
porosimetryfunction.Returns: Rp, Snwp: Two arrays containing (a) the radius of the penetrating
sphere (in voxels) and (b) the volume fraction of pore phase voxels
that are accessible from the specfied inlets.
Notes
This function normalizes the invading phase saturation by total pore volume of the dry image, which is assumed to be all voxels with a value equal to 1. To do porosimetry on images with large outer regions, use the
`find_outer_region`function then set these regions to 0 in the input image. In future, this function could be adapted to apply this check by default.
-
run(npts=25, sizes=None, inlets=None, access_limited=True)[source]¶ Performs a porosimetry simulution on the image
Parameters: im : ND-array
An ND image of the porous material containing True values in the pore space.
npts : scalar
The number of invasion points to simulate. Points will be generated spanning the range of sizes in the distance transform. The default is 25 points.
sizes : array_like
The sizes to invade. Use this argument instead of
nptsfor more control of the range and spacing of points.inlets : ND-array, boolean
A boolean mask with True values indicating where the invasion enters the image. By default all faces are considered inlets, akin to a mercury porosimetry experiment. Users can also apply solid boundaries to their image externally before passing it in, allowing for complex inlets like circular openings, etc.
access_limited : Boolean
This flag indicates if the intrusion should only occur from the surfaces (
access_limitedis True, which is the default), or if the invading phase should be allowed to appear in the core of the image. The former simulates experimental tools like mercury intrusion porosimetry, while the latter is useful for comparison to gauge the extent of shielding effects in the sample.Returns: An ND-image with voxel values indicating the sphere radius at which it
becomes accessible from the inlets. This image can be used to find
invading fluid configurations as a function of applied capillary pressure
by applying a boolean comparison:
inv_phase = im > rwhereristhe radius (in voxels) of the invading sphere. Of course,
rcan beconverted to capillary pressure using your favorite model.
-
Visualization¶
This module contains functions for quickly visualizing 3D images in 2D views.
-
porespy.visualization.sem(im, direction='X')[source]¶ Simulates an SEM photograph looking into the porous material in the specified direction. Features are colored according to their depth into the image, so darker features are further away.
Parameters: im : array_like
ND-image of the porous material with the solid phase marked as 1 or True
direction : string
Specify the axis along which the camera will point. Options are ‘X’, ‘Y’, and ‘Z’.
Returns: A 2D greyscale image suitable for use in matplotlib’s
`imshow`function.
-
porespy.visualization.xray(im, direction='X')[source]¶ Simulates an X-ray radiograph looking through the porouls material in the specfied direction. The resulting image is colored according to the amount of attenuation an X-ray would experience, so regions with more solid will appear darker.
Parameters: im : array_like
ND-image of the porous material with the solid phase marked as 1 or True
direction : string
Specify the axis along which the camera will point. Options are ‘X’, ‘Y’, and ‘Z’.
Returns: A 2D greyscale image suitable for use in matplotlib’s
`imshow`function.