def openSurfaceAtPoint( self, polyData, seed ): ''' Returns a new surface with an opening at the given seed. ''' someradius = 1.0 pointLocator = vtk.vtkPointLocator() pointLocator.SetDataSet( polyData ) pointLocator.BuildLocator() # find the closest point next to the seed on the surface # id = pointLocator.FindClosestPoint(int(seed[0]),int(seed[1]),int(seed[2])) id = pointLocator.FindClosestPoint( seed ) # the seed is now guaranteed on the surface seed = polyData.GetPoint( id ) sphere = vtk.vtkSphere() sphere.SetCenter( seed[0], seed[1], seed[2] ) sphere.SetRadius( someradius ) clip = vtk.vtkClipPolyData() clip.SetInputData( polyData ) clip.SetClipFunction( sphere ) clip.Update() outPolyData = vtk.vtkPolyData() outPolyData.DeepCopy( clip.GetOutput() ) return outPolyData
def openSurfaceAtPoint(self, polyData, seed): ''' Returns a new surface with an opening at the given seed. ''' someradius = 1.0 pointLocator = vtk.vtkPointLocator() pointLocator.SetDataSet(polyData) pointLocator.BuildLocator() # find the closest point next to the seed on the surface #id = pointLocator.FindClosestPoint(int(seed[0]),int(seed[1]),int(seed[2])) id = pointLocator.FindClosestPoint(seed) # the seed is now guaranteed on the surface seed = polyData.GetPoint(id) sphere = vtk.vtkSphere() sphere.SetCenter(seed[0], seed[1], seed[2]) sphere.SetRadius(someradius) clip = vtk.vtkClipPolyData() clip.SetInput(polyData) clip.SetClipFunction(sphere) clip.Update() outPolyData = vtk.vtkPolyData() outPolyData.DeepCopy(clip.GetOutput()) outPolyData.Update() return outPolyData
def addModelPointLocator(self, name, polydata): if not name in self.pointLocatorDictionary: print "Adding point locator: {0}".format(name) pointLocator = vtk.vtkPointLocator() pointLocator.SetDataSet(polydata) pointLocator.AutomaticOn() pointLocator.BuildLocator() self.pointLocatorDictionary[name] = pointLocator
def __init__(self): self.controlPointsMarkupNode = None self.curveModelNode = None self.tubeRadius = 5.0 self.tubeResolution = 20 self.numberOfIntermediatePoints = 20 self.curvePoly = vtk.vtkPolyData() self.curvePoints = vtk.vtkPoints() self.curvePoly.SetPoints(self.curvePoints) self.curvePointsLocator = vtk.vtkPointLocator() self.curvePointsLocator.SetDataSet(self.curvePoly) self.interpolationMethod = InterpolationLinear self.pointInterpolationFunction = self.getInterpolatedPointsLinear self.closed = False
def start( self, preview=False ): ''' ''' SlicerVmtk4CommonLib.Helper.Debug( "Starting Centerline Computation.." ) # first we need the nodes currentModelNode = self.__inputModelNodeSelector.currentNode() currentSeedsNode = self.__seedFiducialsNodeSelector.currentNode() currentOutputModelNode = self.__outputModelNodeSelector.currentNode() currentVoronoiModelNode = self.__voronoiModelNodeSelector.currentNode() if not currentModelNode: # we need a input volume node return 0 if not currentSeedsNode: # we need a seeds node return 0 if not currentOutputModelNode or currentOutputModelNode.GetID() == currentModelNode.GetID(): # we need a current model node, the display node is created later newModelNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelNode" ) newModelNode.SetScene( slicer.mrmlScene ) newModelNode.SetName( slicer.mrmlScene.GetUniqueNameByString( self.__outputModelNodeSelector.baseName ) ) slicer.mrmlScene.AddNode( newModelNode ) currentOutputModelNode = newModelNode self.__outputModelNodeSelector.setCurrentNode( currentOutputModelNode ) if not currentVoronoiModelNode or currentVoronoiModelNode.GetID() == currentModelNode.GetID() or currentVoronoiModelNode.GetID() == currentOutputModelNode.GetID(): # we need a current model node, the display node is created later newModelNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelNode" ) newModelNode.SetScene( slicer.mrmlScene ) newModelNode.SetName( slicer.mrmlScene.GetUniqueNameByString( self.__voronoiModelNodeSelector.baseName ) ) slicer.mrmlScene.AddNode( newModelNode ) currentVoronoiModelNode = newModelNode self.__voronoiModelNodeSelector.setCurrentNode( currentVoronoiModelNode ) # the output models preparedModel = vtk.vtkPolyData() model = vtk.vtkPolyData() network = vtk.vtkPolyData() voronoi = vtk.vtkPolyData() currentCoordinatesRAS = [0, 0, 0] # grab the current coordinates currentSeedsNode.GetFiducialCoordinates( currentCoordinatesRAS ) # prepare the model preparedModel.DeepCopy( self.GetLogic().prepareModel( currentModelNode.GetPolyData() ) ) preparedModel.Update() # decimate the model (only for network extraction) model.DeepCopy( self.GetLogic().decimateSurface( preparedModel ) ) model.Update() # open the model at the seed (only for network extraction) model.DeepCopy( self.GetLogic().openSurfaceAtPoint( model, currentCoordinatesRAS ) ) model.Update() # extract Network network.DeepCopy( self.GetLogic().extractNetwork( model ) ) network.Update() # # # not preview mode: real computation! if not preview: # here we start the actual centerline computation which is mathematically more robust and accurate but takes longer than the network extraction # clip surface at endpoints identified by the network extraction tupel = self.GetLogic().clipSurfaceAtEndPoints( network, currentModelNode.GetPolyData() ) clippedSurface = tupel[0] endpoints = tupel[1] # now find the one endpoint which is closest to the seed and use it as the source point for centerline computation # all other endpoints are the target points sourcePoint = [0, 0, 0] # the following arrays have the same indexes and are synchronized at all times distancesToSeed = [] targetPoints = [] # we now need to loop through the endpoints two times # first loop is to detect the endpoint resulting in the tiny hole we poked in the surface # this is very close to our seed but not the correct sourcePoint for i in range( endpoints.GetNumberOfPoints() ): currentPoint = endpoints.GetPoint( i ) # get the euclidean distance currentDistanceToSeed = math.sqrt( math.pow( ( currentPoint[0] - currentCoordinatesRAS[0] ), 2 ) + math.pow( ( currentPoint[1] - currentCoordinatesRAS[1] ), 2 ) + math.pow( ( currentPoint[2] - currentCoordinatesRAS[2] ), 2 ) ) targetPoints.append( currentPoint ) distancesToSeed.append( currentDistanceToSeed ) # now we have a list of distances with the corresponding points # the index with the most minimal distance is the holePoint, we want to ignore it # the index with the second minimal distance is the point closest to the seed, we want to set it as sourcepoint # all other points are the targetpoints # get the index of the holePoint, which we want to remove from our endPoints holePointIndex = distancesToSeed.index( min( distancesToSeed ) ) # .. and remove it distancesToSeed.pop( holePointIndex ) targetPoints.pop( holePointIndex ) # now find the sourcepoint sourcePointIndex = distancesToSeed.index( min( distancesToSeed ) ) # .. and remove it after saving it as the sourcePoint sourcePoint = targetPoints[sourcePointIndex] distancesToSeed.pop( sourcePointIndex ) targetPoints.pop( sourcePointIndex ) # again, at this point we have a) the sourcePoint and b) a list of real targetPoints # now create the sourceIdList and targetIdList for the actual centerline computation sourceIdList = vtk.vtkIdList() targetIdList = vtk.vtkIdList() pointLocator = vtk.vtkPointLocator() pointLocator.SetDataSet( preparedModel ) pointLocator.BuildLocator() # locate the source on the surface sourceId = pointLocator.FindClosestPoint( sourcePoint ) sourceIdList.InsertNextId( sourceId ) f = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLAnnotationFiducialNode" ) f.SetFiducialCoordinates( sourcePoint ) f.Initialize( slicer.mrmlScene ) f.SelectedOn() # locate the endpoints on the surface for p in targetPoints: f = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLAnnotationFiducialNode" ) f.SetFiducialCoordinates( p ) f.Initialize( slicer.mrmlScene ) id = pointLocator.FindClosestPoint( p ) targetIdList.InsertNextId( id ) tupel = self.GetLogic().computeCenterlines( preparedModel, sourceIdList, targetIdList ) network.DeepCopy( tupel[0] ) voronoi.DeepCopy( tupel[1] ) # # # update the display of the original model in terms of opacity currentModelDisplayNode = currentModelNode.GetDisplayNode() if not currentModelDisplayNode: # create new displayNode currentModelDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelDisplayNode" ) slicer.mrmlScene.AddNode( currentModelDisplayNode ) currentModelDisplayNode.SetOpacity( 0.4 ) currentModelDisplayNode.Modified() currentModelDisplayNode.SetModifiedSinceRead( 1 ) # update the reference between model node and it's display node currentModelNode.SetAndObserveDisplayNodeID( currentModelDisplayNode.GetID() ) currentModelNode.Modified() currentModelNode.SetModifiedSinceRead( 1 ) # # finally: # propagate output model to nodes currentOutputModelNode.SetAndObservePolyData( network ) currentOutputModelNode.Modified() currentOutputModelNode.SetModifiedSinceRead( 1 ) currentOutputModelDisplayNode = currentOutputModelNode.GetDisplayNode() if not currentOutputModelDisplayNode: # create new displayNode currentOutputModelDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelDisplayNode" ) slicer.mrmlScene.AddNode( currentOutputModelDisplayNode ) # always configure the displayNode to show the model currentOutputModelDisplayNode.SetPolyData( currentOutputModelNode.GetPolyData() ) currentOutputModelDisplayNode.SetColor( 0.0, 0.0, 0.4 ) # red currentOutputModelDisplayNode.SetBackfaceCulling( 0 ) currentOutputModelDisplayNode.SetSliceIntersectionVisibility( 0 ) currentOutputModelDisplayNode.SetVisibility( 1 ) currentOutputModelDisplayNode.SetOpacity( 1.0 ) currentOutputModelDisplayNode.Modified() currentOutputModelDisplayNode.SetModifiedSinceRead( 1 ) # update the reference between model node and it's display node currentOutputModelNode.SetAndObserveDisplayNodeID( currentOutputModelDisplayNode.GetID() ) currentOutputModelNode.Modified() currentOutputModelNode.SetModifiedSinceRead( 1 ) # only update the voronoi node if we are not in preview mode if not preview: currentVoronoiModelNode.SetAndObservePolyData( voronoi ) currentVoronoiModelNode.Modified() currentVoronoiModelNode.SetModifiedSinceRead( 1 ) currentVoronoiModelDisplayNode = currentVoronoiModelNode.GetDisplayNode() if not currentVoronoiModelDisplayNode: # create new displayNode currentVoronoiModelDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelDisplayNode" ) slicer.mrmlScene.AddNode( currentVoronoiModelDisplayNode ) # always configure the displayNode to show the model currentVoronoiModelDisplayNode.SetPolyData( currentVoronoiModelNode.GetPolyData() ) currentVoronoiModelDisplayNode.SetScalarVisibility( 1 ) currentVoronoiModelDisplayNode.SetBackfaceCulling( 0 ) currentVoronoiModelDisplayNode.SetActiveScalarName( "Radius" ) currentVoronoiModelDisplayNode.SetAndObserveColorNodeID( slicer.mrmlScene.GetNodesByName( "Labels" ).GetItemAsObject( 0 ).GetID() ) currentVoronoiModelDisplayNode.SetSliceIntersectionVisibility( 0 ) currentVoronoiModelDisplayNode.SetVisibility( 1 ) currentVoronoiModelDisplayNode.SetOpacity( 0.5 ) currentVoronoiModelDisplayNode.Modified() currentVoronoiModelDisplayNode.SetModifiedSinceRead( 1 ) # update the reference between model node and it's display node currentVoronoiModelNode.SetAndObserveDisplayNodeID( currentVoronoiModelDisplayNode.GetID() ) currentVoronoiModelNode.Modified() currentVoronoiModelNode.SetModifiedSinceRead( 1 ) SlicerVmtk4CommonLib.Helper.Debug( "End of Centerline Computation.." )
def start(self, preview=False): ''' ''' SlicerVmtk4CommonLib.Helper.Debug("Starting Centerline Computation..") # first we need the nodes currentModelNode = self.__inputModelNodeSelector.currentNode() currentSeedsNode = self.__seedFiducialsNodeSelector.currentNode() currentOutputModelNode = self.__outputModelNodeSelector.currentNode() currentVoronoiModelNode = self.__voronoiModelNodeSelector.currentNode() if not currentModelNode: # we need a input volume node return 0 if not currentSeedsNode: # we need a seeds node return 0 if not currentOutputModelNode or currentOutputModelNode.GetID( ) == currentModelNode.GetID(): # we need a current model node, the display node is created later newModelNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelNode") newModelNode.SetScene(slicer.mrmlScene) newModelNode.SetName( slicer.mrmlScene.GetUniqueNameByString( self.__outputModelNodeSelector.baseName)) slicer.mrmlScene.AddNode(newModelNode) currentOutputModelNode = newModelNode self.__outputModelNodeSelector.setCurrentNode( currentOutputModelNode) if not currentVoronoiModelNode or currentVoronoiModelNode.GetID( ) == currentModelNode.GetID() or currentVoronoiModelNode.GetID( ) == currentOutputModelNode.GetID(): # we need a current model node, the display node is created later newModelNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelNode") newModelNode.SetScene(slicer.mrmlScene) newModelNode.SetName( slicer.mrmlScene.GetUniqueNameByString( self.__voronoiModelNodeSelector.baseName)) slicer.mrmlScene.AddNode(newModelNode) currentVoronoiModelNode = newModelNode self.__voronoiModelNodeSelector.setCurrentNode( currentVoronoiModelNode) # the output models preparedModel = vtk.vtkPolyData() model = vtk.vtkPolyData() network = vtk.vtkPolyData() voronoi = vtk.vtkPolyData() currentCoordinatesRAS = [0, 0, 0] # grab the current coordinates currentSeedsNode.GetFiducialCoordinates(currentCoordinatesRAS) # prepare the model preparedModel.DeepCopy(self.GetLogic().prepareModel( currentModelNode.GetPolyData())) preparedModel.Update() # decimate the model (only for network extraction) model.DeepCopy(self.GetLogic().decimateSurface(preparedModel)) model.Update() # open the model at the seed (only for network extraction) model.DeepCopy(self.GetLogic().openSurfaceAtPoint( model, currentCoordinatesRAS)) model.Update() # extract Network network.DeepCopy(self.GetLogic().extractNetwork(model)) network.Update() # # # not preview mode: real computation! if not preview: # here we start the actual centerline computation which is mathematically more robust and accurate but takes longer than the network extraction # clip surface at endpoints identified by the network extraction tupel = self.GetLogic().clipSurfaceAtEndPoints( network, currentModelNode.GetPolyData()) clippedSurface = tupel[0] endpoints = tupel[1] # now find the one endpoint which is closest to the seed and use it as the source point for centerline computation # all other endpoints are the target points sourcePoint = [0, 0, 0] # the following arrays have the same indexes and are synchronized at all times distancesToSeed = [] targetPoints = [] # we now need to loop through the endpoints two times # first loop is to detect the endpoint resulting in the tiny hole we poked in the surface # this is very close to our seed but not the correct sourcePoint for i in range(endpoints.GetNumberOfPoints()): currentPoint = endpoints.GetPoint(i) # get the euclidean distance currentDistanceToSeed = math.sqrt( math.pow((currentPoint[0] - currentCoordinatesRAS[0]), 2) + math.pow((currentPoint[1] - currentCoordinatesRAS[1]), 2) + math.pow((currentPoint[2] - currentCoordinatesRAS[2]), 2)) targetPoints.append(currentPoint) distancesToSeed.append(currentDistanceToSeed) # now we have a list of distances with the corresponding points # the index with the most minimal distance is the holePoint, we want to ignore it # the index with the second minimal distance is the point closest to the seed, we want to set it as sourcepoint # all other points are the targetpoints # get the index of the holePoint, which we want to remove from our endPoints holePointIndex = distancesToSeed.index(min(distancesToSeed)) # .. and remove it distancesToSeed.pop(holePointIndex) targetPoints.pop(holePointIndex) # now find the sourcepoint sourcePointIndex = distancesToSeed.index(min(distancesToSeed)) # .. and remove it after saving it as the sourcePoint sourcePoint = targetPoints[sourcePointIndex] distancesToSeed.pop(sourcePointIndex) targetPoints.pop(sourcePointIndex) # again, at this point we have a) the sourcePoint and b) a list of real targetPoints # now create the sourceIdList and targetIdList for the actual centerline computation sourceIdList = vtk.vtkIdList() targetIdList = vtk.vtkIdList() pointLocator = vtk.vtkPointLocator() pointLocator.SetDataSet(preparedModel) pointLocator.BuildLocator() # locate the source on the surface sourceId = pointLocator.FindClosestPoint(sourcePoint) sourceIdList.InsertNextId(sourceId) f = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLAnnotationFiducialNode") f.SetFiducialCoordinates(sourcePoint) f.Initialize(slicer.mrmlScene) f.SelectedOn() # locate the endpoints on the surface for p in targetPoints: f = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLAnnotationFiducialNode") f.SetFiducialCoordinates(p) f.Initialize(slicer.mrmlScene) id = pointLocator.FindClosestPoint(p) targetIdList.InsertNextId(id) tupel = self.GetLogic().computeCenterlines(preparedModel, sourceIdList, targetIdList) network.DeepCopy(tupel[0]) voronoi.DeepCopy(tupel[1]) # # # update the display of the original model in terms of opacity currentModelDisplayNode = currentModelNode.GetDisplayNode() if not currentModelDisplayNode: # create new displayNode currentModelDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelDisplayNode") slicer.mrmlScene.AddNode(currentModelDisplayNode) currentModelDisplayNode.SetOpacity(0.4) currentModelDisplayNode.Modified() currentModelDisplayNode.SetModifiedSinceRead(1) # update the reference between model node and it's display node currentModelNode.SetAndObserveDisplayNodeID( currentModelDisplayNode.GetID()) currentModelNode.Modified() currentModelNode.SetModifiedSinceRead(1) # # finally: # propagate output model to nodes currentOutputModelNode.SetAndObservePolyData(network) currentOutputModelNode.Modified() currentOutputModelNode.SetModifiedSinceRead(1) currentOutputModelDisplayNode = currentOutputModelNode.GetDisplayNode() if not currentOutputModelDisplayNode: # create new displayNode currentOutputModelDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelDisplayNode") slicer.mrmlScene.AddNode(currentOutputModelDisplayNode) # always configure the displayNode to show the model currentOutputModelDisplayNode.SetPolyData( currentOutputModelNode.GetPolyData()) currentOutputModelDisplayNode.SetColor(0.0, 0.0, 0.4) # red currentOutputModelDisplayNode.SetBackfaceCulling(0) currentOutputModelDisplayNode.SetSliceIntersectionVisibility(0) currentOutputModelDisplayNode.SetVisibility(1) currentOutputModelDisplayNode.SetOpacity(1.0) currentOutputModelDisplayNode.Modified() currentOutputModelDisplayNode.SetModifiedSinceRead(1) # update the reference between model node and it's display node currentOutputModelNode.SetAndObserveDisplayNodeID( currentOutputModelDisplayNode.GetID()) currentOutputModelNode.Modified() currentOutputModelNode.SetModifiedSinceRead(1) # only update the voronoi node if we are not in preview mode if not preview: currentVoronoiModelNode.SetAndObservePolyData(voronoi) currentVoronoiModelNode.Modified() currentVoronoiModelNode.SetModifiedSinceRead(1) currentVoronoiModelDisplayNode = currentVoronoiModelNode.GetDisplayNode( ) if not currentVoronoiModelDisplayNode: # create new displayNode currentVoronoiModelDisplayNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelDisplayNode") slicer.mrmlScene.AddNode(currentVoronoiModelDisplayNode) # always configure the displayNode to show the model currentVoronoiModelDisplayNode.SetPolyData( currentVoronoiModelNode.GetPolyData()) currentVoronoiModelDisplayNode.SetScalarVisibility(1) currentVoronoiModelDisplayNode.SetBackfaceCulling(0) currentVoronoiModelDisplayNode.SetActiveScalarName("Radius") currentVoronoiModelDisplayNode.SetAndObserveColorNodeID( slicer.mrmlScene.GetNodesByName("Labels").GetItemAsObject( 0).GetID()) currentVoronoiModelDisplayNode.SetSliceIntersectionVisibility(0) currentVoronoiModelDisplayNode.SetVisibility(1) currentVoronoiModelDisplayNode.SetOpacity(0.5) currentVoronoiModelDisplayNode.Modified() currentVoronoiModelDisplayNode.SetModifiedSinceRead(1) # update the reference between model node and it's display node currentVoronoiModelNode.SetAndObserveDisplayNodeID( currentVoronoiModelDisplayNode.GetID()) currentVoronoiModelNode.Modified() currentVoronoiModelNode.SetModifiedSinceRead(1) SlicerVmtk4CommonLib.Helper.Debug("End of Centerline Computation..")