Commit eb63e746 authored by Gustavo Pinzon's avatar Gustavo Pinzon
Browse files

New function spam.label.convexFillHoles(), test is missing

parent e0e261f5
Pipeline #50564 passed with stages
in 12 minutes and 43 seconds
......@@ -1878,4 +1878,90 @@ def erodeLabels(lab, erosion=1, boundingBoxes=None, centresOfMass=None, numberOf
labelDilate=-erosion,
numberOfThreads=numberOfThreads)
return erodeImage
def convexFillHoles(lab, boundingBoxes=None, centresOfMass=None):
"""
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 running ``boundingBoxes``
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``
Returns
--------
labOut : 3D numpy array
New labelled image.
Note
----
The function works nicely for convex particles. For non-convex particles, it will alter the shape.
"""
# Check for boundingBoxes
if boundingBoxes is None:
boundingBoxes = spam.label.boundingBoxes(lab)
# Check for centresOfMass
if centresOfMass is None:
centresOfMass = spam.label.centresOfMass(lab)
# Create output label image
labOut = numpy.zeros_like(lab, dtype=spam.label.labelType)
# Get number of labels
numberOfLabels = lab.max()
# Create progressbar
widgets = [progressbar.FormatLabel(''), ' ', progressbar.Bar(), ' ', progressbar.AdaptiveETA()]
pbar = progressbar.ProgressBar(widgets=widgets, maxval=numberOfLabels)
pbar.start()
for i in range(1,numberOfLabels+1,1):
# Get label
getLabelReturn = spam.label.getLabel(lab,
i,
labelDilate=0,
margin=3,
boundingBoxes=boundingBoxes,
centresOfMass=centresOfMass,
maskOtherLabels=False)
# Get subvolume
subVol = getLabelReturn['subvol']
# Transform to binary
subVolBinMask = (subVol > 0).astype(int)
# Mask out all the other labels
subVolBinMaskLabel = numpy.where(subVol == i, 1, 0).astype(int)
# Mask only the current label - save all the other labels
subVolMaskOtherLabel = subVolBinMask - subVolBinMaskLabel
# Fill holes with convex volume
points = numpy.transpose(numpy.where(subVolBinMaskLabel))
hull = scipy.spatial.ConvexHull(points)
deln = scipy.spatial.Delaunay(points[hull.vertices])
idx = numpy.stack(numpy.indices(subVol.shape), axis = -1)
out_idx = numpy.nonzero(deln.find_simplex(idx) + 1)
hullIm = numpy.zeros(subVol.shape)
hullIm[out_idx] = 1
hullIm = hullIm > 0
# Identify added voxels
subVolAdded = hullIm - subVolBinMaskLabel
# Identify the wrong voxels - they are inside other labels
subVolWrongAdded = subVolAdded * subVolMaskOtherLabel
# Remove wrong filling areas
subVolCorrect = (hullIm - subVolWrongAdded) > 0
# Get slice
grainSlice = (slice(getLabelReturn['slice'][0].start, getLabelReturn['slice'][0].stop),
slice(getLabelReturn['slice'][1].start, getLabelReturn['slice'][1].stop),
slice(getLabelReturn['slice'][2].start, getLabelReturn['slice'][2].stop))
# Add it to the output file
labOut[grainSlice][subVolCorrect] = i
# Update the progressbar
widgets[0] = progressbar.FormatLabel("{}/{} ".format(i, numberOfLabels))
pbar.update(i)
return labOut
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment