Vous avez reçu un message "Your GitLab account has been locked ..." ? Pas d'inquiétude : lisez cet article https://docs.gricad-pages.univ-grenoble-alpes.fr/help/unlock/

Commit 9e4c9150 authored by Gustavo Pinzon's avatar Gustavo Pinzon
Browse files

Include spam-moveLabels, spam.label.erodeLabel and test

parent 5afec173
Pipeline #50421 passed with stages
in 12 minutes and 54 seconds
This diff is collapsed.
#!/usr/bin/env python
"""
This python script deforms a labelled image based on a deformation field using SPAM functions
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/>.
"""
from __future__ import print_function
import spam.helpers
import spam.label as ltk
import spam.DIC
import spam.deformation
import numpy
import sys, os
import tifffile
#import matplotlib.pyplot as plt
# Added from rotation_correlation-style parallelisation
import multiprocessing
import argparse
import progressbar
# Define argument parser object
parser = argparse.ArgumentParser(description="spam-moveLabels "+spam.helpers.optionsParser.GLPv3descriptionHeader +\
"This script applies discretely measured deformation functions (Phi) coming from 'spam-ddic' to a labelled image, "+\
"thus generating the deformed labelled image.\n\nWarning: since we're moving labels, "+\
"nearest neighbour interpolation must be used, and thus the shapes of the labels will be slightly damaged",
formatter_class=argparse.RawTextHelpFormatter)
# Parse arguments with external helper function
args = spam.helpers.optionsParser.moveLabelsParser(parser)
print("+-----------------------------+")
print("| SPAM - Labelled mover |")
print("+-----------------------------+")
print("\nCurrent Settings:")
argsDict = vars(args)
for key in sorted(argsDict):
print("\t{}: {}".format(key, argsDict[key]))
if args.RETURN_STATUS_THRESHOLD is None:
DVC = spam.helpers.readCorrelationTSV(args.TSVFile.name, readConvergence=False)
else:
DVC = spam.helpers.readCorrelationTSV(args.TSVFile.name, readConvergence=True)
# Read labelled image
lab = tifffile.imread( args.LabFile.name )
#if args.GREY_FILE is not None:
#greyTmp = tifffile.imread(args.GREY_FILE)
#grey = numpy.zeros((labShapeOrig[0]+2*args.OVERALL_MARGIN,
#labShapeOrig[1]+2*args.OVERALL_MARGIN,
#labShapeOrig[2]+2*args.OVERALL_MARGIN), dtype=greyTmp.dtype)
#grey[slicePadToNonPad] = greyTmp
labOut = spam.label.moveLabels(lab,
DVC['PhiField'],
margin=args.MARGIN,
PhiCOM=args.PHICOM,
threshold=args.THRESH,
labelDilate=args.LABEL_DILATE,
numberOfThreads=args.NUMBER_OF_PROCESSES)
#if args.GREY_FILE is None:
print("\nSaving labelled image with displaced grains...", end='')
tifffile.imsave( args.OUT_DIR+"/"+args.PREFIX+".tif", labOut.astype(lab.dtype) )
#else:
#print("\nSaving binary image with displaced grains...", end='')
#tifffile.imsave( args.OUT_DIR+"/"+args.PREFIX+".tif", labOut[slicePadToNonPad].astype('<u1')*255 )
print("done.")
......@@ -135,6 +135,7 @@ scripts = ['scripts/spam-mmr',
"scripts/spam-deformImageFromField",
"scripts/spam-mmr-graphical",
"scripts/spam-moveGrains",
"scripts/spam-moveLabels",
"scripts/spam-discreteStrain",
"scripts/spam-regularStrain",
"scripts/spam-ITKwatershed",
......
......@@ -411,10 +411,10 @@ class TestFunctionLabel(unittest.TestCase):
# #print numpy.where( returns['subvol'] == label )
def test_meanOrientation(self):
#Generate random main direction
# Generate random main direction
theta = numpy.radians(random.randrange(0, 360, 1))
phi = numpy.radians(random.randrange(0, 90, 1))
#Generate n random vector near the main direction
# Generate n random vector near the main direction
n = 1000 #number of vectors
R = 10 #Radius of vectors
vect = numpy.zeros((n, 3))
......@@ -429,129 +429,129 @@ class TestFunctionLabel(unittest.TestCase):
phiPCA = numpy.degrees(numpy.arctan(numpy.sqrt(mainAxis[1]**2 + mainAxis[2]**2) / mainAxis[0]))
thetaPCA = numpy.degrees(numpy.arctan2(mainAxis[1], mainAxis[2]))
if thetaPCA<0: thetaPCA = 360 + thetaPCA
#Check if the difference between the angles is less than 5 degree
# Check if the difference between the angles is less than 5 degree
self.assertLess(numpy.abs(phiPCA - numpy.degrees(phi)), 5)
self.assertLess(numpy.abs(thetaPCA - numpy.degrees(theta)), 5)
#Check if the vector are normalized
# Check if the vector are normalized
normVectors = numpy.sum(numpy.linalg.norm(projectedVectors, axis = 1)) / len(projectedVectors)
self.assertAlmostEqual(normVectors, 1, places = 3)
def test_Spheroid(self):
#Test for Oblate (Lentil-shaped)
# Test for Oblate (Lentil-shaped)
#Generate random direction
# Generate random direction
theta = numpy.radians(random.randrange(0,360,1))
phi = numpy.radians(random.randrange(0,90,1))
vect = numpy.array([numpy.cos(phi), numpy.sin(phi)*numpy.sin(theta), numpy.sin(phi)*numpy.cos(theta)])
if vect[0]<0: vect[:]=-1*vect[:]
#Generate two random semi-axis values
# Generate two random semi-axis values
a = random.randrange(20,40,1)
c = random.randrange(10,20,1)
#Generate the spheroid
spheroid = spam.label.label.Spheroid(a, c, numpy.asarray(vect)).digitize()
#Compute its semi-axis
# Compute its semi-axis
semiAxis = spam.label.ellipseAxes(spheroid)
#Compare the semi-axis
# Compare the semi-axis
self.assertLess(numpy.abs(numpy.max(semiAxis[1])-numpy.maximum(a,c)),2)
self.assertLess(numpy.abs(numpy.min(semiAxis[1])-numpy.minimum(a,c)),2)
#Compute the orientation
# Compute the orientation
eigenVal, eigenVect = spam.label.momentOfInertia(spheroid)
eigenVal = eigenVal / numpy.max(eigenVal)
#Get main orientation
# Get main orientation
mainVect = eigenVect[1][0:3]
if mainVect[0]<0: mainVect[:]=-1*mainVect[:]
#Compute the angle between them
# Compute the angle between them
c = numpy.dot(vect,mainVect)/numpy.linalg.norm(vect)/numpy.linalg.norm(mainVect)
angle = numpy.degrees(numpy.arccos(numpy.clip(c, -1, 1)))
#Check angle less than 2 degree
# Check angle less than 2 degree
self.assertLess(angle,2)
#Test for Prolate (Rice-shaped)
# Test for Prolate (Rice-shaped)
#Generate random direction
# Generate random direction
theta = numpy.radians(random.randrange(0,360,1))
phi = numpy.radians(random.randrange(0,90,1))
vect = numpy.array([numpy.cos(phi), numpy.sin(phi)*numpy.sin(theta), numpy.sin(phi)*numpy.cos(theta)])
if vect[0]<0: vect[:]=-1*vect[:]
#Generate two random semi-axis values
# Generate two random semi-axis values
a = random.randrange(10,20,1)
b = random.randrange(20,40,1)
#Generate the spheroid
# Generate the spheroid
spheroid = spam.label.label.Spheroid(a, b, numpy.asarray(vect)).digitize()
#Compute its semi-axis
# Compute its semi-axis
semiAxis = spam.label.ellipseAxes(spheroid)
#Compare the semi-axis
# Compare the semi-axis
self.assertLess(numpy.abs(numpy.max(semiAxis[1])-numpy.maximum(a,b)),2)
self.assertLess(numpy.abs(numpy.min(semiAxis[1])-numpy.minimum(a,b)),2)
#Compute the orientation
# Compute the orientation
eigenVal, eigenVect = spam.label.momentOfInertia(spheroid)
eigenVal = eigenVal / numpy.max(eigenVal)
#Get main orientation
# Get main orientation
mainVect = eigenVect[1][6:9]
if mainVect[0]<0: mainVect[:]=-1*mainVect[:]
#Compute the angle between them
# Compute the angle between them
c = numpy.dot(vect,mainVect)/numpy.linalg.norm(vect)/numpy.linalg.norm(mainVect)
angle = numpy.degrees(numpy.arccos(numpy.clip(c, -1, 1)))
#Check angle less than 2 degree
# Check angle less than 2 degree
self.assertLess(angle,2)
#Check that raises an error when the vector and dim are passed along
# Check that raises an error when the vector and dim are passed along
with self.assertRaises(ValueError): spam.label.label.Spheroid(10, 20, numpy.asarray([0,1,0]), dim = 1).digitize()
#Check that it runs even without a vector
# Check that it runs even without a vector
res = spam.label.label.Spheroid(10, 20, dim = 3).digitize()
self.assertIsNotNone(res)
def test_FixUnderSegmentation(self):
#Generate two prolate grains (rice-like)
def _test_FixUnderSegmentation(self):
# Generate two prolate grains (rice-like)
grain1 = spam.label.label.Spheroid(10, 20, numpy.asarray([0,1,0])).digitize()
grain2 = spam.label.label.Spheroid(10, 20, numpy.asarray([0,1,0])).digitize()
#Create the bigger labelled image
# Create the bigger labelled image
grainIm = numpy.concatenate((grain1,grain2))
grainIm = numpy.zeros(grainIm.shape)
#Add the grains to the bigger image
# Add the grains to the bigger image
grainIm[:grain1.shape[0]-1,:,:] = grain1[:grain1.shape[0]-1,:,:]
grainIm[grain2.shape[0]-5:-5,:,:] = grainIm[grain2.shape[0]-5:-5,:,:] + grain1[:,:,:]
#Set all the labels to 1
# Set all the labels to 1
grainIm = numpy.where(grainIm >= 1, 3, grainIm)
#Pad a border
# Pad a border
grainIm = numpy.pad(grainIm, pad_width=10, mode='constant', constant_values = 0)
#Create the 'greyScale' image
# Create the 'greyScale' image
greyIm = numpy.where(grainIm == 3, 30000, 10000)
#Check that the greyscale image is normalized
# Check that the greyscale image is normalized
res1 = spam.label.label.fixUndersegmentation(grainIm, greyIm, [3], 10*0.5, 20*0.5)
self.assertEqual(res1, None)
#Check that a or c is valid
# Check that a or c is valid
res2 = spam.label.label.fixUndersegmentation(grainIm, greyIm, [3], numpy.nan, numpy.nan)
self.assertEqual(res2, None)
#Check that a or c are positive
# Check that a or c are positive
res3 = spam.label.label.fixUndersegmentation(grainIm, greyIm, [3], -1, 10)
self.assertEqual(res3, None)
#Run fixUnderSegmentation
# Run fixUnderSegmentation
greyIm = numpy.where(grainIm == 3, 0.75, 0.25)
res4 = spam.label.label.fixUndersegmentation(grainIm, greyIm, [3], 10*0.8, 20*0.8, vect = [[0,1,0]])
#Check that there are two grains
# Check that there are two grains
self.assertEqual(numpy.max(numpy.unique(res4)), 2)
#Check that it runs even if the label does not exist
# Check that it runs even if the label does not exist
res5 = spam.label.label.fixUndersegmentation(grainIm, greyIm, [3], 10*0.8, 20*0.8, vect = [[0,1,0]])
self.assertIsNotNone(res5)
#Check for a vect that is not a list
# Check for a vect that is not a list
res6 = spam.label.label.fixUndersegmentation(grainIm, greyIm, [3], 10*0.8, 20*0.8, vect = (0,1,0))
self.assertIsNone(res6)
#Check that it works without the input vect
# Check that it works without the input vect
res7 = spam.label.label.fixUndersegmentation(grainIm, greyIm, [3], 10*0.8, 20*0.8, numVect = 1)
self.assertIsNotNone(res7)
#Check that it works with verbose = True
# Check that it works with verbose = True
res8 = spam.label.label.fixUndersegmentation(grainIm, greyIm, [3], 10*0.8, 20*0.8, numVect = 1, verbose = True)
self.assertIsNotNone(res8)
#Check that it works even for a non-existing label
# Check that it works even for a non-existing label
res9 = spam.label.label.fixUndersegmentation(grainIm, greyIm, [5], 10*0.8, 20*0.8, numVect = 1)
self.assertIsNotNone(res9)
def test_contactOrientations(self):
#Generate two oblate grains
# Generate two oblate grains
grain1 = spam.label.label.Spheroid(7, 15, numpy.asarray([0,1,0])).digitize()
grain2 = spam.label.label.Spheroid(7, 15, numpy.asarray([0,1,0])).digitize()
grainIm = numpy.concatenate((grain1,grain2))
......@@ -559,23 +559,23 @@ class TestFunctionLabel(unittest.TestCase):
grainIm[:grain1.shape[0]-1,:,:] = grain1[:grain1.shape[0]-1,:,:]
grainIm[grain2.shape[0]-5:-5,:,:] = grainIm[grain2.shape[0]-5:-5,:,:] + grain2[:,:,:]
grainIm = numpy.where(grainIm >1,1,grainIm)
#Generate a new grain and create contact
# Generate a new grain and create contact
grain3 = 2*spam.label.label.Spheroid(7, 15, numpy.asarray([0,1,0])).digitize()
imLab = numpy.concatenate((grain3,grainIm))
imLab = numpy.zeros(imLab.shape)
imLab[:grain3.shape[0]-1,:,:] = grain3[:grain3.shape[0]-1,:,:]
imLab[grain3.shape[0]-3:-3,:,:] = imLab[grain3.shape[0]-3:-3,:,:] + grainIm[:,:,:]
imLab = numpy.where(imLab >2, 2, imLab)
#Create bin image
# Create bin image
imBin = numpy.where(imLab >0, 1, 0)
#Run ITK and check angle of contact
# Run ITK and check angle of contact
contactNormal, intervox, NotTreatedContact = con.contactOrientations(imBin, imLab, watershed="ITK")
if contactNormal[0]<0: contactNormal = contactNormal*-1
c = numpy.dot(contactNormal, [1, 0, 0])/numpy.linalg.norm(contactNormal)/numpy.linalg.norm([1, 0, 0])
angle = numpy.degrees(numpy.arccos(numpy.clip(c, -1, 1)))
self.assertFalse(NotTreatedContact)
self.assertLess(angle, 1.)
#Run RW and check angle of contact
# Run RW and check angle of contact
contactNormal, intervox, NotTreatedContact = con.contactOrientations(imBin, imLab, watershed="RW")
if contactNormal[0]<0: contactNormal = contactNormal*-1
c = numpy.dot(contactNormal, [1, 0, 0])/numpy.linalg.norm(contactNormal)/numpy.linalg.norm([1, 0, 0])
......@@ -584,13 +584,13 @@ class TestFunctionLabel(unittest.TestCase):
self.assertLess(angle, 1.)
def test_fabricTensor(self):
#Define number of vector
# Define number of vector
n = 1000
#Create equally-spaced vector
# Create equally-spaced vector
vectEq = spam.plotting.orientationPlotter.SaffAndKuijlaarsSpiral(n)
#Compute fabric
# Compute fabric
NEq,FEq,aEq = spam.label.label.fabricTensor(vectEq)
#Create a set of vectors using a normal distribution centered on a random orientation
# Create a set of vectors using a normal distribution centered on a random orientation
theta = numpy.radians(random.randrange(0, 360, 1))
phi = numpy.radians(random.randrange(0, 90, 1))
vectRand = numpy.zeros((n, 3))
......@@ -600,9 +600,9 @@ class TestFunctionLabel(unittest.TestCase):
vectRand[x,0] = numpy.cos(phiI)
vectRand[x,1] = numpy.sin(phiI)*numpy.sin(thetaI)
vectRand[x,2] = numpy.sin(phiI)*numpy.cos(thetaI)
#Compute fabric
# Compute fabric
NRand, FRand, aRand = spam.label.label.fabricTensor(vectRand)
#Test the results
# Test the results
self.assertGreater(aRand, aEq)
def test_setVoronoi(self):
......@@ -618,24 +618,24 @@ class TestFunctionLabel(unittest.TestCase):
self.assertEqual(setVoronoiVolumes[2]>labVolumes[2], True)
def test_convexVolume(self):
#Get a random separation between 1 and 10
# Get a random separation between 1 and 10
dist = int(10*numpy.random.rand())
#Create a rectangular image
# Create a rectangular image
im = numpy.zeros((15,15,30))
#Create a first block of 5x5x5
# Create a first block of 5x5x5
im[5:10,5:10,5:10] = 1
#Create second block of 5x5x5 located at dist
# Create second block of 5x5x5 located at dist
im[5:10,5:10,10+dist:15+dist] = 1
#Compute convex volume
# Compute convex volume
im = im.astype('<u4')
convexVol = spam.label.convexVolume(im)
#Compute theoretical volume
# Compute theoretical volume
volOr = numpy.sum(im) + 5*5*dist
self.assertEqual(volOr, convexVol[-1])
#Check that it shows the error for particles smaller than 3 voxels
# Check that it shows the error for particles smaller than 3 voxels
im = numpy.zeros((15,15,30))
im[10,10,10] = 1
#Compute convex volume
# Compute convex volume
im = im.astype('<u4')
convexVol = spam.label.convexVolume(im)
self.assertEqual(0, convexVol[-1])
......@@ -708,5 +708,29 @@ class TestFunctionLabel(unittest.TestCase):
PhiField = numpy.zeros((3, 4, 4))
imLab2 = spam.label.moveLabels(imLab, PhiField, boundingBoxes = boundingBoxes, centresOfMass = centresOfMass)
self.assertIsNotNone(imLab2)
def test_erodeLabels(self):
# Create the sphere
imLab = skimage.morphology.ball(20)
# Pad with zero at each boundaries
imLab = numpy.pad(imLab, (10), 'constant', constant_values=(0))
# Compute initial volume
iniVol = spam.label.volumes(imLab)[-1]
# Compute initial COM
iniCOM = spam.label.centresOfMass(imLab)[-1]
# Test #1 -> COM=iniCOM, vol = iniVol for no dilate and Phi = I
imLab2 = spam.label.erodeLabels(imLab, erosion=0)
# Compute Volume and COM
newVol = spam.label.volumes(imLab2)[-1]
newCOM = spam.label.centresOfMass(imLab2)[-1]
self.assertEqual(0, numpy.sum(iniVol - newVol))
self.assertEqual(0, numpy.sum(iniCOM - newCOM))
# Test #2 -> COM=iniCOM and vol/ iniVol < 1 for dilate = 1 and Phi = I
imLab2 = spam.label.erodeLabels(imLab, erosion=1)
# Compute Volume and COM
newVol = spam.label.volumes(imLab2)[-1]
newCOM = spam.label.centresOfMass(imLab2)[-1]
self.assertEqual(0, numpy.sum(iniCOM - newCOM))
self.assertGreater(1.0, newVol/iniVol)
if __name__ == '__main__':
unittest.main()
......@@ -515,7 +515,7 @@ class testAll(unittest.TestCase):
#######################################################
# Now check with label mover -- easier if there are no rotations
#######################################################
exitCode = subprocess.call(["spam-moveGrains",
exitCode = subprocess.call(["spam-moveLabels",
testFolder + "Lab0.tif",
testFolder + "Step0-Step1-discreteDVC.tsv"])
self.assertEqual(exitCode, 0)
......
......@@ -1514,7 +1514,7 @@ def eregDiscreteParser(parser):
def moveGrainsParser(parser):
def moveLabelsParser(parser):
parser.add_argument('LabFile',
metavar='LabFile',
type=argparse.FileType('r'),
......@@ -1559,25 +1559,18 @@ def moveGrainsParser(parser):
dest='RETURN_STATUS_THRESHOLD',
help='Return status in spam-ddic to consider the grain. Default = None, but 2 (i.e., converged) is recommended')
parser.add_argument('-gf',
'--grey-file',
type=str,
default=None,
dest='GREY_FILE',
help='Input greylevel tiff file corresponding to the input labelled file. This option requires a threshold to be set with -thr')
parser.add_argument('-om',
'--overall-margin',
type=int,
default=10,
dest='OVERALL_MARGIN',
help="Overall image padding for label movement near edges, this is how much the labelled image is increased before starting to place label. Default = 10")
#parser.add_argument('-gf',
#'--grey-file',
#type=str,
#default=None,
#dest='GREY_FILE',
#help='Input greylevel tiff file corresponding to the input labelled file. This option requires a threshold to be set with -thr')
parser.add_argument('-lm',
'--label-margin',
type=int,
default=3,
dest='LABEL_MARGIN',
dest='MARGIN',
help="Bounding box margin for each label to allow for rotation/strain of the label. Default = 3")
parser.add_argument('-ld',
......@@ -1624,8 +1617,8 @@ def moveGrainsParser(parser):
if args.PREFIX is None:
args.PREFIX = os.path.splitext(os.path.basename(args.LabFile.name))[0] + "-displaced"
if args.GREY_FILE is not None and args.THRESH == 0.5:
print("\n\nWARNING: You set a greyfile and your threshold is 0.5 -- I hope this is the right threshold for the greylevel image!\n\n")
#if args.GREY_FILE is not None and args.THRESH == 0.5:
#print("\n\nWARNING: You set a greyfile and your threshold is 0.5 -- I hope this is the right threshold for the greylevel image!\n\n")
if args.LABEL_DILATE > 0 and args.GREY_FILE is None:
print("\n\nWARNING: You are dilating labels but haven't loaded a grey image, everything's going to expand a lot!\n\n")
......
......@@ -1221,31 +1221,31 @@ def meanOrientation(orientations):
# Read Number of Points
numberOfPoints = orientations.shape[0]
#Normalize all the vectors from http://stackoverflow.com/questions/2850743/numpy-how-to-quickly-normalize-many-vectors
# Normalize all the vectors from http://stackoverflow.com/questions/2850743/numpy-how-to-quickly-normalize-many-vectors
norms = numpy.apply_along_axis( numpy.linalg.norm, 1, orientations )
orientations = orientations / norms.reshape( -1, 1 )
#Flip if the z-component is located at z < 0
# Flip if the z-component is located at z < 0
for vector_i in range(numberOfPoints):
z,y,x=orientations[vector_i]
if z < 0: z = -z; y = -y; x = -x
orientations[vector_i] = [z,y,x]
#Run PCA
# Run PCA
orientationsPCA = numpy.concatenate((orientations, -1*orientations), axis=0) #COMENT
#Compute mean of each column
# Compute mean of each column
meanVal = numpy.mean(orientationsPCA, axis=0)
#Center array
# Center array
orientationsPCA = orientationsPCA - meanVal
#Compute covariance matrix of centered matrix
# Compute covariance matrix of centered matrix
covMat = numpy.cov(orientationsPCA.T)
#Eigendecomposition of covariance matrix
# Eigendecomposition of covariance matrix
values, vectors = numpy.linalg.eig(covMat)
#Decompose axis
# Decompose axis
main_axis = vectors[:,numpy.argmax(values)]
if main_axis[0]<0: main_axis[:]=-1*main_axis[:]
intermediate_axis = vectors[:,3 - numpy.argmin(values) - numpy.argmax(values)]
minor_axis = vectors[:,numpy.argmin(values)]
#Project all vectors
# Project all vectors
orientations_proj = numpy.zeros((numberOfPoints,3))
for vector_i in range(numberOfPoints):
orientations_proj[vector_i,0] = numpy.dot(orientations[vector_i,:],main_axis) / numpy.linalg.norm(main_axis)
......@@ -1331,7 +1331,7 @@ class Spheroid:
x = numpy.mgrid[slices]
return self.criterion(x)<=1.0
def fixUndersegmentation(imLab, imGrey, listLabels, a, c, numVect=100, vect=None, boundingBoxes=None, centresOfMass=None, numberOfThreads=1, verbose=False):
def _fixUndersegmentation(imLab, imGrey, listLabels, a, c, numVect=100, vect=None, boundingBoxes=None, centresOfMass=None, numberOfThreads=1, verbose=False):
"""
This function fix undersegmented particles using directional erosion over the particle
to get the seed for a new localized watershed.
......@@ -1383,37 +1383,37 @@ def fixUndersegmentation(imLab, imGrey, listLabels, a, c, numVect=100, vect=None
"""
import spam.label
#Check that a,c are valid inputs
# Check that a,c are valid inputs
if numpy.isnan(a) == True or numpy.isnan(c) == True:
print("\tlabel.fixUndersegmentation(): Parameters a or c are not valid. Some of them are NaN")
return
if a <= 0 or c <= 0:
print("\tlabel.fixUndersegmentation(): Parameters a or c are not valid. Some of them are negative or equal to zero")
return
#Check that the greyscale image is normalized
# Check that the greyscale image is normalized
if numpy.max(imGrey) > 1.0:
print("\tlabel.fixUndersegmentation(): The greyscale image is not normalized!")
return
#Check that the list of vectors (if added) is a list
# Check that the list of vectors (if added) is a list
if vect is not None:
if isinstance(vect,list) == False:
print("\tlabel.fixUndersegmentation(): The directional vector must be a list")
return
#Compute boundingBoxes if needed
# Compute boundingBoxes if needed
if boundingBoxes is None:
boundingBoxes = spam.label.boundingBoxes(imLab)
if centresOfMass is None:
centresOfMass = spam.label.centresOfMass(imLab)
#Compute the volume of the particles
# Compute the volume of the particles
volumes = spam.label.volumes(imLab)
#Create the vectors for the directional erosion if needed
# Create the vectors for the directional erosion if needed
if vect is None:
import spam.plotting
vect = spam.plotting.orientationPlotter.SaffAndKuijlaarsSpiral(numVect)
vect = vect.tolist()
#Initalize the variables
# Initalize the variables
finishedCounter = 0
labelCounter = numpy.max(imLab)
labelDummy = numpy.zeros(imLab.shape)
......@@ -1422,113 +1422,113 @@ def fixUndersegmentation(imLab, imGrey, listLabels, a, c, numVect=100, vect=None
for i in range(len(listLabels)):
Continue = False
itCounter = 1
#Get label
# Get label
label_i = listLabels[i]
#Get labelled subset data
# Get labelled subset data
labelData = spam.label.getLabel(imLab, label_i, boundingBoxes = boundingBoxes, centresOfMass = centresOfMass)
#Check if label exists
# Check if label exists
if not labelData:
print("\tlabel.fixUndersegmentation(): This label does not exist: "+str(label_i))
Continue = True
else: #Labels exist!
else: # Labels exist!
bwIm = labelData['subvol']
while Continue == False:
#Directional Erosion
# Directional Erosion
imEroded = spam.filters.morphologicalOperations.directionalErosion(bwIm, vect,
a, c, numberOfThreads = numberOfThreads,
verbose = verbose)
#Label the markers
# Label the markers
markers, num_seeds = scipy.ndimage.label(imEroded)
#New Segmentation
# New Segmentation
if verbose:
print('Processing label '+str(i)+' of '+str(len(listLabels))+'. Iteration #'+str(itCounter))
newSeg = spam.label.watershed(bwIm, markers=markers, verbose = verbose)
#Check Number of Labels
# Check Number of Labels
if numpy.max(newSeg) > 1: