def rescaleAndWrite(filter, fileName): caster = itk.RescaleIntensityImageFilter[InternalImageType, OutputImageType].New( filter, OutputMinimum=0, OutputMaximum=255) itk.write(caster, fileName)
def rescaleAndWrite(filter, fileName): caster = itk.RescaleIntensityImageFilter[ InternalImageType, OutputImageType].New( filter, OutputMinimum=0, OutputMaximum=255) itk.write(caster, fileName)
def shellActiveContourWrapper(image1, seedList, contour, inputVolume): """ Performs level set operation that fills in a shell-shaped object. Parameters: image1: volume to guide the level set operation seedList: list of points from which operation will start contour: deprecated parameter inputVolume: deprecated parameter """ InternalPixelType = itk.F Dimension = 3 ImageType = itk.Image[InternalPixelType, Dimension] converter = itk.PyBuffer[ImageType] IT = itk.Image.F3 #img = IT.New(Regions=[inputVolume1.shape[2], inputVolume1.shape[1], inputVolume1.shape[0]]) #img.Allocate() #img.FillBuffer(0) InternalImageType = IT OutputImageType = IT # Writing and reading from file works around a WrapITK bug itk.write(image1, os.path.join(default_path.defaultOutputPath, "hello1.nrrd")) itk.write(image1, os.path.join(default_path.defaultOutputPath, "hello2.nrrd")) #seedPosition = numpyToItkPoint(center) # test code argv[1:] = ["O:\\images\\HPFcere_vol\\HPF_rotated_tif\\median_then_gaussian_8bit_classified_pixels\\median_then_gaussian_8bit_classified_pixels.nrrd", "o:\\temp\\fastmarch3d.nrrd", 81, 114, 1.0, -0.5, 3.0, 0.4, 0.4] if( len(argv) < 10 ): print >> stderr, """Missing Parameters Usage: FastMarchingImageFilter.py inputImage outputImage seedX seedY Sigma SigmoidAlpha SigmoidBeta TimeThreshold StoppingValue""" exit(1) #end of test code NodeType = itk.LevelSetNode[InternalPixelType, Dimension] NodeContainer = itk.VectorContainer[itk.UI, NodeType] itkSeedList = [] for point in seedList: itkSeedList.append(numpyToItkPoint(point)) resultItkArray = shellActiveContour(inputImage=image1, seedPoints=itkSeedList, #advectionScaling=80.0, advectionScaling=160.0, #curvatureScaling=0.75, curvatureScaling=6.75, dimensions=3, propagationScaling=1) #advectionScaling=20.0, #curvatureScaling=1.2, return resultItkArray
def rescaleAndWrite(filter, fileName): """Rescale and write ITK filter output to file.""" InternalPixelType = itk.F Dimension = 2 InternalImageType = itk.Image[InternalPixelType, Dimension] OutputPixelType = itk.UC OutputImageType = itk.Image[OutputPixelType, Dimension] caster = itk.RescaleIntensityImageFilter[InternalImageType, OutputImageType].New(filter, OutputMinimum=0, OutputMaximum=255) itk.write(caster, fileName)
# perform a simple binarization. Note that the Otsu filter does not use the same convention as usual : the white part is outside. otsu = itk.OtsuThresholdImageFilter[ImageType, ImageType].New(nuclei, OutsideValue=255, InsideValue=0) # split the nuclei maurer = itk.SignedMaurerDistanceMapImageFilter[ImageType, DistanceImageType].New(otsu) watershed = itk.MorphologicalWatershedImageFilter[DistanceImageType, ImageType].New(maurer, Level=60, MarkWatershedLine=False) mask = itk.MaskImageFilter[ImageType, ImageType, ImageType].New(watershed, otsu) # now switch to the label map representation and compute the attribute values, including the perimeter and the Feret diameter stats = itk.LabelImageToStatisticsLabelMapFilter[ImageType, ImageType, LabelMapType].New(mask, nuclei) # drop the objects too small to be a nucleus, and the ones on the border size = itk.ShapeOpeningLabelMapFilter[LabelMapType].New(stats, Attribute='Size', Lambda=100) border = itk.ShapeOpeningLabelMapFilter[LabelMapType].New(size, Attribute='SizeOnBorder', Lambda=10, ReverseOrdering=True) # reoder the labels. The objects with the highest mean are the first ones. relabel = itk.StatisticsRelabelLabelMapFilter[LabelMapType].New(border, Attribute='Mean') # for visual validation overlay = itk.LabelMapOverlayImageFilter[LabelMapType, ImageType, RGBImageType].New(relabel, nuclei) itk.write(overlay, "nuclei-overlay.png") spots = itk.ImageFileReader[ImageType].New(FileName="images/spots.png") # mask the spot image to keep only the nucleus zone. The rest of the image is cropped, excepted a border of 2 pixels maskSpots = itk.LabelMapMaskImageFilter[LabelMapType, ImageType].New(relabel, spots, Label=1, Crop=True, CropBorder=2) th = itk.BinaryThresholdImageFilter[ImageType, ImageType].New(maskSpots, LowerThreshold=110) sstats = itk.BinaryImageToStatisticsLabelMapFilter[ImageType, ImageType, LabelMapType].New(th, nuclei) # we know there are 4 spots in the nubleus, so keep the 4 biggest spots skeep = itk.ShapeKeepNObjectsLabelMapFilter[LabelMapType].New(sstats, Attribute='Size', NumberOfObjects=4) # reoder the labels. The bigger objects first. srelabel = itk.StatisticsRelabelLabelMapFilter[LabelMapType].New(skeep, Attribute='Size') # display the values we are interested in:
# # Copyright Insight Software Consortium # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0.txt # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #==========================================================================*/ # # Example on the use of the SmoothingRecursiveGaussianImageFilter # import itk from sys import argv itk.auto_progress(2) reader = itk.ImageFileReader.IUC2.New(FileName=argv[1]) filter = itk.SmoothingRecursiveGaussianImageFilter.New( reader, Sigma=eval(argv[3])) itk.write(filter, argv[2])
ellipse = itk.EllipseSpatialObject[dim].New(Radius=[10, 5]) ellipse.GetObjectToParentTransform().SetOffset([20, 20]) ellipse.ComputeObjectToWorldTransform() box = itk.BoxSpatialObject[dim].New(Size=20) box.GetObjectToParentTransform().SetOffset([20, 40]) box.ComputeObjectToWorldTransform() gaussian = itk.GaussianSpatialObject[dim].New(Radius=100) gaussian.GetObjectToParentTransform().SetOffset([60, 60]) gaussian.GetObjectToParentTransform().SetScale(10) gaussian.ComputeObjectToWorldTransform() group = itk.GroupSpatialObject[dim].New() group.AddSpatialObject(ellipse) group.AddSpatialObject(box) group.AddSpatialObject(gaussian) filter = itk.SpatialObjectToImageFilter[SOType, InternalImageType].New( group, Size=[100, 100], UseObjectValue=True) filter.Update() # required ?! rescale = itk.RescaleIntensityImageFilter[ InternalImageType, OutputImageType].New( filter, OutputMinimum=itk.NumericTraits[OutputPixelType].NonpositiveMin(), OutputMaximum=itk.NumericTraits[OutputPixelType].max()) itk.write(rescale, argv[1])
dim = 2 SOType = itk.SpatialObject[dim] InternalImageType = itk.Image[itk.F, dim] OutputPixelType = itk.UC OutputImageType = itk.Image[OutputPixelType, dim] ellipse = itk.EllipseSpatialObject[dim].New( Radius=[10,5] ) ellipse.GetObjectToParentTransform().SetOffset( [20,20] ) ellipse.ComputeObjectToWorldTransform() box = itk.BoxSpatialObject[dim].New( Size=20 ) box.GetObjectToParentTransform().SetOffset( [20,40] ) box.ComputeObjectToWorldTransform() gaussian = itk.GaussianSpatialObject[dim].New( Radius=100 ) gaussian.GetObjectToParentTransform().SetOffset( [60,60] ) gaussian.GetObjectToParentTransform().SetScale( 10 ) gaussian.ComputeObjectToWorldTransform() group = itk.GroupSpatialObject[dim].New() group.AddSpatialObject( ellipse.GetPointer() ) group.AddSpatialObject( box.GetPointer() ) group.AddSpatialObject( gaussian.GetPointer() ) filter = itk.SpatialObjectToImageFilter[SOType, InternalImageType].New( group, Size=[100,100], UseObjectValue=True ) filter.Update() # required ?! rescale = itk.RescaleIntensityImageFilter[InternalImageType, OutputImageType].New( filter, OutputMinimum=itk.NumericTraits[OutputPixelType].NonpositiveMin(), OutputMaximum=itk.NumericTraits[OutputPixelType].max() ) itk.write(rescale, argv[1])
if argv[2] == "Ball": print "Ball" strel = itk.FlatStructuringElement[2].Ball( int( argv[3] ) ) elif argv[2] == "Box": print "Box" strel = itk.FlatStructuringElement[2].Box( int( argv[3] ) ) elif argv[2] == "FromImage": print "FromImage" reader = itk.ImageFileReader.IUC2.New( FileName=argv[3] ) strel = itk.FlatStructuringElement[2].FromImageUC( reader.GetOutput() ) else: print "invalid arguement: " + argv[2] exit(1) img = strel.GetImageUC() size = itk.size( img ) for y in range(0, size.GetElement(1)): for x in range(0, size.GetElement(0)): if img.GetPixel( [x, y] ): print "X", else: print " ", print "\n", itk.write( img, argv[1] ) # writer = itk.ImageFileWriter.IUC2.New(FileName=argv[1], Input=img ) # itk.echo(writer) # writer.Update()
def fastMarch(image1, center, contour, inputVolume): """ Fast march. The fast march is seeded by every point of the contour. Returns fast march result. """ InternalPixelType = itk.F Dimension = 3 ImageType = itk.Image[InternalPixelType, Dimension] converter = itk.PyBuffer[ImageType] IT = itk.Image.F3 #img = IT.New(Regions=[inputVolume1.shape[2], inputVolume1.shape[1], inputVolume1.shape[0]]) #img.Allocate() #img.FillBuffer(0) InternalImageType = IT OutputImageType = IT # test code itk.write(image1, "/tmp/hello1.nrrd") itk.write(image1, "/tmp/hello2.nrrd") # end test code seedPosition = numpyToItkPoint(center) argv[1:] = ["O:\\images\\HPFcere_vol\\HPF_rotated_tif\\median_then_gaussian_8bit_classified_pixels\\median_then_gaussian_8bit_classified_pixels.nrrd", "o:\\temp\\fastmarch3d.nrrd", 81, 114, 1.0, -0.5, 3.0, 0.4, 0.4] if( len(argv) < 10 ): print >> stderr, """Missing Parameters Usage: FastMarchingImageFilter.py inputImage outputImage seedX seedY Sigma SigmoidAlpha SigmoidBeta TimeThreshold StoppingValue""" exit(1) CastFilterType = itk.RescaleIntensityImageFilter[ InternalImageType, OutputImageType ] SmoothingFilterType = itk.CurvatureAnisotropicDiffusionImageFilter[ InternalImageType, InternalImageType ] smoothing = SmoothingFilterType.New() GradientFilterType = itk.GradientMagnitudeRecursiveGaussianImageFilter[ InternalImageType, InternalImageType ] SigmoidFilterType = itk.SigmoidImageFilter[ InternalImageType, InternalImageType ] gradientMagnitude = GradientFilterType.New(); sigmoid = SigmoidFilterType.New() sigmoid.SetOutputMinimum( 0.0 ) sigmoid.SetOutputMaximum( 1.0 ) FastMarchingFilterType = itk.FastMarchingUpwindGradientImageFilter[ InternalImageType, InternalImageType ] NodeType = itk.LevelSetNode[InternalPixelType, Dimension] NodeContainer = itk.VectorContainer[itk.UI, NodeType] stopPoints = NodeContainer.New() for pointObject in contour.points(): stopPointNode = NodeType() stopPointNode.SetValue(0) #todo: is this needed stopPointNode.SetIndex(numpyToItkPoint(pointObject.loc)) stopPoints.InsertElement(0, stopPointNode) fastMarching = FastMarchingFilterType.New() fastMarching.SetTargetReachedModeToOneTarget() fastMarching.SetTargetOffset(0) fastMarching.SetTargetPoints(stopPoints) fastMarching.SetInput(image1) sigma = float( argv[5] ) gradientMagnitude.SetSigma( sigma ) alpha = float( argv[6] ) beta = float( argv[7] ) seeds = NodeContainer.New() node = NodeType() seedValue = 0.0 node.SetValue( seedValue ) node.SetIndex( seedPosition ) seeds.Initialize(); seeds.InsertElement( 0, node ) fastMarching.SetTrialPoints( seeds ); fastMarching.SetOutputSize(inputVolume.GetBufferedRegion().GetSize()) stoppingTime = float( argv[9] ) fastMarching.SetStoppingValue( stoppingTime ) print "update" fastMarching.Update() print "finished update" resultItkArray = fastMarching.GetOutput() return resultItkArray
def quickComputeFillFromEllipseCenters(inputVolume1, contourList, fillMethod): """ Uses shellActiveContourWrapper to perform level set initiated at all contours in contourList. Parameters: inputVolume1: guides the level set operation contourList: list of seed contours fillMethod: specifies the fill method, use 'shellActiveContour' """ global numpyBufferFromPyBufferClass global img InternalPixelType = itk.F Dimension = 3 ImageType = itk.Image[InternalPixelType, Dimension] converter = itk.PyBuffer[ImageType] IT = itk.Image.F3 img = IT.New(Regions=[inputVolume1.shape[2], inputVolume1.shape[1], inputVolume1.shape[0]]) img.Allocate() img.FillBuffer(0) InternalImageType = IT OutputImageType = IT numpyBufferFromPyBufferClass = itk.PyBuffer[IT].GetArrayFromImage(img) numpyBufferFromPyBufferClass[:, :, :] = inputVolume1 centerList = [] contourCount = 0 print "number of contours", len(contourList) erodedContoursNode = GroupNode('ErodedContours') #file = open("o:\\temp\\contours.txt", 'w') for contour in contourList: center = contour.bestFitEllipse.center #centerList.append(center) #print "starting erosion", contourCount #print dir(copy_module) #locations = copy_module.deepcopy(contour.locations()) #print locations #file.write(str(locations)) #print "number of points", len(locations) erodedContourSet = erosion.erosion_polygon(contour.locations(), 10) erodedContourSet = erodedContourSet +\ erosion.erosion_polygon(contour.locations(), 20) #print "completed erosion" for erodedContour in erodedContourSet: erodedContourObject = Contour() erodedContourObject.addNumpyPoints(erodedContour) erodedContoursNode.addObject(erodedContourObject) #for point in contour.locations(): for point in erodedContour: #centerList.append(((array(point) - array(center)) / 2.0) + array(center)) centerList.append(array(point)) contourCount += 1 #file.close() count = 0 #todo: check if this center variable needs to be here if len(contourList) > 0: center = contour.bestFitEllipse.center print "compute fill", count, "total", len(contourList) inputVolume = converter.GetImageFromArray(numpyBufferFromPyBufferClass) inputVolumeFileName = os.path.join(default_path.defaultOutputPath, "hello.nrrd") # Writing and reading from file works around a WrapITK bug itk.write(inputVolume, inputVolumeFileName) reader1 = itk.ImageFileReader[InternalImageType].New(FileName=inputVolumeFileName) image1 = reader1.GetOutput() if fillMethod == 'fastMarch': #resultItkArray = fastMarch(image1, center, contour, inputVolume) raise Exception, "not implemented" elif fillMethod == 'shellActiveContour': #resultItkArray = shellActiveContourWrapper(image1, centerList, contour, inputVolume) resultItkArray = shellActiveContourWrapper(image1, centerList, None, inputVolume) else: raise Exception, "Invalid fill method" tempFileName = os.path.join(default_path.defaultOutputPath, "fillResult.nrrd") print "writing file", tempFileName itk.write(resultItkArray, tempFileName) resultVolume = numpy.array(converter.GetArrayFromImage(resultItkArray)) if 1: #contour.features['fastMarchFromEllipseCenter'] = resultVolume blob = Blob() #binaryResult = resultVolume < 10000000 binaryResult = resultVolume < 0.5 if 0: print "starting flood fill" pointList = floodFill(binaryResult, center) print "flood fill finished" blob.setPoints(pointList) if count == 0: sumVolume = (1.0 * binaryResult) else: sumVolume += (1.0 * binaryResult) #contour.features['fastMarchBlobFromEllipseCenter'] = blob print "result volume" count += 1 return sumVolume, erodedContoursNode
def computeFillFromEllipseCenters(inputVolume1, contourList, fillMethod): """ Uses shellActiveContourWrapper to perform level set separately at each contour. Nolonger using this function. """ global numpyBufferFromPyBufferClass global img InternalPixelType = itk.F Dimension = 3 ImageType = itk.Image[InternalPixelType, Dimension] converter = itk.PyBuffer[ImageType] IT = itk.Image.F3 img = IT.New(Regions=[inputVolume1.shape[2], inputVolume1.shape[1], inputVolume1.shape[0]]) img.Allocate() img.FillBuffer(0) InternalImageType = IT OutputImageType = IT numpyBufferFromPyBufferClass = itk.PyBuffer[IT].GetArrayFromImage(img) numpyBufferFromPyBufferClass[:, :, :] = inputVolume1 count = 0 for contour in contourList: center = contour.bestFitEllipse.center print "compute fill", count, "total", len(contourList) inputVolume = converter.GetImageFromArray(numpyBufferFromPyBufferClass) inputVolumeFileName = os.path.join(default_path.defaultOutputPath, "hello.nrrd") # Writing and reading from file works around a WrapITK bug itk.write(inputVolume, inputVolumeFileName) reader1 = itk.ImageFileReader[InternalImageType].New(FileName=inputVolumeFileName) image1 = reader1.GetOutput() if fillMethod == 'fastMarch': resultItkArray = fastMarch(image1, center, contour, inputVolume) elif fillMethod == 'shellActiveContour': resultItkArray = shellActiveContourWrapper(image1, center, contour, inputVolume) else: raise Exception, "Invalid fill method" tempFileName = os.path.join(default_path.defaultOutputPath, "fillResult.nrrd") print "writing file", tempFileName itk.write(resultItkArray, tempFileName) resultVolume = numpy.array(converter.GetArrayFromImage(resultItkArray)) if 1: #contour.features['fastMarchFromEllipseCenter'] = resultVolume blob = Blob() #binaryResult = resultVolume < 10000000 binaryResult = resultVolume < 0.5 if 0: print "starting flood fill" pointList = floodFill(binaryResult, center) print "flood fill finished" blob.setPoints(pointList) if count == 0: sumVolume = (1.0 * binaryResult) else: sumVolume += (1.0 * binaryResult) #contour.features['fastMarchBlobFromEllipseCenter'] = blob print "result volume" count += 1 return sumVolume
def shellActiveContourWrapper_old(seedPositionNumpyArray, numpyTargetPointList): """Deprecated""" if 1: seedPosition = numpyToItkPoint(seedPositionNumpyArray) ImageType = itk.Image[itk.F, 3] converter = itk.PyBuffer[ImageType] print "fast march inputNumpyVolume", numpyBufferFromPyBufferClass inputVolume = converter.GetImageFromArray(numpyBufferFromPyBufferClass) print "fast march inputVolume", inputVolume itk.write(inputVolume, "/tmp/hello.nrrd") argv[1:] = ["O:\\images\\HPFcere_vol\\HPF_rotated_tif\\median_then_gaussian_8bit_classified_pixels\\median_then_gaussian_8bit_classified_pixels.nrrd", "o:\\temp\\fastmarch3d.nrrd", 81, 114, 1.0, -0.5, 3.0, 0.4, 0.4] if( len(argv) < 10 ): print >> stderr, """Missing Parameters Usage: FastMarchingImageFilter.py inputImage outputImage seedX seedY Sigma SigmoidAlpha SigmoidBeta TimeThreshold StoppingValue""" exit(1) InternalPixelType = itk.F Dimension = 3 InternalImageType = itk.Image[ InternalPixelType, Dimension ] OutputPixelType = itk.UC OutputImageType = itk.Image[ OutputPixelType, Dimension ] CastFilterType = itk.RescaleIntensityImageFilter[ InternalImageType, OutputImageType ] SmoothingFilterType = itk.CurvatureAnisotropicDiffusionImageFilter[ InternalImageType, InternalImageType ] smoothing = SmoothingFilterType.New() GradientFilterType = itk.GradientMagnitudeRecursiveGaussianImageFilter[ InternalImageType, InternalImageType ] SigmoidFilterType = itk.SigmoidImageFilter[ InternalImageType, InternalImageType ] gradientMagnitude = GradientFilterType.New(); sigmoid = SigmoidFilterType.New() sigmoid.SetOutputMinimum( 0.0 ) sigmoid.SetOutputMaximum( 1.0 ) FastMarchingFilterType = itk.FastMarchingUpwindGradientImageFilter[ InternalImageType, InternalImageType ] NodeType = itk.LevelSetNode[InternalPixelType, Dimension] NodeContainer = itk.VectorContainer[itk.UI, NodeType] numpyStopPointList = numpyTargetPointList stopPoints = NodeContainer.New() for pointObject in numpyStopPointList: stopPointNode = NodeType() stopPointNode.SetValue(0) #todo: is this needed stopPointNode.SetIndex(numpyToItkPoint(pointObject.loc)) stopPoints.InsertElement(0, stopPointNode) fastMarching = FastMarchingFilterType.New() fastMarching.SetTargetReachedModeToOneTarget() fastMarching.SetTargetOffset(0) fastMarching.SetTargetPoints(stopPoints) fastMarching.SetInput(inputVolume) sigma = float( argv[5] ) gradientMagnitude.SetSigma( sigma ) alpha = float( argv[6] ) beta = float( argv[7] ) seeds = NodeContainer.New() node = NodeType() seedValue = 0.0 node.SetValue( seedValue ) node.SetIndex( seedPosition ) seeds.Initialize(); seeds.InsertElement( 0, node ) fastMarching.SetTrialPoints( seeds ); fastMarching.SetOutputSize(inputVolume.GetBufferedRegion().GetSize()) stoppingTime = float( argv[9] ) fastMarching.SetStoppingValue( stoppingTime ) fastMarching.Update() resultItkArray = fastMarching.GetOutput() print "inputVolume2", inputVolume itk.write(inputVolume, "/tmp/result_something.nrrd")
def fastMarch_old(seedPositionNumpyArray, numpyTargetPointList): """Deprecated""" if 1: seedPosition = numpyToItkPoint(seedPositionNumpyArray) ImageType = itk.Image[itk.F, 3] converter = itk.PyBuffer[ImageType] #UCImageType = itk.Image[itk.UC, 3] #UCConverter = itk.PyBuffer[UCImageType] print "fast march inputNumpyVolume", numpyBufferFromPyBufferClass inputVolume = converter.GetImageFromArray(numpyBufferFromPyBufferClass) print "fast march inputVolume", inputVolume itk.write(inputVolume, "/tmp/hello.nrrd") #argv[1:] = ["O:\\software\\InsightToolkit-3.12.0\\Wrapping\\WrapITK\\images\\BrainProtonDensitySlice.png", "o:\\temp\\fastmarch2d.png", 81, 114, 1.0, -0.5, 3.0, 100, 100] #argv[1:] = ["O:\\temp\\3dvolume\\3d.nrrd", "o:\\temp\\fastmarch3d.nrrd", 81, 114, 1.0, -0.5, 3.0, 100, 100] #argv[1:] = ["O:\\images\\HPFcere_vol\\HPF_rotated_tif\\median_then_gaussian_filter.nrrd", "o:\\temp\\fastmarch3d.nrrd", 81, 114, 1.0, -0.5, 3.0, 100, 100] #argv[1:] = ["O:\\images\\HPFcere_vol\\HPF_rotated_tif\\median_then_gaussian_filter.nrrd", "o:\\temp\\fastmarch3d.nrrd", 81, 114, 1.0, -0.5, 3.0, 1, 1] #argv[1:] = ["O:\\images\\HPFcere_vol\\HPF_rotated_tif\\median_then_gaussian_8bit_classified_pixels\\median_then_gaussian_8bit_classified_pixels.nrrd", "o:\\temp\\fastmarch3d.nrrd", 81, 114, 1.0, -0.5, 3.0, 0.1, 0.1] argv[1:] = ["O:\\images\\HPFcere_vol\\HPF_rotated_tif\\median_then_gaussian_8bit_classified_pixels\\median_then_gaussian_8bit_classified_pixels.nrrd", "o:\\temp\\fastmarch3d.nrrd", 81, 114, 1.0, -0.5, 3.0, 0.4, 0.4] if( len(argv) < 10 ): print >> stderr, """Missing Parameters Usage: FastMarchingImageFilter.py inputImage outputImage seedX seedY Sigma SigmoidAlpha SigmoidBeta TimeThreshold StoppingValue""" exit(1) #itk.auto_progress(2) InternalPixelType = itk.F Dimension = 3 InternalImageType = itk.Image[ InternalPixelType, Dimension ] OutputPixelType = itk.UC OutputImageType = itk.Image[ OutputPixelType, Dimension ] CastFilterType = itk.RescaleIntensityImageFilter[ InternalImageType, OutputImageType ] SmoothingFilterType = itk.CurvatureAnisotropicDiffusionImageFilter[ InternalImageType, InternalImageType ] smoothing = SmoothingFilterType.New() GradientFilterType = itk.GradientMagnitudeRecursiveGaussianImageFilter[ InternalImageType, InternalImageType ] SigmoidFilterType = itk.SigmoidImageFilter[ InternalImageType, InternalImageType ] gradientMagnitude = GradientFilterType.New(); sigmoid = SigmoidFilterType.New() sigmoid.SetOutputMinimum( 0.0 ) sigmoid.SetOutputMaximum( 1.0 ) FastMarchingFilterType = itk.FastMarchingUpwindGradientImageFilter[ InternalImageType, InternalImageType ] #FastMarchingFilterType = itk.FastMarchingImageFilter[ InternalImageType, # InternalImageType ] NodeType = itk.LevelSetNode[InternalPixelType, Dimension] NodeContainer = itk.VectorContainer[itk.UI, NodeType] #numpyStopPointList = [array(seedPosition) + array([10,10,10])] numpyStopPointList = numpyTargetPointList #print numpyStopPointList stopPoints = NodeContainer.New() for pointObject in numpyStopPointList: stopPointNode = NodeType() stopPointNode.SetValue(0) #todo: is this needed stopPointNode.SetIndex(numpyToItkPoint(pointObject.loc)) stopPoints.InsertElement(0, stopPointNode) fastMarching = FastMarchingFilterType.New() fastMarching.SetTargetReachedModeToOneTarget() fastMarching.SetTargetOffset(0) fastMarching.SetTargetPoints(stopPoints) fastMarching.SetInput(inputVolume) sigma = float( argv[5] ) gradientMagnitude.SetSigma( sigma ) alpha = float( argv[6] ) beta = float( argv[7] ) ##sigmoid.SetAlpha( alpha ) ##sigmoid.SetBeta( beta ) seeds = NodeContainer.New() #seedPosition = [10, 10, 10] node = NodeType() seedValue = 0.0 node.SetValue( seedValue ) node.SetIndex( seedPosition ) #print "fastmarch seed position", seedPosition seeds.Initialize(); seeds.InsertElement( 0, node ) fastMarching.SetTrialPoints( seeds ); #fastMarching.SetOutputSize( # reader.GetOutput().GetBufferedRegion().GetSize() ) fastMarching.SetOutputSize(inputVolume.GetBufferedRegion().GetSize()) stoppingTime = float( argv[9] ) #stoppingTime = float(1000000) fastMarching.SetStoppingValue( stoppingTime ) #writer.Update() #return UCConverter.GetArrayFromImage(thresholder.GetOutput()) fastMarching.Update() resultItkArray = fastMarching.GetOutput() #itk.write(resultItkArray, "/tmp/result.nrrd") print "inputVolume2", inputVolume itk.write(inputVolume, "/tmp/result_something.nrrd")
# # Example on the use of the MeanImageFilter # import itk from sys import argv dim = 2 PixelType = itk.F ImageType = itk.Image[PixelType, dim] reader = itk.ImageFileReader[ImageType].New(FileName=argv[1]) fftFilter = itk.FFTWRealToComplexConjugateImageFilter[PixelType, dim].New(reader) fftFilter2 = itk.FFTWComplexConjugateToRealImageFilter[PixelType, dim].New(fftFilter) cast = itk.CastImageFilter[ImageType, itk.Image[itk.UC, dim]].New(fftFilter2) itk.write(cast, argv[2]) print itk.size(fftFilter).GetElement(0), itk.size(fftFilter).GetElement(1)
if argv[2] == "Ball": print "Ball" strel = itk.FlatStructuringElement[2].Ball(int(argv[3])) elif argv[2] == "Box": print "Box" strel = itk.FlatStructuringElement[2].Box(int(argv[3])) elif argv[2] == "FromImage": print "FromImage" reader = itk.ImageFileReader.IUC2.New(FileName=argv[3]) strel = itk.FlatStructuringElement[2].FromImageUC(reader.GetOutput()) else: print "invalid arguement: " + argv[2] exit(1) img = strel.GetImageUC() size = itk.size(img) for y in range(0, size.GetElement(1)): for x in range(0, size.GetElement(0)): if img.GetPixel([x, y]): print "X", else: print " ", print "\n", itk.write(img, argv[1]) # writer = itk.ImageFileWriter.IUC2.New(FileName=argv[1], Input=img ) # itk.echo(writer) # writer.Update()
#==========================================================================*/ # # Example on the use of the CannyEdgeDetectionImageFilter # from __future__ import print_function import itk from sys import argv, stderr, exit itk.auto_progress(2) if len(argv) < 3: print(("Usage: CannyEdgeDetectionImageFilter.py inputImage outputImage " "[variance]"), file=stderr) exit(1) variance = 2.0 if len(argv) > 3: variance = float(argv[3]) print(variance) reader = itk.ImageFileReader.IF2.New(FileName=argv[1]) filter = itk.CannyEdgeDetectionImageFilter.IF2IF2.New(reader, Variance=variance) outputCast = itk.RescaleIntensityImageFilter.IF2IUC2.New(filter, OutputMinimum=0, OutputMaximum=255) itk.write(outputCast, argv[2])
import itk input = '../../Testing/Data/Input/foot.mha' valt = itk.F imgt = itk.Image[valt, 2] reader = itk.ImageFileReader[imgt].New( FileName=input ) grad_io = itk.VTKImageIO.New() grad_io.SetPixelType( grad_io.VECTOR ) gradient_filter = itk.GradientImageFilter[ imgt, valt, valt ].New() gradient_filter.SetInput( reader.GetOutput() ) gradt = itk.output(gradient_filter) itk.write( gradient_filter, 'foot_GradientImageFilter.mha' ) gradient_mag_filter = itk.GradientToMagnitudeImageFilter[ gradt, imgt ].New() gradient_mag_filter.SetInput( gradient_filter.GetOutput() ) itk.write( gradient_mag_filter, 'foot_GradientImageFilter_magnitude.mha' ) dog_filter = itk.DifferenceOfGaussiansGradientImageFilter[ imgt, valt ].New() dog_filter.SetInput( reader.GetOutput() ) dog_filter.SetWidth( 1 ) itk.write( dog_filter, 'foot_DifferenceOfGaussiansGradientImageFilter.mha' ) dog_mag_filter = itk.GradientToMagnitudeImageFilter[ gradt, imgt ].New() dog_mag_filter.SetInput( dog_filter.GetOutput() ) itk.write( dog_mag_filter, 'foot_DifferenceOfGaussiansGradientImageFilter_magnitude.mha' )
def main(): if len(argv) < 10: errMsg = "Missing parameters\n" \ "Usage: %s\n" % (argv[0],) + \ " inputImage outputImage\n" \ " seedX seedY InitialDistance\n" \ " Sigma SigmoidAlpha SigmoidBeta\n" \ " PropagationScaling\n" print >> stderr, errMsg return # We're going to build the following pipelines: # 1. reader -> smoothing -> gradientMagnitude -> sigmoid -> FI # 2. fastMarching -> geodesicActiveContour(FI) -> thresholder -> writer # The output of pipeline 1 is a feature image that is used by the # geodesicActiveContour object. Also see figure 9.18 in the ITK # Software Guide. # we wan't to know what is happening # itk.auto_progress(True) InternalPixelType = itk.F Dimension = 2 InternalImageType = itk.Image[InternalPixelType, Dimension] OutputPixelType = itk.UC OutputImageType = itk.Image[OutputPixelType, Dimension] reader = itk.ImageFileReader[InternalImageType].New(FileName=argv[1]) # needed to give the size to the fastmarching filter reader.Update() smoothing = itk.CurvatureAnisotropicDiffusionImageFilter[ InternalImageType, InternalImageType].New(reader, TimeStep=0.125, NumberOfIterations=5, ConductanceParameter=9.0) gradientMagnitude = itk.GradientMagnitudeRecursiveGaussianImageFilter[ InternalImageType, InternalImageType].New(smoothing, Sigma=float(argv[6])) sigmoid = itk.SigmoidImageFilter[InternalImageType, InternalImageType].New( gradientMagnitude, OutputMinimum=0.0, OutputMaximum=1.1, Alpha=float(argv[7]), Beta=float(argv[8])) seedPosition = itk.Index[2]() seedPosition.SetElement(0, int(argv[3])) seedPosition.SetElement(1, int(argv[4])) node = itk.LevelSetNode[InternalPixelType, Dimension]() node.SetValue(-float(argv[5])) node.SetIndex(seedPosition) seeds = itk.VectorContainer[itk.UI, itk.LevelSetNode[InternalPixelType, Dimension]].New() seeds.Initialize() seeds.InsertElement(0, node) fastMarching = itk.FastMarchingImageFilter[ InternalImageType, InternalImageType].New( sigmoid, TrialPoints=seeds, SpeedConstant=1.0, OutputSize=reader.GetOutput().GetBufferedRegion().GetSize()) geodesicActiveContour = itk.GeodesicActiveContourLevelSetImageFilter[ InternalImageType, InternalImageType, InternalPixelType].New(fastMarching, sigmoid, PropagationScaling=float(argv[9]), CurvatureScaling=1.0, AdvectionScaling=1.0, MaximumRMSError=0.02, NumberOfIterations=800) thresholder = itk.BinaryThresholdImageFilter[InternalImageType, OutputImageType].New( geodesicActiveContour, LowerThreshold=-1000, UpperThreshold=0, OutsideValue=0, InsideValue=255) writer = itk.ImageFileWriter[OutputImageType].New(thresholder, FileName=argv[2]) def rescaleAndWrite(filter, fileName): caster = itk.RescaleIntensityImageFilter[InternalImageType, OutputImageType].New( filter, OutputMinimum=0, OutputMaximum=255) itk.write(caster, fileName) rescaleAndWrite(smoothing, "GeodesicActiveContourImageFilterOutput1.png") rescaleAndWrite(gradientMagnitude, "GeodesicActiveContourImageFilterOutput2.png") rescaleAndWrite(sigmoid, "GeodesicActiveContourImageFilterOutput3.png") rescaleAndWrite(fastMarching, "GeodesicActiveContourImageFilterOutput4.png") writer.Update() print print "Max. no. iterations: %d" % ( geodesicActiveContour.GetNumberOfIterations()) print "Max. RMS error: %.3f" % (geodesicActiveContour.GetMaximumRMSError()) print print "No. elapsed iterations: %d" % ( geodesicActiveContour.GetElapsedIterations()) print "RMS change: %.3f" % (geodesicActiveContour.GetRMSChange()) itk.write(fastMarching, "GeodesicActiveContourImageFilterOutput4.mha") itk.write(sigmoid, "GeodesicActiveContourImageFilterOutput3.mha") itk.write(gradientMagnitude, "GeodesicActiveContourImageFilterOutput2.mha")
v = int( rmaxRelabel[0].GetLabelObject(22).GetMaximum()/2 ) values = [rmaxRelabel[0].GetLabelObject(i+1).GetMaximum() for i in range(11)] # vmean = mean(values) / 4 # vmedian = median(values) / 4 th.SetLowerThreshold( int(vmedian) ) # auto crop filter is actually buggy - lets force it to see that the input has changed crop.Modified() # # visualisation obo2() result.ClearLabels() window.SetWindowMinimum(int(nucleus.GetMinimum())) window.SetWindowMaximum(int(nucleus.GetMaximum())) # for spot in bi2lm[0]: cog = spot.GetCenterOfGravity() idx = bi2lm[0].TransformPhysicalPointToIndex(cog) result2.SetPixel(idx, l) print '"'+inputFileName+'"', l, " ".join(str(i) for i in idx), " ".join(str(i) for i in cog) # result.PushLabelObject(obo2[0].GetLabelObject(spot.GetLabel())) # # push the nucleus shape to the result label map, to see the nucleus border in the image result.PushLabelObject(obo3.GetOutput().GetLabelObject(l)) # and write the result itk.write(overlay, inputFileName + "-%s.tif" % l) itk.write(result2, inputFileName + "-CENP.nrrd", True)
def main(): if len(argv) < 10: errMsg = "Missing parameters\n" \ "Usage: %s\n" % (argv[0],) + \ " inputImage outputImage\n" \ " seedX seedY InitialDistance\n" \ " Sigma SigmoidAlpha SigmoidBeta\n" \ " PropagationScaling\n" print >> stderr, errMsg return # We're going to build the following pipelines: # 1. reader -> smoothing -> gradientMagnitude -> sigmoid -> FI # 2. fastMarching -> geodesicActiveContour(FI) -> thresholder -> writer # The output of pipeline 1 is a feature image that is used by the # geodesicActiveContour object. Also see figure 9.18 in the ITK # Software Guide. # we wan't to know what is happening # itk.auto_progress(True) InternalPixelType = itk.F Dimension = 2 InternalImageType = itk.Image[InternalPixelType, Dimension] OutputPixelType = itk.UC OutputImageType = itk.Image[OutputPixelType, Dimension] reader = itk.ImageFileReader[InternalImageType].New(FileName=argv[1]) # needed to give the size to the fastmarching filter reader.Update() smoothing = itk.CurvatureAnisotropicDiffusionImageFilter[InternalImageType, InternalImageType].New(reader, TimeStep=0.125, NumberOfIterations=5, ConductanceParameter=9.0) gradientMagnitude = itk.GradientMagnitudeRecursiveGaussianImageFilter[InternalImageType, InternalImageType].New(smoothing, Sigma=float(argv[6])) sigmoid = itk.SigmoidImageFilter[InternalImageType, InternalImageType].New(gradientMagnitude, OutputMinimum=0.0, OutputMaximum=1.1, Alpha=float(argv[7]), Beta=float(argv[8])) seedPosition = itk.Index[2]() seedPosition.SetElement(0, int(argv[3])) seedPosition.SetElement(1, int(argv[4])) node = itk.LevelSetNode[InternalPixelType, Dimension]() node.SetValue(-float(argv[5])) node.SetIndex(seedPosition) seeds = itk.VectorContainer[itk.UI, itk.LevelSetNode[InternalPixelType, Dimension]].New() seeds.Initialize() seeds.InsertElement(0, node) fastMarching = itk.FastMarchingImageFilter[InternalImageType, InternalImageType].New(sigmoid, TrialPoints=seeds, SpeedConstant=1.0, OutputSize=reader.GetOutput().GetBufferedRegion().GetSize() ) geodesicActiveContour = itk.GeodesicActiveContourLevelSetImageFilter[InternalImageType, InternalImageType, InternalPixelType].New(fastMarching, sigmoid, PropagationScaling=float(argv[9]), CurvatureScaling=1.0, AdvectionScaling=1.0, MaximumRMSError=0.02, NumberOfIterations=800 ) thresholder = itk.BinaryThresholdImageFilter[InternalImageType, OutputImageType].New(geodesicActiveContour, LowerThreshold=-1000, UpperThreshold=0, OutsideValue=0, InsideValue=255) writer = itk.ImageFileWriter[OutputImageType].New(thresholder, FileName=argv[2]) def rescaleAndWrite(filter, fileName): caster = itk.RescaleIntensityImageFilter[InternalImageType, OutputImageType].New(filter, OutputMinimum=0, OutputMaximum=255) itk.write(caster, fileName) rescaleAndWrite(smoothing, "GeodesicActiveContourImageFilterOutput1.png") rescaleAndWrite(gradientMagnitude, "GeodesicActiveContourImageFilterOutput2.png") rescaleAndWrite(sigmoid, "GeodesicActiveContourImageFilterOutput3.png") rescaleAndWrite(fastMarching, "GeodesicActiveContourImageFilterOutput4.png") writer.Update() print print "Max. no. iterations: %d" % (geodesicActiveContour.GetNumberOfIterations()) print "Max. RMS error: %.3f" % (geodesicActiveContour.GetMaximumRMSError()) print print "No. elapsed iterations: %d" % (geodesicActiveContour.GetElapsedIterations()) print "RMS change: %.3f" % (geodesicActiveContour.GetRMSChange()) itk.write(fastMarching, "GeodesicActiveContourImageFilterOutput4.mha") itk.write(sigmoid, "GeodesicActiveContourImageFilterOutput3.mha") itk.write(gradientMagnitude, "GeodesicActiveContourImageFilterOutput2.mha")
# a function to produce a full image from a cropped label image def fullLabelImage( f ): padLabels.SetInput( f.GetOutput() ) lm2li.UpdateLargestPossibleRegion() i = lm2li.GetOutput() imgDuplicator = itk.ImageDuplicator[i].New(i) imgDuplicator.Update() return imgDuplicator.GetOutput() # the list to store the images of the wap and caseins spots caseins = [] waps = [] # v = itk.show(labels, MaxOpacity=0.05) itk.write(overlayNuclei, readerNuclei.GetFileName()+"-nuclei.tif") #, True) # let start, really statisticsLabelMapRobustNuclei.Update() shapeLabelMapNuclei.Update() otsuNuclei.Compute() if opts.visualValidation: padLabels.SetRegion( readerNuclei.GetOutput().GetLargestPossibleRegion() ) if opts.saveSegmentation: itk.write( labelRobustNuclei, readerNuclei.GetFileName()+"-nuclei-segmentation.nrrd", True)
# test strel # should work with the image type, an image instance or a filter # and should work with a list, a tuple, an int or an itk.Size for s in [2, (2, 2), [2, 2], itk.Size[2](2)] : st = itk.strel(dim, s) (tpl, param) = itk.template(st) assert tpl == itk.FlatStructuringElement assert param[0] == dim assert st.GetRadius().GetElement(0) == st.GetRadius().GetElement(1) == 2 # test size s = itk.size(reader) assert s.GetElement(0) == s.GetElement(1) == 256 s = itk.size(reader.GetOutput()) assert s.GetElement(0) == s.GetElement(1) == 256 s = itk.size(reader.GetOutput().GetPointer()) assert s.GetElement(0) == s.GetElement(1) == 256 # test range assert itk.range(reader) == (0, 255) assert itk.range(reader.GetOutput()) == (0, 255) assert itk.range(reader.GetOutput().GetPointer()) == (0, 255) # test write itk.write(reader, sys.argv[2])
seeds.Initialize() seeds.InsertElement(0, node) fastMarching.SetTrialPoints(seeds) fastMarching.SetOutputSize(reader.GetOutput().GetBufferedRegion().GetSize()) stoppingTime = float(argv[9]) fastMarching.SetStoppingValue(stoppingTime) writer.Update() # other outputs def rescaleAndWrite(filter, fileName): caster = itk.RescaleIntensityImageFilter[InternalImageType, OutputImageType].New( filter, OutputMinimum=0, OutputMaximum=255) itk.write(caster, fileName) rescaleAndWrite(smoothing, "FastMarchingFilterOutput1.png") rescaleAndWrite(gradientMagnitude, "FastMarchingFilterOutput2.png") rescaleAndWrite(sigmoid, "FastMarchingFilterOutput3.png") rescaleAndWrite(fastMarching, "FastMarchingFilterOutput4.png") #internal outputs itk.write(fastMarching, "FastMarchingFilterOutput4.mha") itk.write(sigmoid, "FastMarchingFilterOutput3.mha") itk.write(gradientMagnitude, "FastMarchingFilterOutput2.mha")
# # Example on the use of the MeanImageFilter # import itk from sys import argv dim = 2 PixelType = itk.F ImageType = itk.Image[PixelType, dim] reader = itk.ImageFileReader[ImageType].New( FileName=argv[1] ) fftFilter = itk.FFTWRealToComplexConjugateImageFilter[PixelType, dim].New(reader) fftFilter2 = itk.FFTWComplexConjugateToRealImageFilter[PixelType, dim].New(fftFilter) cast = itk.CastImageFilter[ImageType, itk.Image[itk.UC, dim]].New( fftFilter2 ) itk.write(cast, argv[2]) print itk.size(fftFilter).GetElement(0), itk.size(fftFilter).GetElement(1)
maskCENP.SetLabel( l ) # search the spots thCENP.SetLowerThreshold( 1 ) statsCENP.UpdateLargestPossibleRegion() while number_of_objects(statsCENP) > 44: thCENP.SetLowerThreshold( thCENP.GetLowerThreshold() + 1 ) statsCENP.Update() # some basic outputs about nuclei nucleusLabelObject = borderNuclei.GetOutput().GetLabelObject(l) print >> nucleiFile, '"'+readerNuclei.GetFileName()+'"', l, nucleusLabelObject.GetPhysicalSize(), nucleusLabelObject.GetRegionElongation(), number_of_objects(statsCENP), ' '.join([str(i) for i in itk.physical_point_to_index(borderNuclei, nucleusLabelObject.GetCentroid())]) for l2 in range(1, statsCENP.GetOutput().GetNumberOfLabelObjects()+1): lo = statsCENP.GetOutput().GetLabelObject(l2) cog = lo.GetCenterOfGravity() idx = itk.physical_point_to_index(cenpSpotsImg, cog) cenpSpotsImg.SetPixel(idx, 255) # copy label objects cplo = itk.StatisticsLabelObject.UL3.New() cplo.CopyDataFrom( lo ) cenpImg.PushLabelObject( cplo ) print >> genesFile, '"'+readerNuclei.GetFileName()+'"', l, " ".join(str(i) for i in idx), " ".join(str(i) for i in cog) if opts.saveSegmentation: itk.write(lm2iNuclei, readerNuclei.GetFileName()+"-nuclei.nrrd", True) itk.write(cenpSpotsImg, readerNuclei.GetFileName()+"-CENP.nrrd", True) if opts.visualValidation: itk.write(overlayNuclei, readerNuclei.GetFileName()+"-nuclei.tif") #, True) itk.write(overlayCENP, readerNuclei.GetFileName()+"-CENP.tif") #, True)
# # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #==========================================================================*/ # # Example on the use of the CannyEdgeDetectionImageFilter # import itk from sys import argv, stderr, exit itk.auto_progress(2) if len(argv) < 3: print >> stderr, "Usage: CannyEdgeDetectionImageFilter.py inputImage outputImage [variance]" exit(1) variance = 2.0 if len(argv) > 3: variance = float( argv[3] ) print variance reader = itk.ImageFileReader.IF2.New( FileName=argv[1] ) filter = itk.CannyEdgeDetectionImageFilter.IF2IF2.New( reader, Variance=variance ) outputCast = itk.RescaleIntensityImageFilter.IF2IUC2.New( filter, OutputMinimum=0, OutputMaximum=255 ) itk.write( outputCast, argv[2] )
stats = itk.LabelImageToStatisticsLabelMapFilter[ImageType, ImageType, LabelMapType].New( mask, nuclei) # drop the objects too small to be a nucleus, and the ones on the border size = itk.ShapeOpeningLabelMapFilter[LabelMapType].New(stats, Attribute='Size', Lambda=100) border = itk.ShapeOpeningLabelMapFilter[LabelMapType].New( size, Attribute='SizeOnBorder', Lambda=10, ReverseOrdering=True) # reoder the labels. The objects with the highest mean are the first ones. relabel = itk.StatisticsRelabelLabelMapFilter[LabelMapType].New( border, Attribute='Mean') # for visual validation overlay = itk.LabelMapOverlayImageFilter[LabelMapType, ImageType, RGBImageType].New(relabel, nuclei) itk.write(overlay, "nuclei-overlay.png") spots = itk.ImageFileReader[ImageType].New(FileName="images/spots.png") # mask the spot image to keep only the nucleus zone. The rest of the image is cropped, excepted a border of 2 pixels maskSpots = itk.LabelMapMaskImageFilter[LabelMapType, ImageType].New(relabel, spots, Label=1, Crop=True, CropBorder=2) th = itk.BinaryThresholdImageFilter[ImageType, ImageType].New(maskSpots, LowerThreshold=110) sstats = itk.BinaryImageToStatisticsLabelMapFilter[ImageType, ImageType, LabelMapType].New( th, nuclei)