spam.label package#
Submodules#
spam.label.ITKwatershed module#
Library of wrapper functions for Simple ITK Copyright (C) 2020 SPAM Contributors
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
- spam.label.ITKwatershed.watershed(binary, markers=None, watershedLevel=1)[source]#
This function runs an ITK watershed on a binary image and returns a labelled image. This function uses an interpixel watershed.
- Parameters:
binary (3D numpy array) – This image which is non-zero in the areas which should be split by the watershed algorithm
markers (3D numpy array (optional, default = None)) – Not implemented yet, but try!
watershedLevel (int, optional) – Watershed level for merging maxima
- Returns:
labelled – 3D array where each object is numbered
- Return type:
3D numpy array of ints
spam.label.contacts module#
Library of SPAM functions for dealing with contacts between particles Copyright (C) 2020 SPAM Contributors
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
- spam.label.contacts.contactingLabels(lab, labelsList=None, areas=False, boundingBoxes=None, centresOfMass=None)[source]#
This function returns contacting labels for a given label or list of labels, and optionally the number of voxels involved in the contact. This is designed for an interpixel watershed where there are no watershed lines, and so contact detection is done by dilating the particle in question once and seeing what other labels in comes in contact with.
- Parameters:
lab (3D numpy array of ints ( of type spam.label.toolkit.labelType)) – An array of labels with 0 as the background
labels (int or a list of labels) – Labels for which we should compute neighbours
areas (bool, optional (default = False)) – Compute contact “areas”? i.e., number of voxels Careful, this is not a physically correct quantity, and is measured only as the overlap from
label
to its neightbours. Seec ontactPoint
for something more meaningfulboundingBoxes (lab.max()x6 array of ints, optional) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
centresOfMass (lab.max()x3 array of floats, optional) – Centres of mass in format returned by
centresOfMass
. If not defined (Default = None), it is recomputed by runningcentresOfMass
- Returns:
For a single “labels”, a list of contacting labels.
if areas == True, then a list of “areas” is also returned.
For multiple labels, as above but a lsit of lists in the order of the labels
Note
Because of dilation, this function is not very safe at the edges, and will throw an exception
- spam.label.contacts.contactPoints(lab, contactPairs, returnContactZones=False, boundingBoxes=None, centresOfMass=None, verbose=False)[source]#
Get the point, or area of contact between contacting particles. This is done by looking at the overlap of a 1-dilation of particle1 onto particle 2 and vice versa.
- Parameters:
lab (3D numpy array of ints ( of type spam.label.toolkit.labelType)) – An array of labels with 0 as the background
contactPairs (list (or list of list) of labels) – Pairs of labels for which we should compute neighbours
returnContactZones (bool, optional (default = False)) – Output a labelled volume where contact zones are labelled according to the order of contact pairs? If False, the centres of mass of the contacts are returned
boundingBoxes (lab.max()x6 array of ints, optional) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
centresOfMass (lab.max()x3 array of floats, optional) – Centres of mass in format returned by
centresOfMass
. If not defined (Default = None), it is recomputed by runningcentresOfMass
- Returns:
if returnContactZones – lab : 3D numpy array of ints ( of type spam.label.toolkit.labelType)
else – Z Y X Centres of mass of contacts
- spam.label.contacts.labelledContacts(lab, maximumCoordinationNumber=20)[source]#
Uniquely names contacts based on grains.
- Parameters:
lab (3D numpy array of ints ( of type spam.label.toolkit.labelType)) – An array of labels with 0 as the background
maximumCoordinationNumber (int (optional, default = 20)) – Maximum number of neighbours to consider per grain
- Returns:
- contactVolumearray of ints
3D array where contact zones are uniquely labelled
- Zarray of ints
Vector of length lab.max()+1 contaning the coordination number (number of touching labels for each label)
- contactTablearray of ints
2D array of lab.max()+1 by 2*maximumCoordinationNumber containing, per grain: touching grain label, contact number
- contactingLabelsarray of ints
2D array of numberOfContacts by 2 containing, per contact: touching grain label 1, touching grain label 2
- Return type:
An array, containing
- spam.label.contacts.fetchTwoGrains(volLab, labels, volGrey=None, boundingBoxes=None, padding=0, size_exclude=5)[source]#
Fetches the sub-volume of two grains from a labelled image
- Parameters:
volLab (3D array of integers) – Labelled volume, with lab.max() labels
labels (1x2 array of integers) – the two labels that should be contained in the subvolume
volGrey (3D array) – Grey-scale volume
boundingBoxes (lab.max()x6 array of ints, optional) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
padding (integer) – padding of the subvolume for some purpose it might be benefitial to have a subvolume with a boundary of zeros
- Returns:
subVolLab (3D array of integers) – labelled sub-volume containing the two input labels
subVolBin (3D array of integers) – binary subvolume
subVolGrey (3D array) – grey-scale subvolume
- spam.label.contacts.localDetection(subVolGrey, localThreshold, radiusThresh=None)[source]#
local contact refinement checks whether two particles are in contact with a local threshold, that is higher than the global one used for binarisation
- Parameters:
subVolGrey (3D array) – Grey-scale volume
localThreshold (integer or float, same type as the 3D array) – threshold for binarisation of the subvolume
radiusThresh (integer, optional) – radius for excluding patches that might not be relevant, e.g. noise can lead to patches that are not connected with the grains in contact the patches are calculated with
equivalentRadii()
Default is None and such patches are not excluded from the subvolume
- Returns:
CONTACT – if True, that particles appear in contact for the local threshold
- Return type:
boolean
Note
see https://doi.org/10.1088/1361-6501/aa8dbf for further information
- spam.label.contacts.contactOrientations(volBin, volLab, watershed='ITK', peakDistance=1, markerShrink=True, verbose=False)[source]#
determines contact normal orientation between two particles uses the random walker implementation from skimage
- Parameters:
volBin (3D array) – binary volume containing two particles in contact
volLab (3D array of integers) – labelled volume containing two particles in contact
watershed (string) – sets the basis for the determination of the orientation options are “ITK” for the labelled image from the input, “RW” for a further segmentation by the random walker Default = “ITK”
peakDistance (int, optional) – Distance in pixels used in skimage.feature.peak_local_max Default value is 1
markerShrink (boolean) – shrinks the markers to contain only one voxel. For large markers, the segmentation might yield strange results depending on the shape. Default = True
verbose (boolean (optional, default = False)) – True for printing the evolution of the process False for not printing the evolution of process
- Returns:
contactNormal (1x3 array) – contact normal orientation in z,y,x coordinates the vector is flipped such that the z coordinate is positive
len(coordIntervox) (integer) – the number of points for the principal component analysis indicates the quality of the fit
notTreatedContact (boolean) – if False that contact is not determined if the contact consisted of too few voxels a fit is not possible or feasible
- spam.label.contacts.localDetectionAssembly(volLab, volGrey, contactList, localThreshold, boundingBoxes=None, nProcesses=32, radiusThresh=4)[source]#
Local contact refinement of a set of contacts checks whether two particles are in contact with a local threshold using
localDetection()
- Parameters:
volLab (3D array) – Labelled volume
volGrey (3D array) – Grey-scale volume
contactList ((ContactNumber)x2 array of integers) – contact list with grain labels of each contact in a seperate row, as given by
spam.label.contacts.labelledContacts
in the list contactingLabelslocalThreshold (integer or float, same type as the 3D array) – threshold for binarisation of the subvolume
boundingBoxes (lab.max()x6 array of ints, optional) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
nProcesses (integer (optional, default = nProcessesDefault)) – Number of processes for multiprocessing Default = number of CPUs in the system
radiusThresh (integer, optional) – radius in px for excluding patches that might not be relevant, e.g. noise can lead to patches that are not connected with the grains in contact the patches are calculated with
equivalentRadii()
Default is 4
- Returns:
contactListRefined – refined contact list, based on the chosen local threshold
- Return type:
(ContactNumber)x2 array of integers
Note
see https://doi.org/10.1088/1361-6501/aa8dbf for further information
- spam.label.contacts.contactOrientationsAssembly(volLab, volGrey, contactList, watershed='ITK', peakDistance=5, boundingBoxes=None, nProcesses=32, verbose=False)[source]#
Determines contact normal orientation in an assembly of touching particles uses either directly the labelled image or the random walker implementation from skimage
- Parameters:
volLab (3D array) – Labelled volume
volGrey (3D array) – Grey-scale volume
contactList ((ContactNumber)x2 array of integers) – contact list with grain labels of each contact in a seperate row, as given by
spam.label.contacts.labelledContacts
in the list contactingLabels or byspam.label.contacts.localDetectionAssembly()
watershed (string, optional) – sets the basis for the determination of the orientation options are “ITK” for the labelled image from the input, “RW” for a further segmentation by the random walker Default = “ITK”
peakDistance (int, optional) – Distance in pixels used in skimage.feature.peak_local_max Default value is 5
boundingBoxes (lab.max()x6 array of ints, optional) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
nProcesses (integer (optional, default = nProcessesDefault)) – Number of processes for multiprocessing Default = number of CPUs in the system
verbose (boolean (optional, default = False)) – True for printing the evolution of the process False for not printing the evolution of process
- Returns:
contactOrientations ((numContacts)x6 array) – contact normal orientation for every contact [labelGrainA, labelGrainB, orientationZ, orientationY, orientationX, intervoxel positions for PCA]
notTreatedContact (boolean) – if False that contact is not determined if the contact consisted of too few voxels a fit is not possible or feasible
spam.label.label module#
Library of SPAM functions for dealing with labelled images Copyright (C) 2020 SPAM Contributors
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
- spam.label.label.boundingBoxes(lab)[source]#
Returns bounding boxes for labelled objects using fast C-code which runs a single time through lab
- Parameters:
lab (3D array of integers) – Labelled volume, with lab.max() labels
- Returns:
boundingBoxes – This array contains, for each label, 6 integers:
Zmin, Zmax
Ymin, Ymax
Xmin, Xmax
- Return type:
lab.max()x6 array of ints
Note
- Bounding boxes are not slices and so to extract the correct bounding box from a numpy array you should use:
lab[ Zmin:Zmax+1, Ymin:Ymax+1, Xmin:Xmax+1 ]
- Otherwise said, the bounding box of a single-voxel object at 1,1,1 will be:
1,1,1,1,1,1
Also note: for labelled images where some labels are missing, the bounding box returned for this case will be obviously wrong: e.g., Zmin = (z dimension-1) and Zmax = 0
- spam.label.label.centresOfMass(lab, boundingBoxes=None, minVol=None)[source]#
Calculates (binary) centres of mass of each label in labelled image
- Parameters:
lab (3D array of integers) – Labelled volume, with lab.max() labels
boundingBoxes (lab.max()x6 array of ints, optional) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
minVol (int, optional) – The minimum volume in vx to be treated, any object below this threshold is returned as 0
- Returns:
centresOfMass – This array contains, for each label, 3 floats, describing the centre of mass of each label in Z, Y, X order
- Return type:
lab.max()x3 array of floats
- spam.label.label.volumes(lab, boundingBoxes=None)[source]#
Calculates (binary) volumes each label in labelled image, using potentially slow numpy.where
- Parameters:
lab (3D array of integers) – Labelled volume, with lab.max() labels
boundingBoxes (lab.max()x6 array of ints, optional) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
- Returns:
volumes – This array contains the volume in voxels of each label
- Return type:
lab.max()x1 array of ints
- spam.label.label.equivalentRadii(lab, boundingBoxes=None, volumes=None)[source]#
Calculates (binary) equivalent sphere radii of each label in labelled image
- Parameters:
lab (3D array of integers) – Labelled volume, with lab.max() labels
boundingBoxes (lab.max()x6 array of ints, optional) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
volumes (lab.max()x1 array of ints) – Vector contining volumes, if this is passed, the others are ignored
- Returns:
equivRadii – This array contains the equivalent sphere radius in pixels of each label
- Return type:
lab.max()x1 array of floats
- spam.label.label.momentOfInertia(lab, boundingBoxes=None, minVol=None, centresOfMass=None)[source]#
Calculates (binary) moments of inertia of each label in labelled image
- Parameters:
lab (3D array of integers) – Labelled volume, with lab.max() labels
boundingBoxes (lab.max()x6 array of ints, optional) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
centresOfMass (lab.max()x3 array of floats, optional) – Centres of mass in format returned by
centresOfMass
. If not defined (Default = None), it is recomputed by runningcentresOfMass
minVol (int, optional) – The minimum volume in vx to be treated, any object below this threshold is returned as 0 Default = default for spam.label.centresOfMass
- Returns:
eigenValues (lab.max()x3 array of floats) – The values of the three eigenValues of the moment of inertia of each labelled shape
eigenVectors (lab.max()x9 array of floats) – 3 x Z,Y,X components of the three eigenValues in the order of the eigenValues
- spam.label.label.ellipseAxes(lab, volumes=None, MOIeigenValues=None, enforceVolume=True, twoD=False)[source]#
Calculates length of half-axes a,b,c of the ellipitic fit of the particle. These are half-axes and so are comparable to the radius – and not the diameter – of the particle.
- See appendix of for inital work:
“Three-dimensional study on the interconnection and shape of crystals in a graphic granite by X-ray CT and image analysis.”, Ikeda, S., Nakano, T., & Nakashima, Y. (2000).
- Parameters:
lab (3D array of integers) – Labelled volume, with lab.max() labels Note: This is not strictly necessary if volumes and MOI is given
volumes (1D array of particle volumes (optional, default = None)) – Volumes of particles (length of array = lab.max())
MOIeigenValues (lab.max()x3 array of floats, (optional, default = None)) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
True) (enforceVolume = bool (default =) – Should a, b and c be scaled to enforce the fitted ellipse volume to be the same as the particle? This causes eigenValues are no longer completely consistent with fitted ellipse
twoD (bool (default = False)) – Are these in fact 2D ellipses? Not implemented!!
- Returns:
ABCaxes – a, b, c lengths of particle in pixels
- Return type:
lab.max()x3 array of floats
Note
Our elliptic fit is not necessarily of the same volume as the original particle, although by default we scale all axes linearly with enforceVolumes to enforce this condition.
Reminder: volume of an ellipse is (4/3)*pi*a*b*c
Useful check from TM: Ia = (4/15)*pi*a*b*c*(b**2+c**2)
Function contributed by Takashi Matsushima (University of Tsukuba)
- spam.label.label.convertLabelToFloat(lab, vector)[source]#
Replaces all values of a labelled array with a given value. Useful for visualising properties attached to labels, e.g., sand grain displacements.
- Parameters:
lab (3D array of integers) – Labelled volume, with lab.max() labels
vector (a lab.max()x1 vector with values to replace each label with)
- Returns:
relabelled
- Return type:
3D array of converted floats
- spam.label.label.makeLabelsSequential(lab)[source]#
This function fills gaps in labelled images, by relabelling them to be sequential integers. Don’t forget to recompute all your grain properties since the label numbers will change
- Parameters:
lab (3D numpy array of ints ( of type spam.label.toolkit.labelType)) – An array of labels with 0 as the background
- Returns:
lab – An array of labels with 0 as the background
- Return type:
3D numpy array of ints ( of type spam.label.toolkit.labelType)
- spam.label.label.getLabel(labelledVolume, label, boundingBoxes=None, centresOfMass=None, margin=0, extractCube=False, extractCubeSize=None, maskOtherLabels=True, labelDilate=0, labelDilateMaskOtherLabels=False)[source]#
Helper function to extract labels from a labelled image/volume. A dictionary is returned with the a subvolume around the particle. Passing boundingBoxes and centresOfMass is highly recommended.
- Parameters:
labelVolume (3D array of ints) – 3D Labelled volume
label (int) – Label that we want information about
boundingBoxes (nLabels*2 array of ints, optional) – Bounding boxes as returned by
boundingBoxes
. Optional but highly recommended. If unset, bounding boxes are recalculated for every call.centresOfMass (nLabels*3 array of floats, optional) – Centres of mass as returned by
centresOfMass
. Optional but highly recommended. If unset, centres of mass are recalculated for every call.extractCube (bool, optional) – Return label subvolume in the middle of a cube? Default = False
extractCubeSize (int, optional) – half-size of cube to extract. Default = calculate minimum cube
margin (int, optional) – Extract a
margin
pixel margin around bounding box or cube. Default = 0maskOtherLabels (bool, optional) – In the returned subvolume, should other labels be masked? If true, the mask is directly returned. Default = True
labelDilate (int, optional) – Number of times label should be dilated before returning it? This can be useful for catching the outside/edge of an image.
margin
should at least be equal to this value. RequiresmaskOtherLabels
. Default = 0labelDilateMaskOtherLabels (bool, optional) – Strictly cut the other labels out of the dilated image of the requested label? Only pertinent for positive labelDilate values. Default = False
- Returns:
- Keys:
- subvol3D array of bools or ints
subvolume from labelled image
- slicetuple of 3*slices
Slice used to extract subvol for the bounding box mode
- sliceCubetuple of 3*slices
Slice used to extract subvol for the cube mode, warning, if the label is near the edge, this is the slice up to the edge, and so it will be smaller than the returned cube
- boundingBox1D numpy array of 6 ints
Bounding box, including margin, in bounding box mode. Contains: [Zmin, Zmax, Ymin, Ymax, Xmin, Xmax] Note: uses the same convention as spam.label.boundingBoxes, so if you want to use this to extract your subvolume, add +1 to max
- boundingBoxCube1D numpy array of 6 ints
Bounding box, including margin, in cube mode. Contains: [Zmin, Zmax, Ymin, Ymax, Xmin, Xmax] Note: uses the same convention as spam.label.boundingBoxes, so if you want to use this to extract your subvolume, add +1 to max
- centreOfMassABS3*float
Centre of mass with respect to
labelVolume
- centreOfMassREL3*float
Centre of mass with respect to
subvol
- volumeInitialint
Volume of label (before dilating)
- volumeDilatedint
Volume of label (after dilating, if requested)
- Return type:
Dictionary containing
- spam.label.label.getImagettesLabelled(lab1, label, Phi, im1, im2, searchRange, boundingBoxes, centresOfMass, margin=0, labelDilate=0, maskOtherLabels=True, applyF='all', volumeThreshold=100)[source]#
This function is responsible for extracting correlation windows (“imagettes”) from two larger images (im1 and im2) with the help of a labelled im1. This is generally to do image correlation, this function will be used for spam-ddic and pixelSearch modes.
- Parameters:
lab1 (3D numpy array of ints) – Labelled image containing nLabels
label (int) – Label of interest
Phi (4x4 numpy array of floats) – Phi matrix representing the movement of imagette1, if not equal to I, imagette1 is deformed by the non-translation parts of Phi (F) and the displacement is added to the search range (see below)
im1 (3D numpy array) – This is the large input reference image of greyvalues
im2 (3D numpy array) – This is the large input deformed image of greyvalues
searchRange (6-component numpy array of ints) – This defines where imagette2 should be extracted with respect to imagette1’s position in im1. The 6 components correspond to [ Zbot Ztop Ybot Ytop Xbot Xtop ]. If Z, Y and X values are the same, then imagette2 will be displaced and the same size as imagette1. If ‘bot’ is lower than ‘top’, imagette2 will be larger in that dimension
boundingBoxes (nLabels*2 array of ints) – Bounding boxes as returned by
boundingBoxes
centresOfMass (nLabels*3 array of floats) – Centres of mass as returned by
centresOfMass
margin (int, optional) – Margin around the grain to extract in pixels Default = 0
labelDilate (int, optional) – How much to dilate the label before computing the mask? Default = 0
maskOtherLabels (bool, optional) – In the returned subvolume, should other labels be masked? If true, the mask is directly returned. Default = True
applyF (string, optional) – If a non-identity Phi is passed, should the F be applied to the returned imagette1? Options are: ‘all’, ‘rigid’, ‘no’ Default = ‘all’ Note: as of January 2021, it seems to make more sense to have this as ‘all’ for pixelSearch, and ‘no’ for local DIC
volumeThreshold (int, optional) – Pixel volume of labels that are discarded Default = 100
- Returns:
‘imagette1’ : 3D numpy array,
’imagette1mask’: 3D numpy array of same size as imagette1 or None,
’imagette2’: 3D numpy array, bigger or equal size to imagette1
- ’returnStatus’: int,
Describes success in extracting imagette1 and imagette2. If == 1 success, otherwise negative means failure.
- ’pixelSearchOffset’: 3-component list of ints
Coordinates of the top of the pixelSearch range in im1, i.e., the displacement that needs to be added to the raw pixelSearch output to make it a im1 -> im2 displacement
- Return type:
Dictionary
- spam.label.label.labelsOnEdges(lab)[source]#
Return labels on edges of volume
- Parameters:
lab (3D numpy array of ints) – Labelled volume
- Returns:
uniqueLabels – List of labels on edges
- Return type:
list of ints
- spam.label.label.removeLabels(lab, listOfLabelsToRemove)[source]#
Resets a list of labels to zero in a labelled volume.
- Parameters:
lab (3D numpy array of ints) – Labelled volume
listOfLabelsToRemove (list-like of ints) – Labels to remove
- Returns:
lab – Labelled volume with desired labels blanked
- Return type:
3D numpy array of ints
Note
You might want to use makeLabelsSequential after using this function, but don’t forget to recompute all your grain properties since the label numbers will change
- spam.label.label.setVoronoi(lab, poreEDT=None, maxPoreRadius=10)[source]#
This function computes an approximate set Voronoi for a given labelled image. This is a voronoi which does not have straight edges, and which necessarily passes through each contact point, so it is respectful of non-spherical grains.
See: Schaller, F. M., Kapfer, S. C., Evans, M. E., Hoffmann, M. J., Aste, T., Saadatfar, M., … & Schroder-Turk, G. E. (2013). Set Voronoi diagrams of 3D assemblies of aspherical particles. Philosophical Magazine, 93(31-33), 3993-4017. https://doi.org/10.1080/14786435.2013.834389
and
Weis, S., Schonhofer, P. W., Schaller, F. M., Schroter, M., & Schroder-Turk, G. E. (2017). Pomelo, a tool for computing Generic Set Voronoi Diagrams of Aspherical Particles of Arbitrary Shape. In EPJ Web of Conferences (Vol. 140, p. 06007). EDP Sciences.
- Parameters:
lab (3D numpy array of labelTypes) – Labelled image
poreEDT (3D numpy array of floats (optional, default = None)) – Euclidean distance map of the pores. If not given, it is computed by scipy.ndimage.distance_transform_edt
maxPoreRadius (int (optional, default = 10)) – Maximum pore radius to be considered (this threshold is for speed optimisation)
- Returns:
lab – Image labelled with set voronoi labels
- Return type:
3D numpy array of labelTypes
- spam.label.label.labelTetrahedra(dims, points, connectivity, nThreads=1)[source]#
Labels voxels corresponding to tetrahedra according to a connectivity matrix and node points
- Parameters:
dims (tuple representing z,y,x dimensions of the desired labelled output)
points (number of points x 3 array of floats) – List of points that define the vertices of the tetrahedra in Z,Y,X format. These points are referred to by line number in the connectivity array
connectivity (number of tetrahedra x 4 array of integers) – Connectivity matrix between points that define tetrahedra. Each line defines a tetrahedron whose number is the line number + 1. Each line contains 4 integers that indicate the 4 points in the nodePos array.
nThreads (int (optional, default=1)) – The number of threads used for the cpp parallelisation.
- Returns:
Labelled 3D volume where voxels are numbered according to the tetrahedron number they fall inside of # WARNING: Voxels outside of the mesh get a value of #tetrahedra + 1
- Return type:
3D array of ints, shape = dims
- spam.label.label.labelTetrahedraForScipyDelaunay(dims, delaunay)[source]#
Labels voxels corresponding to tetrahedra coming from scipy.spatial.Delaunay Apparently the cells are not well-numbered, which causes a number of zeros when using labelledTetrahedra
- Parameters:
dims (tuple) – represents z,y,x dimensions of the desired labelled output
delaunay ("delaunay" object) – Object returned by scipy.spatial.Delaunay( centres ) Hint: If using label.toolkit.centresOfMass( ), do centres[1:] to remove the position of zero.
- Returns:
lab – Labelled 3D volume where voxels are numbered according to the tetrahedron number they fall inside of
- Return type:
3D array of ints, shape = dims
- spam.label.label.filterIsolatedCells(array, struct, size)[source]#
Return array with completely isolated single cells removed
- Parameters:
array (3-D (labelled or binary) array) – Array with completely isolated single cells
struct (3-D binary array) – Structure array for generating unique regions
size (integer) – Size of the isolated cells to exclude (Number of Voxels)
- Returns:
filteredArray – Array with minimum region size > size
- Return type:
3-D (labelled or binary) array
Notes
function from: http://stackoverflow.com/questions/28274091/removing-completely-isolated-cells-from-python-array
- spam.label.label.trueSphericity(lab, boundingBoxes=None, centresOfMass=None, gaussianFilterSigma=0.75, minVol=256)[source]#
Calculates the degree of True Sphericity (psi) for all labels, as per: “Sphericity measures of sand grains” Rorato et al., Engineering Geology, 2019 and originlly proposed in: “Volume, shape, and roundness of rock particles”, Waddell, The Journal of Geology, 1932.
True Sphericity (psi) = Surface area of equivalent sphere / Actual surface area
The actual surface area is computed by extracting each particle with getLabel, a Gaussian smooth of 0.75 is applied and the marching cubes algorithm from skimage is used to mesh the surface and compute the surface area.
- Parameters:
lab (3D array of integers) – Labelled volume, with lab.max() labels
boundingBoxes (lab.max()x6 array of ints, optional) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
centresOfMass (lab.max()x3 array of floats, optional) – Centres of mass in format returned by
centresOfMass
. If not defined (Default = None), it is recomputed by runningcentresOfMass
gaussianFilterSigma (float, optional) – Sigma of the Gaussian filter used to smooth the binarised shape Default = 0.75
minVol (int, optional) – The minimum volume in vx to be treated, any object below this threshold is returned as 0 Default = 256 voxels
- Returns:
trueSphericity – The values of the degree of true sphericity for each particle
- Return type:
lab.max() array of floats
Notes
Function contributed by Riccardo Rorato (UPC Barcelona)
Due to numerical errors, this value can be >1, it should be clipped at 1.0
- spam.label.label.convexVolume(lab, boundingBoxes=None, centresOfMass=None, volumes=None, nProcesses=32, verbose=True)[source]#
This function compute the convex hull of each label of the labelled image and return a list with the convex volume of each particle.
- Parameters:
lab (3D array of integers) – Labelled volume, with lab.max() labels
boundingBoxes (lab.max()x6 array of ints, optional) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
centresOfMass (lab.max()x3 array of floats, optional) – Centres of mass in format returned by
centresOfMass
. If not defined (Default = None), it is recomputed by runningcentresOfMass
volumes (lab.max()x1 array of ints) – Volumes in format returned by
volumes
If not defined (Default = None), it is recomputed by runningvolumes
nProcesses (integer (optional, default = nProcessesDefault)) – Number of processes for multiprocessing Default = number of CPUs in the system
verbose (boolean (optional, default = False)) – True for printing the evolution of the process False for not printing the evolution of process
- Returns:
convexVolume
- Return type:
lab.max()x1 array of floats with the convex volume.
Note
convexVolume can only be computed for particles with volume greater than 3 voxels. If it is not the case, it will return 0.
- spam.label.label.moveLabels(lab, PhiField, returnStatus=None, boundingBoxes=None, centresOfMass=None, margin=3, PhiCOM=True, threshold=0.5, labelDilate=0, nProcesses=32)[source]#
This function applies a discrete Phi field (from DDIC?) over a labelled image.
- Parameters:
lab (3D numpy array) – Labelled image
PhiField ((multidimensional x 4 x 4 numpy array of floats)) – Spatial field of Phis
returnStatus (lab.max()x1 array of ints, optional) – Array with the return status for each label (usually returned by
spam-ddic
) If not defined (Default = None), all the labels will be moved If returnStatus[i] == 2, the label will be moved, otherwise is omitted and erased from the final imageboundingBoxes (lab.max()x6 array of ints, optional) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
centresOfMass (lab.max()x3 array of floats, optional) – Centres of mass in format returned by
centresOfMass
. If not defined (Default = None), it is recomputed by runningcentresOfMass
margin (int, optional) – Margin, in pixels, to take in each label. Default = 3
PhiCOM (bool, optional) – Apply Phi to centre of mass of particle?, otherwise it will be applied in the middle of the particle’s bounding box. Default = True
threshold (float, optional) – Threshold to keep interpolated voxels in the binary image. Default = 0.5
labelDilate (int, optional) – Number of times label should be dilated/eroded before returning it. If
labelDilate > 0
a dilated label is returned, whilelabelDilate < 0
returns an eroded label. Default = 0nProcesses (integer (optional, default = nProcessesDefault)) – Number of processes for multiprocessing Default = number of CPUs in the system
- Returns:
labOut – New labelled image with the labels moved by the deformations established by the PhiField.
- Return type:
3D numpy array
- spam.label.label.erodeLabels(lab, erosion=1, boundingBoxes=None, centresOfMass=None, nProcesses=32)[source]#
This function erodes a labelled image.
- Parameters:
lab (3D numpy array) – Labelled image
erosion (int, optional) – Erosion level
boundingBoxes (lab.max()x6 array of ints, optional) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
centresOfMass (lab.max()x3 array of floats, optional) – Centres of mass in format returned by
centresOfMass
. If not defined (Default = None), it is recomputed by runningcentresOfMass
nProcesses (integer (optional, default = nProcessesDefault)) – Number of processes for multiprocessing Default = number of CPUs in the system
- Returns:
erodeImage – New labelled image with the eroded labels.
- Return type:
3D numpy array
Note
The function makes use of spam.label.moveLabels() to generate the eroded image.
- spam.label.label.convexFillHoles(lab, boundingBoxes=None, centresOfMass=None)[source]#
This function fills the holes computing the convex volume around each label.
- Parameters:
lab (3D numpy array) – Labelled image
boundingBoxes (lab.max()x6 array of ints, optional) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
centresOfMass (lab.max()x3 array of floats, optional) – Centres of mass in format returned by
centresOfMass
. If not defined (Default = None), it is recomputed by runningcentresOfMass
- Returns:
labOut – New labelled image.
- Return type:
3D numpy array
Note
The function works nicely for convex particles. For non-convex particles, it will alter the shape.
- spam.label.label.getNeighbours(lab, listOfLabels, method='getLabel', neighboursRange=None, centresOfMass=None, boundingBoxes=None)[source]#
This function computes the neighbours for a list of labels.
- Parameters:
lab (3D numpy array) – Labelled image
listOfLabels (list of ints) – List of labels to which the neighbours will be computed
method (string) – Method to compute the neighbours. ‘getLabel’ : The neighbours are the labels inside the subset obtained through spam.getLabel() ‘mesh’ : The neighbours are computed using a tetrahedral connectivity matrix Default = ‘getLabel’
neighboursRange (int) – Parameter controlling the search range to detect neighbours for each method. For ‘getLabel’, it correspond to the size of the subset. Default = meanRadii For ‘mesh’, it correspond to the size of the alpha shape used for carving the mesh. Default = 5*meanDiameter.
boundingBoxes (lab.max()x6 array of ints, optional) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
centresOfMass (lab.max()x3 array of floats, optional) – Centres of mass in format returned by
centresOfMass
. If not defined (Default = None), it is recomputed by runningcentresOfMass
- Returns:
neighbours – List with the neighbours for each label in listOfLabels.
- Return type:
list
- spam.label.label.detectUnderSegmentation(lab, nProcesses=32, verbose=True)[source]#
This function computes the coefficient of undersegmentation for each particle, defined as the ratio of the convex volume and the actual volume.
- Parameters:
lab (3D numpy array) – Labelled image
nProcesses (integer (optional, default = nProcessesDefault)) – Number of processes for multiprocessing Default = number of CPUs in the system
verbose (boolean (optional, default = False)) – True for printing the evolution of the process
- Returns:
underSegCoeff – An array of float values that suggests the respective labels are undersegmentated.
- Return type:
lab.max() array of floats
Note
For perfect convex particles, any coefficient higher than 1 should be interpreted as a particle with undersegmentation problems. However, for natural materials the threshold to define undersegmentation varies. It is suggested to plot the histogram of the undersegmentation coefficient and select the threshold accordingly.
- spam.label.label.detectOverSegmentation(lab)[source]#
This function computes the coefficient of oversegmentation for each particle, defined as the ratio between a characteristic lenght of the maximum contact area and a characteristic length of the particle.
- Parameters:
lab (3D numpy array) – Labelled image
- Returns:
overSegCoeff (lab.max() array of floats) – An array of float values with the oversegmentation coefficient
sharedLabel (lab.max() array of floats) – Array of floats with the the oversegmentation coefficient neighbours - label that share the maximum contact area
Note
The threshold to define oversegmentation is dependent on each material and conditions of the test. It is suggested to plot the histogram of the oversegmentation coefficient and select the threshold accordingly.
- spam.label.label.fixUndersegmentation(lab, imGrey, targetLabels, underSegCoeff, boundingBoxes=None, centresOfMass=None, imShowProgress=False, verbose=True)[source]#
This function fixes undersegmentation problems, by performing a watershed with a higher local threshold for the problematic labels.
- Parameters:
lab (3D numpy array) – Labelled image
imGrey (3D numpy array) – Normalised greyscale of the labelled image, with a greyscale range between 0 and 1 and with void/solid peaks at 0.25 and 0.75, respectively. You can use helpers.histogramTools.findHistogramPeaks and helpers.histogramTools.histogramNorm to obtain a normalized greyscale image.
targetLabels (int or a list of labels) – List of target labels to solve undersegmentation
underSegCoeff (lab.max() array of floats) – Undersegmentation coefficient as returned by
detectUnderSegmentation
boundingBoxes (lab.max()x6 array of ints, optional) – Bounding boxes in format returned by
boundingBoxes
. If not defined (Default = None), it is recomputed by runningboundingBoxes
centresOfMass (lab.max()x3 array of floats, optional) – Centres of mass in format returned by
centresOfMass
. If not defined (Default = None), it is recomputed by running ``centresOfMass``boundingBoxes : 3D numpy array Labelled imageimShowProgress (bool, optional) – Graphical interface to observe the process for each label. Default = False
verbose (boolean (optional, default = False)) – True for printing the evolution of the process
- Returns:
lab – Labelled image after running
makeLabelsSequential
- Return type:
3D numpy array
- spam.label.label.fixOversegmentation(lab, targetLabels, sharedLabel, verbose=True, imShowProgress=False)[source]#
This function fixes oversegmentation problems, by merging each target label with its oversegmentation coefficient neighbour.
- Parameters:
lab (3D numpy array) – Labelled image
targetLabels (int or a list of labels) – List of target labels to solve oversegmentation
sharedLabel (lab.max() array of floats) – List ofoversegmentation coefficient neighbour as returned by
detectOverSegmentation
imShowProgress (bool, optional) – Graphical interface to observe the process for each label. Default = False
verbose (boolean (optional, default = False)) – True for printing the evolution of the process
- Returns:
lab – Labelled image after running
makeLabelsSequential
- Return type:
3D numpy array
- spam.label.label.shuffleLabels(lab)[source]#
This function re-assigns randomly the labels of a label image, usually for visualisation purposes.
- Parameters:
lab (3D array of integers) – Labelled volume, with lab.max() labels
- Returns:
lab – Labelled volume, with lab.max() labels
- Return type:
3D array of integers