def Smooth_Surface(self, surface): # Take a vtk surface and run it through the smoothing pipeline boneNormals = vtk.vtkPolyDataNormals() try: boneNormals.SetInputData(surface) except: boneNormals.SetInputConnection(surface.GetOutputPort()) boneNormals.Update() # Clean the polydata so that the edges are shared! cleanPolyData = vtk.vtkCleanPolyData() cleanPolyData.SetInputConnection(boneNormals.GetOutputPort()) cleanPolyData.Update() polydata = cleanPolyData.GetOutput() if self.smoothing_iterations > 0: # Apply laplacian smoothing to the surface smoothingFilter = vtk.vtkSmoothPolyDataFilter() smoothingFilter.SetInputData(polydata) smoothingFilter.SetNumberOfIterations( int(self.smoothing_iterations)) smoothingFilter.SetRelaxationFactor(self.relaxation_factor) smoothingFilter.Update() polydata = smoothingFilter.GetOutput() if self.decimate_surface > 0 and self.decimate_surface < 1: # We want to preserve topology (not let any cracks form). This may # limit the total reduction possible, which we have specified at 80%. deci = vtk.vtkDecimatePro() deci.SetInputData(polydata) deci.SetTargetReduction(self.decimate_surface) deci.PreserveTopologyOn() deci.Update() polydata = deci.GetOutput() # Clean the polydata so that the edges are shared! cleanPolyData = vtk.vtkCleanPolyData() cleanPolyData.SetInputData(polydata) cleanPolyData.Update() polydata = cleanPolyData.GetOutput() # Generate surface normals to give a better visualization normals = vtk.vtkPolyDataNormals() normals.SetInputData(polydata) normals.Update() polydata = normals.GetOutput() return polydata
def runLabelWise(self, targetLabelNode, obstacleModelNode, skinModelNode): """ Run label-wise analysis """ poly = skinModelNode.GetPolyData() polyDataNormals = vtk.vtkPolyDataNormals() polyDataNormals.SetInput(poly) polyDataNormals.ComputeCellNormalsOn() polyDataNormals.Update() polyData = polyDataNormals.GetOutput() bspTree = vtk.vtkModifiedBSPTree() bspTree.SetDataSet(obstacleModelNode.GetPolyData()) bspTree.BuildLocator() trans = vtk.vtkMatrix4x4() targetLabelNode.GetIJKToRASMatrix(trans) pos = [0.0, 0.0, 0.0, 0.0] imageData = targetLabelNode.GetImageData() (x0, x1, y0, y1, z0, z1) = imageData.GetExtent() for z in range(z0, z1+1): for y in range(y0, y1+1): for x in range(x0, x1+1): if imageData.GetScalarComponentAsDouble(x, y, z, 0) > 0: trans.MultiplyPoint([x, y, z, 1.0], pos); (score, mind, mindp) = self.calcApproachScore(pos[0:3], polyData, bspTree, None) imageData.SetScalarComponentFromDouble(x, y, z, 0, score*100.0+1.0) #print ("Index(%f, %f, %f) -> RAS(%f, %f, %f)" % (x, y, z, pos[0], pos[1], pos[2])) #print ("Approach Score (<accessible area> / (<accessible area> + <inaccessible area>)) = %f" % (score)) return True
def runPointWise(self, targetPointNode, obstacleModelNode, skinModelNode): """ Run point-wise analysis """ print("runPointWise()") tPoint = targetPointNode.GetMarkupPointVector(0, 0) pTarget = [tPoint[0], tPoint[1], tPoint[2]] poly = skinModelNode.GetPolyData() polyDataNormals = vtk.vtkPolyDataNormals() polyDataNormals.SetInput(poly) polyDataNormals.ComputeCellNormalsOn() polyDataNormals.Update() polyData = polyDataNormals.GetOutput() bspTree = vtk.vtkModifiedBSPTree() bspTree.SetDataSet(obstacleModelNode.GetPolyData()) bspTree.BuildLocator() (score, mind, mindp) = self.calcApproachScore(pTarget, polyData, bspTree, skinModelNode) print( "Approach Score (<accessible area> / (<accessible area> + <inaccessible area>)) = %f" % (score)) print("Minmum Distance = %f" % (mind)) return (score, mind, mindp)
def runPointWise(self, targetPointNode, obstacleModelNode, skinModelNode): """ Run point-wise analysis """ print ("runPointWise()") tPoint = targetPointNode.GetMarkupPointVector(0, 0) pTarget = [tPoint[0], tPoint[1], tPoint[2]] poly = skinModelNode.GetPolyData() polyDataNormals = vtk.vtkPolyDataNormals() polyDataNormals.SetInput(poly) polyDataNormals.ComputeCellNormalsOn() polyDataNormals.Update() polyData = polyDataNormals.GetOutput() bspTree = vtk.vtkModifiedBSPTree() bspTree.SetDataSet(obstacleModelNode.GetPolyData()) bspTree.BuildLocator() (score, mind, mindp) = self.calcApproachScore(pTarget, polyData, bspTree, skinModelNode) print ("Approach Score (<accessible area> / (<accessible area> + <inaccessible area>)) = %f" % (score)) print ("Minmum Distance = %f" % (mind)) return (score, mind, mindp)
def runLabelWise(self, targetLabelNode, obstacleModelNode, skinModelNode): """ Run label-wise analysis """ poly = skinModelNode.GetPolyData() polyDataNormals = vtk.vtkPolyDataNormals() polyDataNormals.SetInput(poly) polyDataNormals.ComputeCellNormalsOn() polyDataNormals.Update() polyData = polyDataNormals.GetOutput() bspTree = vtk.vtkModifiedBSPTree() bspTree.SetDataSet(obstacleModelNode.GetPolyData()) bspTree.BuildLocator() trans = vtk.vtkMatrix4x4() targetLabelNode.GetIJKToRASMatrix(trans) pos = [0.0, 0.0, 0.0, 0.0] imageData = targetLabelNode.GetImageData() (x0, x1, y0, y1, z0, z1) = imageData.GetExtent() for z in range(z0, z1 + 1): for y in range(y0, y1 + 1): for x in range(x0, x1 + 1): if imageData.GetScalarComponentAsDouble(x, y, z, 0) > 0: trans.MultiplyPoint([x, y, z, 1.0], pos) (score, mind, mindp) = self.calcApproachScore( pos[0:3], polyData, bspTree, None) imageData.SetScalarComponentFromDouble( x, y, z, 0, score * 100.0 + 1.0) #print ("Index(%f, %f, %f) -> RAS(%f, %f, %f)" % (x, y, z, pos[0], pos[1], pos[2])) #print ("Approach Score (<accessible area> / (<accessible area> + <inaccessible area>)) = %f" % (score)) return True
def runPointWise(self, targetPointANode, obstacleModelNode, skinModelNode): """ Run point-wise analysis """ print("runPointWise()") #tPointA = targetPointANode.GetMarkupPointVector(0, 0) #pTargetA = [tPointA[0], tPointA[1], tPointA[2]] #tPointB = targetPointBNode.GetMarkupPointVector(0, 0) #pTargetB = [tPointB[0], tPointB[1], tPointB[2]] #tPointC = targetPointCNode.GetMarkupPointVector(0, 0) #pTargetC = [tPointC[0], tPointC[1], tPointC[2]] poly = skinModelNode.GetPolyData() polyDataNormals = vtk.vtkPolyDataNormals() polyDataNormals.SetInputData(poly) polyDataNormals.ComputeCellNormalsOn() polyDataNormals.Update() polyData = polyDataNormals.GetOutput() bspTree = vtk.vtkModifiedBSPTree() bspTree.SetDataSet(obstacleModelNode.GetPolyData()) bspTree.BuildLocator() #(score, mind, mindp) = self.calcApproachScore(pTargetA, pTargetB, pTargetC, polyData, bspTree, skinModelNode) #(score, mind, mindp) = self.calcApproachScore(pTargetA, polyData, bspTree, skinModelNode) (score, mind, mindp) = self.calcApproachScore(targetPointANode, polyData, bspTree, skinModelNode) print("Approach Score (<accessible area>) = %f" % (score)) print("Minmum Distance = %f" % (mind)) return (score, mind, mindp)
def GenerateMould(self, facePolydata, distanceFromMask, ROI, tubePolydata, clippedFace): ROIExtents = self.utility.GetROIExtents(ROI) outerFaceImplicitFunction = vtk.vtkImplicitModeller() outerFaceImplicitFunction.SetInputConnection(facePolydata.GetOutputPort()) outerFaceImplicitFunction.SetSampleDimensions(70, 70, 70) outerFaceImplicitFunction.SetMaximumDistance(distanceFromMask) outerFaceImplicitFunction.SetModelBounds(ROIExtents) outerFaceImplicitFunction.SetProcessModeToPerVoxel() outerMaskContourFunction = vtk.vtkContourFilter() # TODO Find out the the allowed thinkness of the plastic THICKNESS = 3 outerMaskContourFunction.SetValue(0, THICKNESS) outerMaskContourFunction.SetInputConnection(outerFaceImplicitFunction.GetOutputPort()) outerFaceNormalsFunction = vtk.vtkPolyDataNormals() outerFaceNormalsFunction.AutoOrientNormalsOn() outerFaceNormalsFunction.AddInputConnection(outerMaskContourFunction.GetOutputPort()) # Subtract the Tubes from the mask subtractionFilter1 = vtk.vtkBooleanOperationPolyDataFilter() subtractionFilter1.SetOperationToDifference() subtractionFilter1.SetInputConnection(0, outerFaceNormalsFunction.GetOutputPort()) subtractionFilter1.SetInputConnection(1, tubePolydata.GetOutputPort()) # Subtract the inner face from the outer face to make the mask subtractionFilter2 = vtk.vtkBooleanOperationPolyDataFilter() subtractionFilter2.SetOperationToDifference() subtractionFilter2.SetInputConnection(0, subtractionFilter1.GetOutputPort()) subtractionFilter2.SetInputConnection(1, clippedFace.GetOutputPort()) x = self.utility.DisplayPolyData("Mask", subtractionFilter2.GetOutput()) x.SetColor(0.8, 0.8, 0.8) x.SetOpacity(1)
def applyFilters(self, state): surface = state.inputModelNode.GetPolyData() if state.decimation: triangle = vtk.vtkTriangleFilter() triangle.SetInput(surface) decimation = vtk.vtkDecimatePro() decimation.SetInput(triangle.GetOutput()) decimation.SetTargetReduction(state.reduction) decimation.SetBoundaryVertexDeletion(state.boundaryDeletion) decimation.PreserveTopologyOn() decimation.Update() surface = decimation.GetOutput() if state.smoothing: if state.smoothingMethod == "Laplace": smoothing = vtk.vtkSmoothPolyDataFilter() smoothing.SetInput(surface) smoothing.SetBoundarySmoothing(state.boundarySmoothing) smoothing.SetNumberOfIterations(state.laplaceIterations) smoothing.SetRelaxationFactor(state.laplaceRelaxation) smoothing.Update() surface = smoothing.GetOutput() elif state.smoothingMethod == "Taubin": smoothing = vtk.vtkWindowedSincPolyDataFilter() smoothing.SetInput(surface) smoothing.SetBoundarySmoothing(state.boundarySmoothing) smoothing.SetNumberOfIterations(state.taubinIterations) smoothing.SetPassBand(state.taubinPassBand) smoothing.Update() surface = smoothing.GetOutput() if state.normals: normals = vtk.vtkPolyDataNormals() normals.SetInput(surface) normals.AutoOrientNormalsOn() normals.SetFlipNormals(state.flipNormals) normals.SetSplitting(state.splitting) normals.SetFeatureAngle(state.featureAngle) normals.ConsistencyOn() normals.Update() surface = normals.GetOutput() if state.cleaner: cleaner = vtk.vtkCleanPolyData() cleaner.SetInput(surface) cleaner.Update() surface = cleaner.GetOutput() if state.connectivity: connectivity = vtk.vtkPolyDataConnectivityFilter() connectivity.SetInput(surface) connectivity.SetExtractionModeToLargestRegion() connectivity.Update() surface = connectivity.GetOutput() state.outputModelNode.SetAndObservePolyData(surface) return True
def calculateNormals(polydata, flip=False): normalsFilter = vtk.vtkPolyDataNormals() normalsFilter.SetInputData(polydata) normalsFilter.AutoOrientNormalsOn() if flip: normalsFilter.FlipNormalsOn() normalsFilter.Update() return normalsFilter.GetOutput()
def MinimumDistanceMask(self, vtkAlgorythmObject, distanceFromMask, ROI, ruler, isBubble=False): """ Takes an algorythm object which is will send through a pipeline to create a mask defining the minimum distance value from the skin surface returns an algorythm object as well to preform GetOutput() -> polydata or GetOutputPort() -> algorythm see MinimumDistanceMask.pdf """ if distanceFromMask < 2: print "WARNING: MouldLogic: MinimumDistanceMask implicit", "modeling is very unstable below 1.5 , mask may degrade", "and lines will become discontinuous." Extents = self.utility.GetROIExtents(ROI) if (isBubble): Extents = self.utility.ExpandExtents(Extents, 100) implicitModeller = vtk.vtkImplicitModeller() implicitModeller.SetInputConnection(vtkAlgorythmObject.GetOutputPort()) implicitModeller.SetMaximumDistance(distanceFromMask) implicitModeller.SetModelBounds(Extents) implicitModeller.AdjustBoundsOn() implicitModeller.SetAdjustBounds(10) # Removes the boundary effects implicitModeller.CappingOff( ) # Important to create disjoint inner and outer masks implicitModeller.SetProcessModeToPerVoxel() implicitModeller.Update() contourFilter = vtk.vtkContourFilter() contourFilter.SetValue(0, distanceFromMask) contourFilter.SetInputConnection(implicitModeller.GetOutputPort()) contourFilter.Update() normalsFunction = vtk.vtkPolyDataNormals() normalsFunction.FlipNormalsOn() normalsFunction.AddInputConnection(contourFilter.GetOutputPort()) normalsFunction.Update() implicitBoxRegion = vtk.vtkBox() implicitBoxRegion.SetBounds(Extents) clipper2 = vtk.vtkClipPolyData() clipper2.InsideOutOn() # Clip the regions outside of implicit function clipper2.SetInputConnection(normalsFunction.GetOutputPort()) clipper2.SetClipFunction(implicitBoxRegion) clipper2.Update() closestPoint = [0, 0, 0] ruler.GetPosition1(closestPoint) connectivityFilter = vtk.vtkPolyDataConnectivityFilter() connectivityFilter.SetInputConnection(clipper2.GetOutputPort()) connectivityFilter.SetExtractionModeToClosestPointRegion() connectivityFilter.SetClosestPoint(closestPoint) connectivityFilter.Update() return connectivityFilter.GetOutput()
def prepareModel( self, polyData ): ''' ''' # import the vmtk libraries try: #from libvtkvmtkComputationalGeometryPython import * #from libvtkvmtkMiscPython import * import libvtkvmtkComputationalGeometryPython as cg import libvtkvmtkMiscPython as m except ImportError: print "FAILURE: Unable to import the SlicerVmtk libraries!" capDisplacement = 0.0 surfaceCleaner = vtk.vtkCleanPolyData() surfaceCleaner.SetInput( polyData ) surfaceCleaner.Update() surfaceTriangulator = vtk.vtkTriangleFilter() surfaceTriangulator.SetInput( surfaceCleaner.GetOutput() ) surfaceTriangulator.PassLinesOff() surfaceTriangulator.PassVertsOff() surfaceTriangulator.Update() # new steps for preparation to avoid problems because of slim models (f.e. at stenosis) subdiv = vtk.vtkLinearSubdivisionFilter() subdiv.SetInput( surfaceTriangulator.GetOutput() ) subdiv.SetNumberOfSubdivisions( 1 ) subdiv.Update() smooth = vtk.vtkWindowedSincPolyDataFilter() smooth.SetInput( subdiv.GetOutput() ) smooth.SetNumberOfIterations( 20 ) smooth.SetPassBand( 0.1 ) smooth.SetBoundarySmoothing( 1 ) smooth.Update() normals = vtk.vtkPolyDataNormals() normals.SetInput( smooth.GetOutput() ) normals.SetAutoOrientNormals( 1 ) normals.SetFlipNormals( 0 ) normals.SetConsistency( 1 ) normals.SplittingOff() normals.Update() surfaceCapper = m.vtkvmtkCapPolyData() surfaceCapper.SetInput( normals.GetOutput() ) surfaceCapper.SetDisplacement( capDisplacement ) surfaceCapper.SetInPlaneDisplacement( capDisplacement ) surfaceCapper.Update() outPolyData = vtk.vtkPolyData() outPolyData.DeepCopy( surfaceCapper.GetOutput() ) outPolyData.Update() return outPolyData
def autoOrientNormals(self, model): normals = vtk.vtkPolyDataNormals() normals.SetAutoOrientNormals(True) normals.SetFlipNormals(False) normals.SetSplitting(False) normals.ConsistencyOn() normals.SetInputData(model) normals.Update() normalspoint = normals.GetOutput().GetPointData().GetArray("Normals") model.GetPointData().SetNormals(normalspoint)
def MinimumDistanceMask(self, vtkAlgorythmObject, distanceFromMask, ROI, ruler, isBubble=False): """ Takes an algorythm object which is will send through a pipeline to create a mask defining the minimum distance value from the skin surface returns an algorythm object as well to preform GetOutput() -> polydata or GetOutputPort() -> algorythm see MinimumDistanceMask.pdf """ if distanceFromMask < 2: print "WARNING: MouldLogic: MinimumDistanceMask implicit", "modeling is very unstable below 1.5 , mask may degrade", "and lines will become discontinuous." Extents = self.utility.GetROIExtents(ROI) if isBubble: Extents = self.utility.ExpandExtents(Extents, 100) implicitModeller = vtk.vtkImplicitModeller() implicitModeller.SetInputConnection(vtkAlgorythmObject.GetOutputPort()) implicitModeller.SetMaximumDistance(distanceFromMask) implicitModeller.SetModelBounds(Extents) implicitModeller.AdjustBoundsOn() implicitModeller.SetAdjustBounds(10) # Removes the boundary effects implicitModeller.CappingOff() # Important to create disjoint inner and outer masks implicitModeller.SetProcessModeToPerVoxel() implicitModeller.Update() contourFilter = vtk.vtkContourFilter() contourFilter.SetValue(0, distanceFromMask) contourFilter.SetInputConnection(implicitModeller.GetOutputPort()) contourFilter.Update() normalsFunction = vtk.vtkPolyDataNormals() normalsFunction.FlipNormalsOn() normalsFunction.AddInputConnection(contourFilter.GetOutputPort()) normalsFunction.Update() implicitBoxRegion = vtk.vtkBox() implicitBoxRegion.SetBounds(Extents) clipper2 = vtk.vtkClipPolyData() clipper2.InsideOutOn() # Clip the regions outside of implicit function clipper2.SetInputConnection(normalsFunction.GetOutputPort()) clipper2.SetClipFunction(implicitBoxRegion) clipper2.Update() closestPoint = [0, 0, 0] ruler.GetPosition1(closestPoint) connectivityFilter = vtk.vtkPolyDataConnectivityFilter() connectivityFilter.SetInputConnection(clipper2.GetOutputPort()) connectivityFilter.SetExtractionModeToClosestPointRegion() connectivityFilter.SetClosestPoint(closestPoint) connectivityFilter.Update() return connectivityFilter.GetOutput()
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 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 CreateSegmentation(self, masterVolumeNode, outputObj): # Create segmentation segmentationNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLSegmentationNode") segmentationNode.CreateDefaultDisplayNodes() # only needed for display segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( masterVolumeNode) addedSegmentID = segmentationNode.GetSegmentation().AddEmptySegment( "segmentation") # Create segment editor to get access to effects segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLSegmentEditorNode") segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) # Thresholding segmentEditorWidget.setActiveEffectByName("Threshold") effect = segmentEditorWidget.activeEffect() effect.setParameter("MinimumThreshold", "1") effect.setParameter("MaximumThreshold", "999") effect.self().onApply() # Clean up segmentEditorWidget = None slicer.mrmlScene.RemoveNode(segmentEditorNode) # Make segmentation results visible in 3D segmentationNode.CreateClosedSurfaceRepresentation() # Make sure surface mesh cells are consistently oriented surfaceMesh = segmentationNode.GetClosedSurfaceRepresentation( addedSegmentID) normals = vtk.vtkPolyDataNormals() normals.AutoOrientNormalsOn() normals.ConsistencyOn() normals.SetInputData(surfaceMesh) normals.Update() surfaceMesh = normals.GetOutput() # Write to OBJ file writer = vtk.vtkOBJWriter() writer.SetInputData(surfaceMesh) writer.SetFileName(outputObj) writer.Update()
def AddTubeToMask(self, maskPolydata, tube, ROI, radius, ruler): ROIExtents = self.utility.GetROIExtents(ROI) implicitFilter = vtk.vtkImplicitModeller() implicitFilter.SetInput(tube) implicitFilter.SetSampleDimensions(70, 70, 70) implicitFilter.SetMaximumDistance(radius) implicitFilter.SetModelBounds(ROIExtents) implicitFilter.SetProcessModeToPerVoxel() contourFilter = vtk.vtkContourFilter() contourFilter.SetValue(0, radius) implicitFilter.AdjustBoundsOn() implicitFilter.SetAdjustBounds(1) # Removes the boundary effects implicitFilter.CappingOff() contourFilter.SetInputConnection(implicitFilter.GetOutputPort()) normalsFunction = vtk.vtkPolyDataNormals() normalsFunction.AutoOrientNormalsOn() normalsFunction.AddInputConnection(contourFilter.GetOutputPort()) unionFilter = vtk.vtkBooleanOperationPolyDataFilter() unionFilter.SetOperationToUnion() unionFilter.SetInput(0, normalsFunction.GetOutput()) unionFilter.SetInput(1, maskPolydata) return unionFilter.GetOutput()
def GenerateMould(self, facePolydata, distanceFromMask, ROI, tubePolydata, clippedFace): ROIExtents = self.utility.GetROIExtents(ROI) outerFaceImplicitFunction = vtk.vtkImplicitModeller() outerFaceImplicitFunction.SetInputConnection( facePolydata.GetOutputPort()) outerFaceImplicitFunction.SetSampleDimensions(70, 70, 70) outerFaceImplicitFunction.SetMaximumDistance(distanceFromMask) outerFaceImplicitFunction.SetModelBounds(ROIExtents) outerFaceImplicitFunction.SetProcessModeToPerVoxel() outerMaskContourFunction = vtk.vtkContourFilter() #TODO Find out the the allowed thinkness of the plastic THICKNESS = 3 outerMaskContourFunction.SetValue(0, THICKNESS) outerMaskContourFunction.SetInputConnection( outerFaceImplicitFunction.GetOutputPort()) outerFaceNormalsFunction = vtk.vtkPolyDataNormals() outerFaceNormalsFunction.AutoOrientNormalsOn() outerFaceNormalsFunction.AddInputConnection( outerMaskContourFunction.GetOutputPort()) # Subtract the Tubes from the mask subtractionFilter1 = vtk.vtkBooleanOperationPolyDataFilter() subtractionFilter1.SetOperationToDifference() subtractionFilter1.SetInputConnection( 0, outerFaceNormalsFunction.GetOutputPort()) subtractionFilter1.SetInputConnection(1, tubePolydata.GetOutputPort()) # Subtract the inner face from the outer face to make the mask subtractionFilter2 = vtk.vtkBooleanOperationPolyDataFilter() subtractionFilter2.SetOperationToDifference() subtractionFilter2.SetInputConnection( 0, subtractionFilter1.GetOutputPort()) subtractionFilter2.SetInputConnection(1, clippedFace.GetOutputPort()) x = self.utility.DisplayPolyData("Mask", subtractionFilter2.GetOutput()) x.SetColor(0.8, 0.8, 0.8) x.SetOpacity(1)
def load(self, properties): try: filePath = properties["fileName"] tempDirectory = slicer.util.tempDirectory() if not slicer.util.extractArchive(filePath, tempDirectory): raise ValueError("Failed to extract file: " + filePath) # Parse header properties = {} timestamps = [] headerSuffix = "_header.txt" for root, dirs, filenames in os.walk(tempDirectory): for filename in filenames: if filename.endswith(headerSuffix): # found header print(filename) internalBaseName = filename[:-len(headerSuffix)] properties, timestamps = self.parseHeader( os.path.join(root, filename)) break if not properties: raise ValueError( "Failed to read file as TomTec UCD data file: " + filePath) # Get node base name from filename baseName = os.path.basename(filePath) suffix = ".UCD.data.zip" if baseName.endswith(suffix): baseName = baseName[:-len(suffix)] baseName = slicer.mrmlScene.GenerateUniqueName(baseName) sequenceNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLSequenceNode", baseName) sequenceNode.SetIndexName("time") sequenceNode.SetIndexUnit("ms") sequenceNode.SetIndexType(slicer.vtkMRMLSequenceNode.NumericIndex) for propertyName in [ "Average RR Duration", "Enddiastole time", "Endsystole time" ]: sequenceNode.SetAttribute(propertyName, properties[propertyName][0]) numberOfFrames = int(properties["Number of frames"][0]) tempModelNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLModelNode", baseName + " temp") for frameIndex in range(numberOfFrames): # Read mesh meshFilePath = os.path.join( tempDirectory, "{0}_{1:02}.ucd".format(internalBaseName, frameIndex)) reader = vtk.vtkAVSucdReader() reader.SetFileName(meshFilePath) reader.Update() # TomTec UCD files store surface mesh in unstructured grid - convert it to polydata extractSurface = vtk.vtkGeometryFilter() extractSurface.SetInputConnection(reader.GetOutputPort()) normals = vtk.vtkPolyDataNormals() normals.SetInputConnection(extractSurface.GetOutputPort()) normals.Update() # Save in sequence node tempModelNode.SetAndObserveMesh(normals.GetOutput()) addedNode = sequenceNode.SetDataNodeAtValue( tempModelNode, timestamps[frameIndex]) import shutil shutil.rmtree(tempDirectory, True) slicer.mrmlScene.RemoveNode(tempModelNode) sequenceBrowserNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLSequenceBrowserNode", baseName + " browser") sequenceBrowserNode.SetAndObserveMasterSequenceNodeID( sequenceNode.GetID()) # Disable scalar visibility by default (there is not really anything useful to show) proxyModelNode = sequenceBrowserNode.GetProxyNode(sequenceNode) proxyModelNode.GetDisplayNode().SetScalarVisibility(False) # Show sequence browser toolbar if a sequence has been loaded slicer.modules.sequences.showSequenceBrowser(sequenceBrowserNode) except Exception as e: logging.error("Failed to load TomTec UCD data file: " + str(e)) import traceback traceback.print_exc() return False return True
def run(self, inputModel, sModel, seedList): """ Run the actual algorithm """ self.delayDisplay('Running the aglorithm') tri = vtk.vtkDelaunay3D() tri.SetInputData(sModel.GetPolyData()) elev = vtk.vtkElevationFilter() elev.SetInputConnection(tri.GetOutput()) implicitDataSet = vtk.vtkImplicitDataSet() implicitDataSet.SetDataSet(elev.GetOutput()) triangle = vtk.vtkTriangleFilter() triangle.SetInputData(inputModel.GetPolyData()) triangle.Update() computeNormals = vtk.vtkPolyDataNormals() computeNormals.SetInputData(triangle.GetOutput()) computeNormals.ComputeCellNormalsOn() computeNormals.Update() clip = vtk.vtkClipPolyData() clip.SetInputData(computeNormals.GetOutput()) clip.SetClipFunction(implicitDataSet) clip.InsideOutOff() clip.Update() clean = vtk.vtkCleanPolyData() clean.SetInputData(clip.GetOutput()) clean.Update() polydata = clean.GetOutput() cellData = polydata.GetCellData() normals = cellData.GetNormals() meanNormal = [0, 0, 0] nOfTuples = normals.GetNumberOfTuples() for cellIndex in range(0, nOfTuples): cellNormal = [0, 0, 0] cell = polydata.GetCell(cellIndex) normals.GetTuple(cellIndex, cellNormal) meanNormal[0] = meanNormal[0] + cellNormal[0] meanNormal[1] = meanNormal[1] + cellNormal[1] meanNormal[2] = meanNormal[2] + cellNormal[2] meanNormal[0] = meanNormal[0] / nOfTuples meanNormal[1] = meanNormal[1] / nOfTuples meanNormal[2] = meanNormal[2] / nOfTuples print("Normal: " + str(meanNormal)) seed1 = [0, 0, 0] seedList.GetNthFiducialPosition(0, seed1) vector = [ seed1[0] + 50 * meanNormal[0], seed1[1] + 50 * meanNormal[1], seed1[2] + 50 * meanNormal[2] ] seedList.AddFiducialFromArray(vector) # Calculate perpendicular vectors v1 = [0, 0, 0] v2 = [0, 0, 0] math = vtk.vtkMath() math.Perpendiculars(meanNormal, v2, v1, 0) # Normalize vectors math.Normalize(meanNormal) math.Normalize(v1) math.Normalize(v2) # create matrix4x4 transform = slicer.mrmlScene.CreateNodeByClass( 'vtkMRMLLinearTransformNode') slicer.mrmlScene.AddNode(transform) matrix = transform.GetMatrixTransformToParent() matrix.SetElement(0, 0, v1[0]) matrix.SetElement(1, 0, v1[1]) matrix.SetElement(2, 0, v1[2]) matrix.SetElement(3, 0, 0.0) matrix.SetElement(0, 1, meanNormal[0]) matrix.SetElement(1, 1, meanNormal[1]) matrix.SetElement(2, 1, meanNormal[2]) matrix.SetElement(3, 1, 0.0) matrix.SetElement(0, 2, v2[0]) matrix.SetElement(1, 2, v2[1]) matrix.SetElement(2, 2, v2[2]) matrix.SetElement(3, 2, 0.0) matrix.SetElement(0, 3, seed1[0]) matrix.SetElement(1, 3, seed1[1]) matrix.SetElement(2, 3, seed1[2]) matrix.SetElement(3, 3, 1.0) return True
def run(self,inputModel,sModel,seedList): """ Run the actual algorithm """ self.delayDisplay('Running the aglorithm') tri = vtk.vtkDelaunay3D() tri.SetInputData(sModel.GetPolyData()) elev = vtk.vtkElevationFilter() elev.SetInputConnection(tri.GetOutput()) implicitDataSet = vtk.vtkImplicitDataSet() implicitDataSet.SetDataSet(elev.GetOutput()) triangle = vtk.vtkTriangleFilter() triangle.SetInputData(inputModel.GetPolyData()) triangle.Update() computeNormals = vtk.vtkPolyDataNormals() computeNormals.SetInputData(triangle.GetOutput()) computeNormals.ComputeCellNormalsOn() computeNormals.Update() clip = vtk.vtkClipPolyData() clip.SetInputData(computeNormals.GetOutput()) clip.SetClipFunction(implicitDataSet) clip.InsideOutOff() clip.Update() clean = vtk.vtkCleanPolyData() clean.SetInputData(clip.GetOutput()) clean.Update() polydata = clean.GetOutput() cellData = polydata.GetCellData() normals = cellData.GetNormals() meanNormal = [0,0,0] nOfTuples = normals.GetNumberOfTuples() for cellIndex in range(0, nOfTuples): cellNormal = [0,0,0] cell = polydata.GetCell(cellIndex) normals.GetTuple(cellIndex, cellNormal) meanNormal[0] = meanNormal[0] + cellNormal[0] meanNormal[1] = meanNormal[1] + cellNormal[1] meanNormal[2] = meanNormal[2] + cellNormal[2] meanNormal[0] = meanNormal[0] / nOfTuples meanNormal[1] = meanNormal[1] / nOfTuples meanNormal[2] = meanNormal[2] / nOfTuples print("Normal: " + str(meanNormal)) seed1 = [0,0,0] seedList.GetNthFiducialPosition(0,seed1) vector = [seed1[0]+50*meanNormal[0], seed1[1]+50*meanNormal[1], seed1[2]+50*meanNormal[2]] seedList.AddFiducialFromArray(vector) # Calculate perpendicular vectors v1 = [0,0,0] v2 = [0,0,0] math = vtk.vtkMath() math.Perpendiculars(meanNormal, v2, v1, 0) # Normalize vectors math.Normalize(meanNormal) math.Normalize(v1) math.Normalize(v2) # create matrix4x4 transform = slicer.mrmlScene.CreateNodeByClass('vtkMRMLLinearTransformNode') slicer.mrmlScene.AddNode(transform) matrix = transform.GetMatrixTransformToParent() matrix.SetElement(0,0,v1[0]) matrix.SetElement(1,0,v1[1]) matrix.SetElement(2,0,v1[2]) matrix.SetElement(3,0,0.0) matrix.SetElement(0,1,meanNormal[0]) matrix.SetElement(1,1,meanNormal[1]) matrix.SetElement(2,1,meanNormal[2]) matrix.SetElement(3,1,0.0) matrix.SetElement(0,2,v2[0]) matrix.SetElement(1,2,v2[1]) matrix.SetElement(2,2,v2[2]) matrix.SetElement(3,2,0.0) matrix.SetElement(0,3,seed1[0]) matrix.SetElement(1,3,seed1[1]) matrix.SetElement(2,3,seed1[2]) matrix.SetElement(3,3,1.0) return True
def PolyDataToImageData(self, inputPolydata_Ras, referenceVolumeNode_Ras, inVal=100, outVal=0): """ We take in an polydata and convert it to an new image data , withing the Reference Voulume node the reference volume node is cleared with a threshold because originally the volume may contain alot of noisy pixels PARAM: inputPolydata_Ras: Polydata we are looking to conver vtkPolydata() PARAM: refernceVolumeNode_Ras vtkMRMLScalarVolumeNode() RETURN : vtkImageData """ """ Transform the polydata from ras to ijk using the referenceVolumeNode """ #inputPolydataTriangulated_Ijk=polyToImage.GetOutput() transformPolydataFilter = vtk.vtkTransformPolyDataFilter() rasToIjkMatrix = vtk.vtkMatrix4x4() referenceVolumeNode_Ras.GetRASToIJKMatrix(rasToIjkMatrix) rasToIjkTransform = vtk.vtkTransform() rasToIjkTransform.SetMatrix(rasToIjkMatrix) transformPolydataFilter.SetTransform(rasToIjkTransform) transformPolydataFilter.SetInputData(inputPolydata_Ras) transformPolydataFilter.Update() inputPolydata_Ijk = transformPolydataFilter.GetOutput() normalsFunction = vtk.vtkPolyDataNormals() normalsFunction.SetInputData(inputPolydata_Ijk) normalsFunction.ConsistencyOn() trigFilter = vtk.vtkTriangleFilter() trigFilter.SetInputConnection(normalsFunction.GetOutputPort()) stripper = vtk.vtkStripper() stripper.SetInputConnection(trigFilter.GetOutputPort()) stripper.Update() inputPolydataTriangulated_Ijk = stripper.GetOutput() # Clone reference image and clear it referenceImage_Ijk = referenceVolumeNode_Ras.GetImageData() # Fill image with outVal (there is no volume Fill filter in VTK, therefore we need to use threshold filter) thresh = vtk.vtkImageThreshold() thresh.ReplaceInOn() thresh.ReplaceOutOn() thresh.SetInValue(outVal) thresh.SetOutValue(outVal) #thresh.SetOutputScalarType (vtk.VTK_UNSIGNED_CHAR) thresh.SetInputData(referenceImage_Ijk) thresh.Update() whiteImage_Ijk = thresh.GetOutput() # Convert polydata to stencil polyToImage = vtk.vtkPolyDataToImageStencil() polyToImage.SetInputData(inputPolydataTriangulated_Ijk) polyToImage.SetOutputSpacing(whiteImage_Ijk.GetSpacing()) polyToImage.SetOutputOrigin(whiteImage_Ijk.GetOrigin()) polyToImage.SetOutputWholeExtent(whiteImage_Ijk.GetExtent()) polyToImage.Update() imageStencil_Ijk = polyToImage.GetOutput() # Convert stencil to image imgstenc = vtk.vtkImageStencil() imgstenc.SetInputData(whiteImage_Ijk) imgstenc.SetStencilData(imageStencil_Ijk) imgstenc.ReverseStencilOn() imgstenc.SetBackgroundValue(inVal) imgstenc.Update() return imgstenc.GetOutput()
def PolyDataToImageData(self, inputPolydata_Ras, referenceVolumeNode_Ras, inVal=100, outVal=0): """ We take in an polydata and convert it to an new image data , withing the Reference Voulume node the reference volume node is cleared with a threshold because originally the volume may contain alot of noisy pixels PARAM: inputPolydata_Ras: Polydata we are looking to conver vtkPolydata() PARAM: refernceVolumeNode_Ras vtkMRMLScalarVolumeNode() RETURN : vtkImageData """ """ Transform the polydata from ras to ijk using the referenceVolumeNode """ #inputPolydataTriangulated_Ijk=polyToImage.GetOutput() transformPolydataFilter=vtk.vtkTransformPolyDataFilter() rasToIjkMatrix=vtk.vtkMatrix4x4() referenceVolumeNode_Ras.GetRASToIJKMatrix(rasToIjkMatrix) rasToIjkTransform = vtk.vtkTransform() rasToIjkTransform.SetMatrix(rasToIjkMatrix) transformPolydataFilter.SetTransform(rasToIjkTransform) transformPolydataFilter.SetInputData(inputPolydata_Ras) transformPolydataFilter.Update() inputPolydata_Ijk=transformPolydataFilter.GetOutput() normalsFunction=vtk.vtkPolyDataNormals() normalsFunction.SetInputData(inputPolydata_Ijk) normalsFunction.ConsistencyOn() trigFilter=vtk.vtkTriangleFilter() trigFilter.SetInputConnection(normalsFunction.GetOutputPort()) stripper=vtk.vtkStripper() stripper.SetInputConnection(trigFilter.GetOutputPort()) stripper.Update() inputPolydataTriangulated_Ijk=stripper.GetOutput() # Clone reference image and clear it referenceImage_Ijk = referenceVolumeNode_Ras.GetImageData() # Fill image with outVal (there is no volume Fill filter in VTK, therefore we need to use threshold filter) thresh = vtk.vtkImageThreshold() thresh.ReplaceInOn() thresh.ReplaceOutOn() thresh.SetInValue(outVal) thresh.SetOutValue(outVal) #thresh.SetOutputScalarType (vtk.VTK_UNSIGNED_CHAR) thresh.SetInputData(referenceImage_Ijk) thresh.Update() whiteImage_Ijk = thresh.GetOutput() # Convert polydata to stencil polyToImage = vtk.vtkPolyDataToImageStencil() polyToImage.SetInputData(inputPolydataTriangulated_Ijk) polyToImage.SetOutputSpacing(whiteImage_Ijk.GetSpacing()) polyToImage.SetOutputOrigin(whiteImage_Ijk.GetOrigin()) polyToImage.SetOutputWholeExtent(whiteImage_Ijk.GetExtent()) polyToImage.Update() imageStencil_Ijk=polyToImage.GetOutput() # Convert stencil to image imgstenc = vtk.vtkImageStencil() imgstenc.SetInputData(whiteImage_Ijk) imgstenc.SetStencilData(imageStencil_Ijk) imgstenc.ReverseStencilOn() imgstenc.SetBackgroundValue(inVal) imgstenc.Update() return imgstenc.GetOutput()