def marchingCubes( self, image, ijkToRasMatrix, threshold ):


        transformIJKtoRAS = vtk.vtkTransform()
        transformIJKtoRAS.SetMatrix( ijkToRasMatrix )

        marchingCubes = vtk.vtkMarchingCubes()
        marchingCubes.SetInput( image )
        marchingCubes.SetValue( 0, threshold )
        marchingCubes.ComputeScalarsOn()
        marchingCubes.ComputeGradientsOn()
        marchingCubes.ComputeNormalsOn()
        marchingCubes.GetOutput().ReleaseDataFlagOn()
        marchingCubes.Update()


        if transformIJKtoRAS.GetMatrix().Determinant() < 0:
            reverser = vtk.vtkReverseSense()
            reverser.SetInput( marchingCubes.GetOutput() )
            reverser.ReverseNormalsOn()
            reverser.GetOutput().ReleaseDataFlagOn()
            reverser.Update()
            correctedOutput = reverser.GetOutput()
        else:
            correctedOutput = marchingCubes.GetOutput()

        transformer = vtk.vtkTransformPolyDataFilter()
        transformer.SetInput( correctedOutput )
        transformer.SetTransform( transformIJKtoRAS )
        transformer.GetOutput().ReleaseDataFlagOn()
        transformer.Update()

        normals = vtk.vtkPolyDataNormals()
        normals.ComputePointNormalsOn()
        normals.SetInput( transformer.GetOutput() )
        normals.SetFeatureAngle( 60 )
        normals.SetSplitting( 1 )
        normals.GetOutput().ReleaseDataFlagOn()
        normals.Update()

        stripper = vtk.vtkStripper()
        stripper.SetInput( normals.GetOutput() )
        stripper.GetOutput().ReleaseDataFlagOff()
        stripper.Update()
        stripper.GetOutput().Update()

        result = vtk.vtkPolyData()
        result.DeepCopy( stripper.GetOutput() )
        result.Update()

        return result
예제 #2
0
 def marchingCubes(self,image,ijkToRasMatrix,threshold):
     
     
     transformIJKtoRAS = vtk.vtkTransform()
     transformIJKtoRAS.SetMatrix(ijkToRasMatrix)
     
     marchingCubes = vtk.vtkMarchingCubes()
     marchingCubes.SetInput(image)
     marchingCubes.SetValue(0,threshold)
     marchingCubes.ComputeScalarsOn()
     marchingCubes.ComputeGradientsOn()
     marchingCubes.ComputeNormalsOn()
     marchingCubes.GetOutput().ReleaseDataFlagOn()
     marchingCubes.Update()
     
     
     if transformIJKtoRAS.GetMatrix().Determinant() < 0:
         reverser = vtk.vtkReverseSense()
         reverser.SetInput(marchingCubes.GetOutput())
         reverser.ReverseNormalsOn()
         reverser.GetOutput().ReleaseDataFlagOn()
         reverser.Update()
         correctedOutput = reverser.GetOutput()
     else:
         correctedOutput = marchingCubes.GetOutput()
     
     transformer = vtk.vtkTransformPolyDataFilter()
     transformer.SetInput(correctedOutput)
     transformer.SetTransform(transformIJKtoRAS)
     transformer.GetOutput().ReleaseDataFlagOn()
     transformer.Update()
     
     normals = vtk.vtkPolyDataNormals()
     normals.ComputePointNormalsOn()
     normals.SetInput(transformer.GetOutput())
     normals.SetFeatureAngle(60)
     normals.SetSplitting(1)
     normals.GetOutput().ReleaseDataFlagOn()
     normals.Update()
     
     stripper = vtk.vtkStripper()
     stripper.SetInput(normals.GetOutput())
     stripper.GetOutput().ReleaseDataFlagOff()
     stripper.Update()
     stripper.GetOutput().Update()
     
     result = vtk.vtkPolyData()
     result.DeepCopy(stripper.GetOutput())
     result.Update()
     
     return result
  def PointsToSurfacePolyData( self, inPoints, reverse ):

    # Create a polydata object from the points
    pointsPolyData = vtk.vtkPolyData()
    pointsPolyData.SetPoints( inPoints )
  
    # Create the surface filter from the polydata
    surfaceFilter = vtk.vtkSurfaceReconstructionFilter()
    surfaceFilter.SetInputData( pointsPolyData )
    surfaceFilter.Update()
    
    # Do the contouring filter, and reverse to ensure it works properly
    contourFilter = vtk.vtkContourFilter()
    contourFilter.SetValue( 0, 0.0 )
    contourFilter.SetInputData( surfaceFilter.GetOutput() )
    contourFilter.Update()
    
    # Reverse the normals if necessary
    reverseFilter = vtk.vtkReverseSense()
    reverseFilter.SetInputData( contourFilter.GetOutput() )
    reverseFilter.SetReverseCells( reverse )
    reverseFilter.SetReverseNormals( reverse )
    reverseFilter.Update()
   
    # Reset the scaling to let the surface match the points
    fiducialBounds = [ 0, 0, 0, 0, 0, 0 ]
    pointsPolyData.GetBounds( fiducialBounds )
    
    tissueBounds = [ 0, 0, 0, 0, 0, 0 ]
    reverseFilter.GetOutput().GetBounds( tissueBounds )
    
    scaleX = ( fiducialBounds[1] - fiducialBounds[0] ) / ( tissueBounds[1] - tissueBounds[0] )
    scaleY = ( fiducialBounds[3] - fiducialBounds[2] ) / ( tissueBounds[3] - tissueBounds[2] )
    scaleZ = ( fiducialBounds[5] - fiducialBounds[4] ) / ( tissueBounds[5] - tissueBounds[4] )
    
    transform = vtk.vtkTransform()
    transform.Translate( fiducialBounds[0], fiducialBounds[2], fiducialBounds[4] )
    transform.Scale( scaleX, scaleY, scaleZ )
    transform.Translate( - tissueBounds[0], - tissueBounds[2], - tissueBounds[4] )
  
    transformFilter = vtk.vtkTransformPolyDataFilter()
    transformFilter.SetInputData( reverseFilter.GetOutput() )
    transformFilter.SetTransform( transform )
    transformFilter.Update()
  
    return transformFilter.GetOutput()
예제 #4
0
    def updateModelFromMarkup(self, inputMarkup, outputModel):
        """
    Update model to enclose all points in the input markup list
    """

        # Delaunay triangulation is robust and creates nice smooth surfaces from a small number of points,
        # however it can only generate convex surfaces robustly.
        useDelaunay = True

        # Create polydata point set from markup points

        points = vtk.vtkPoints()
        cellArray = vtk.vtkCellArray()

        numberOfPoints = inputMarkup.GetNumberOfFiducials()

        # Surface generation algorithms behave unpredictably when there are not enough points
        # return if there are very few points
        if useDelaunay:
            if numberOfPoints < 3:
                return
        else:
            if numberOfPoints < 10:
                return

        points.SetNumberOfPoints(numberOfPoints)
        new_coord = [0.0, 0.0, 0.0]

        for i in range(numberOfPoints):
            inputMarkup.GetNthFiducialPosition(i, new_coord)
            points.SetPoint(i, new_coord)

        cellArray.InsertNextCell(numberOfPoints)
        for i in range(numberOfPoints):
            cellArray.InsertCellPoint(i)

        pointPolyData = vtk.vtkPolyData()
        pointPolyData.SetLines(cellArray)
        pointPolyData.SetPoints(points)

        # Create surface from point set

        if useDelaunay:

            delaunay = vtk.vtkDelaunay3D()
            delaunay.SetInputData(pointPolyData)

            surfaceFilter = vtk.vtkDataSetSurfaceFilter()
            surfaceFilter.SetInputConnection(delaunay.GetOutputPort())

            smoother = vtk.vtkButterflySubdivisionFilter()
            smoother.SetInputConnection(surfaceFilter.GetOutputPort())
            smoother.SetNumberOfSubdivisions(3)
            smoother.Update()

            outputModel.SetPolyDataConnection(smoother.GetOutputPort())

        else:

            surf = vtk.vtkSurfaceReconstructionFilter()
            surf.SetInputData(pointPolyData)
            surf.SetNeighborhoodSize(20)
            surf.SetSampleSpacing(
                80
            )  # lower value follows the small details more closely but more dense pointset is needed as input

            cf = vtk.vtkContourFilter()
            cf.SetInputConnection(surf.GetOutputPort())
            cf.SetValue(0, 0.0)

            # Sometimes the contouring algorithm can create a volume whose gradient
            # vector and ordering of polygon (using the right hand rule) are
            # inconsistent. vtkReverseSense cures this problem.
            reverse = vtk.vtkReverseSense()
            reverse.SetInputConnection(cf.GetOutputPort())
            reverse.ReverseCellsOff()
            reverse.ReverseNormalsOff()

            outputModel.SetPolyDataConnection(reverse.GetOutputPort())

        # Create default model display node if does not exist yet
        if not outputModel.GetDisplayNode():
            modelDisplayNode = slicer.mrmlScene.CreateNodeByClass(
                "vtkMRMLModelDisplayNode")
            modelDisplayNode.SetColor(0, 0, 1)  # Blue
            modelDisplayNode.BackfaceCullingOff()
            modelDisplayNode.SliceIntersectionVisibilityOn()
            modelDisplayNode.SetOpacity(0.3)  # Between 0-1, 1 being opaque
            slicer.mrmlScene.AddNode(modelDisplayNode)
            outputModel.SetAndObserveDisplayNodeID(modelDisplayNode.GetID())

        outputModel.GetDisplayNode().SliceIntersectionVisibilityOn()

        outputModel.Modified()
  def run( self, markupNode, depth, fitPlane, flip ):
    """
    Run the actual algorithm
    """
    
    # Get all of the fiducial nodes and convert to vtkPoints
    points = vtk.vtkPoints()
    
    for i in range( 0, markupNode.GetNumberOfFiducials() ):
      currentCoordinates = [ 0, 0, 0 ]
      markupNode.GetNthFiducialPosition( i, currentCoordinates )
      points.InsertNextPoint( currentCoordinates )
      
    # Check that there is non-zero range in all coordinate directions
    pointsBounds = [ 0, 0, 0, 0, 0, 0 ]
    points.GetBounds( pointsBounds )
    if ( pointsBounds[0] == pointsBounds [1] or pointsBounds[2] == pointsBounds [3] or pointsBounds[4] == pointsBounds [5] ):
      print "Tissue Model Creator: Points have no extent in one or more coordinate directions."
      return False
      
    # Create a polydata object from the points
    # The reversiness doesn't matter - we will fix it later if it os wrong
    if ( fitPlane ):
      surfacePolyData = self.PointsToPlanePolyData( points, True )
    else:
      surfacePolyData = self.PointsToSurfacePolyData( points, True )
      
    surfaceCleaner = vtk.vtkCleanPolyData()
    surfaceCleaner.SetInputData( surfacePolyData )
    surfaceCleaner.Update()
    surfacePolyData = surfaceCleaner.GetOutput()
    
    mean = self.CalculateMean( points )
    
    surfaceBase = [ 0, 0, 0 ]
    surfaceDir1 = [ 0, 0, 0 ]
    surfaceDir2 = [ 0, 0, 0 ]
    surfaceNormal = [ 0, 0, 0 ]
    self.CalculatePlane( surfacePolyData.GetPoints(), surfaceBase, surfaceDir1, surfaceDir2, surfaceNormal )
    
    if ( flip == True ):
      surfaceNormal[ 0 ] = - surfaceNormal[ 0 ]
      surfaceNormal[ 1 ] = - surfaceNormal[ 1 ]
      surfaceNormal[ 2 ] = - surfaceNormal[ 2 ]
    
    extremePointIndex = self.FindExtremePoint( surfacePolyData.GetPoints(), surfaceBase, surfaceNormal )
    reverse = self.ReverseNormals( extremePointIndex, surfacePolyData, surfaceNormal )
    
    # Reverse the normals if necessary
    reverseFilter = vtk.vtkReverseSense()
    reverseFilter.SetInputData( surfacePolyData )
    reverseFilter.SetReverseCells( reverse )
    reverseFilter.SetReverseNormals( reverse )
    reverseFilter.Update()
    surfacePolyData = reverseFilter.GetOutput()
    
    untransDeepPolyData = vtk.vtkPolyData()
    untransDeepPolyData.DeepCopy( surfacePolyData )
    
    # Make the normals opposite the surface's normals
    reverseFilter = vtk.vtkReverseSense()
    reverseFilter.SetInputData( untransDeepPolyData )
    reverseFilter.SetReverseCells( True )
    reverseFilter.SetReverseNormals( True )
    reverseFilter.Update()
    untransDeepPolyData = reverseFilter.GetOutput()
    
    deepTransform = vtk.vtkTransform()
    deepTransform.Translate( depth * surfaceNormal[0], depth * surfaceNormal[1], depth * surfaceNormal[2] )  
    deepTransformFilter = vtk.vtkTransformPolyDataFilter()
    deepTransformFilter.SetInputData( untransDeepPolyData )
    deepTransformFilter.SetTransform( deepTransform )
    deepTransformFilter.Update()
    
    deepPolyData = deepTransformFilter.GetOutput()

    
    surfaceHullPoints = self.GetBoundaryPoints( surfacePolyData )
    
    deepHullPoints = self.GetBoundaryPoints( deepPolyData )
    
    # Apparently, the joining needs an offset for the plane, but not for the surface reconstruction
    if ( fitPlane ):
      jointHullPolyData = self.JoinBoundaryPoints( surfaceHullPoints, deepHullPoints, 1 )
    else:
      jointHullPolyData = self.JoinBoundaryPoints( surfaceHullPoints, deepHullPoints, 0 )
    
    
    # Append all of the polydata together
    tissuePolyDataAppend = vtk.vtkAppendPolyData()
    tissuePolyDataAppend.AddInputData( surfacePolyData )
    tissuePolyDataAppend.AddInputData( deepPolyData )
    tissuePolyDataAppend.AddInputData( jointHullPolyData )   
    tissuePolyDataAppend.Update()

    # Clean up so the surface is closed
    tissueCleaner = vtk.vtkCleanPolyData()
    tissueCleaner.SetInputData( tissuePolyDataAppend.GetOutput() )
    tissueCleaner.Update()
    
    tissueModelPolyData = tissueCleaner.GetOutput()
    
    # Add the data to a model 
    tissueModel = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelNode" )
    slicer.mrmlScene.AddNode( tissueModel )
    tissueModel.SetName( "TissueModel" )
    tissueModel.SetAndObservePolyData( tissueModelPolyData )    
    tissueModel.SetScene( slicer.mrmlScene )
    
    # Finally display the model
    tissueModelDisplay = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLModelDisplayNode" )
    slicer.mrmlScene.AddNode( tissueModelDisplay )
    tissueModel.SetAndObserveDisplayNodeID( tissueModelDisplay.GetID() )
    tissueModelDisplay.SetScene( slicer.mrmlScene )
    tissueModelDisplay.SetInputPolyDataConnection( tissueModel.GetPolyDataConnection() )


    # Check to make sure the model is a closed surface
    edgesFilter = vtk.vtkFeatureEdges()
    edgesFilter.FeatureEdgesOff()
    edgesFilter.BoundaryEdgesOn()
    edgesFilter.NonManifoldEdgesOn()
    edgesFilter.SetInputData( tissueModel.GetPolyData() )
    edgesFilter.Update()
    
    if ( edgesFilter.GetOutput().GetNumberOfCells() != 0 ):
      print "Tissue Model Creator: Surface is not closed."
      return False
      
    return True