def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') # feature edges are used to find any holes in the surface. fedges = vtk.vtkFeatureEdges() fedges.BoundaryEdgesOn() fedges.FeatureEdgesOff() fedges.ManifoldEdgesOff() fedges.SetInputData(self.Surface) fedges.Update() ofedges = fedges.GetOutput() # if numEdges is not 0, then there are holes which need to be capped numEdges = ofedges.GetNumberOfPoints() if numEdges != 0: tempcapper = vmtksurfacecapper.vmtkSurfaceCapper() tempcapper.Surface = self.Surface tempcapper.Interactive = 0 tempcapper.Execute() networkSurface = tempcapper.Surface else: networkSurface = self.Surface # randomly select one cell to delete so that there is an opening for # vmtkNetworkExtraction to use. numCells = self.Surface.GetNumberOfCells() cellToDelete = random.randrange(0, numCells-1) networkSurface.BuildLinks() networkSurface.DeleteCell(cellToDelete) networkSurface.RemoveDeletedCells() # extract the network of approximated centerlines net = vmtknetworkextraction.vmtkNetworkExtraction() net.Surface = networkSurface net.AdvancementRatio = 1.001 net.Execute() network = net.Network convert = vmtkcenterlinestonumpy.vmtkCenterlinesToNumpy() convert.Centerlines = network convert.LogOn = False convert.Execute() ad = convert.ArrayDict cellDataTopology = ad['CellData']['Topology'] # the network topology identifies an the input segment with the "0" id. # since we artificially created this segment, we don't want to use the # ends of the segment as source/target points of the centerline calculation nodeIndexToIgnore = np.where(cellDataTopology[:,0] == 0)[0][0] keepCellConnectivityList = [] pointIdxToKeep = np.array([]) # we remove the cell, points, and point data which are associated with the # segment we want to ignore for loopIdx, cellConnectivityList in enumerate(ad['CellData']['CellPointIds']): if loopIdx == nodeIndexToIgnore: removeCellStartIdx = cellConnectivityList[0] removeCellEndIdx = cellConnectivityList[-1] removeCellLength = cellConnectivityList.size if (removeCellEndIdx + 1) - removeCellStartIdx != removeCellLength: raise(ValueError) continue else: rescaledCellConnectivity = np.subtract(cellConnectivityList, removeCellLength, where=cellConnectivityList >= removeCellLength) keepCellConnectivityList.append(rescaledCellConnectivity) pointIdxToKeep = np.concatenate((pointIdxToKeep, cellConnectivityList)).astype(np.int) newPoints = ad['Points'][pointIdxToKeep] newRadius = ad['PointData']['Radius'][pointIdxToKeep] # precompute the delaunay tessellation for the whole surface. tessalation = vmtkdelaunayvoronoi.vmtkDelaunayVoronoi() tessalation.Surface = networkSurface tessalation.Execute() self.DelaunayTessellation = tessalation.DelaunayTessellation self.VoronoiDiagram = tessalation.VoronoiDiagram self.PoleIds = tessalation.PoleIds # vtk objects cannot be serialized in python. Instead of converting the inputs to numpy arrays and having # to reconstruct the vtk object each time the loop executes (a slow process), we can just pass in the # memory address of the data objects as a string, and use the vtk python bindings to create a python name # referring to the data residing at that memory address. This works because joblib executes each loop # iteration in a fork of the original process, providing access to the original memory space. # However, the process does not work for return arguments, since the original process will not have access to # the memory space of the fork. To return results we use the vmtkCenterlinesToNumpy converter. networkSurfaceMemoryAddress = networkSurface.__this__ delaunayMemoryAddress = tessalation.DelaunayTessellation.__this__ voronoiMemoryAddress = tessalation.VoronoiDiagram.__this__ poleIdsMemoryAddress = tessalation.PoleIds.__this__ # When using Joblib Under Windows, it is important to protect the main loop of code to avoid recursive spawning # of subprocesses. Since we cannot guarantee no code will run outside of “if __name__ == ‘__main__’” blocks # (only imports and definitions), we make Joblib execute each loop iteration serially on windows. # On unix-like os's (linux, Mac) we execute each loop iteration independently on as many cores as the system has. if (sys.platform == 'win32') or (sys.platform == 'win64') or (sys.platform == 'cygwin'): self.PrintLog('Centerlines extraction on windows computer will execute serially.') self.PrintLog('To speed up execution, please run vmtk on unix-like operating system') numParallelJobs = 1 else: numParallelJobs = -1 self.PrintLog('Computing Centerlines ...') # note about the verbose function: while Joblib can print a progress bar output (set verbose = 20), # it does not implement a callback function as of version 0.11, so we cannot report progress to the user # if we are redirecting standard out with the self.PrintLog method. outlist = Parallel(n_jobs=numParallelJobs, backend='multiprocessing', verbose=0)( delayed(_compute_centerlines_network)(networkSurfaceMemoryAddress, delaunayMemoryAddress, voronoiMemoryAddress, poleIdsMemoryAddress, cell, newPoints) for cell in keepCellConnectivityList) out = [] for item in outlist: npConvert = vmtknumpytocenterlines.vmtkNumpyToCenterlines() npConvert.ArrayDict = item npConvert.LogOn = 0 npConvert.Execute() out.append(npConvert.Centerlines) # Append each segment's polydata into a single polydata object centerlineAppender = vtk.vtkAppendPolyData() for data in out: centerlineAppender.AddInputData(data) centerlineAppender.Update() # clean and strip the output centerlines so that redundant points are merged and tracts are combined centerlineCleaner = vtk.vtkCleanPolyData() centerlineCleaner.SetInputData(centerlineAppender.GetOutput()) centerlineCleaner.Update() centerlineStripper = vtk.vtkStripper() centerlineStripper.SetInputData(centerlineCleaner.GetOutput()) centerlineStripper.JoinContiguousSegmentsOn() centerlineStripper.Update() self.Centerlines = centerlineStripper.GetOutput()
def test_methods_with_default_params(aorta_surface_open_ends, method, paramid, compare_surfaces, write_surface): name = __name__ + '_test_methods_with_default_params_' + paramid + '.vtp' capper = surfacecapper.vmtkSurfaceCapper() capper.Surface = aorta_surface_open_ends capper.Method = method capper.Interactive = 0 capper.Execute() write_surface(capper.Surface) assert compare_surfaces(capper.Surface, name) == True
def Execute(self): if self.Surface == None: self.PrintError('Error: No Input Surface.') # Step 0: Check if the surface has any unfilled holes in it. if it does, cap them. fedges = vtk.vtkFeatureEdges() fedges.BoundaryEdgesOn() fedges.FeatureEdgesOff() fedges.ManifoldEdgesOff() fedges.SetInputData(self.Surface) fedges.Update() ofedges = fedges.GetOutput() # if the following is not == 0, then the surface contains unfilled holes. numEdges = ofedges.GetNumberOfPoints() if numEdges >= 1: self.PrintLog('Capping unclosed holes in surface.') tempcapper = vmtksurfacecapper.vmtkSurfaceCapper() tempcapper.Surface = self.Surface tempcapper.LogOn = 0 tempcapper.Interactive = 0 tempcapper.Execute() self.Surface = tempcapper.Surface # Step 1: Convert the input surface into an image mask of unsigned char type and spacing = PolyDataToImageDataSpacing # Where voxels lying inside the surface are set to 255 and voxels outside the image are set to value 0. # since we are creating a new image container from nothing, calculate the origin, extent, and dimensions for the # vtkImageDataObject from the surface parameters. self.PrintLog('Converting Surface to Image Mask') binaryImageFilter = vmtksurfacetobinaryimage.vmtkSurfaceToBinaryImage() binaryImageFilter.Surface = self.Surface binaryImageFilter.InsideValue = 255 binaryImageFilter.LogOn = 0 binaryImageFilter.OutsideValue = 0 binaryImageFilter.PolyDataToImageDataSpacing = self.PolyDataToImageDataSpacing binaryImageFilter.Execute() # Step 2: Feed into the vtkvmtkMedialCurveFilter # This takes the binary image and computes the average outward flux of the image. This is then # used to compute the skeleton image. It returns a binary image where values of 1 are skeleton points # and values of 0 are outside the skeleton. The execution speed of this algorithm is fairly sensetive to # the extent of the input image. self.PrintLog('Extracting Centerline Skeleton from Image Mask...') medialCurveFilter = vtkvmtk.vtkvmtkMedialCurveFilter() medialCurveFilter.SetInputData(binaryImageFilter.Image) medialCurveFilter.SetThreshold(self.Threshold) medialCurveFilter.SetSigma(self.Sigma) medialCurveFilter.Update() self.Image = medialCurveFilter.GetOutput()
def test_smooth_method_with_changing_params(aorta_surface_open_ends, constraint, rings, paramid, compare_surfaces, write_surface): name = __name__ + '_test_smooth_method_with_changing_params_' + paramid + '.vtp' capper = surfacecapper.vmtkSurfaceCapper() capper.Surface = aorta_surface_open_ends capper.Method = 'smooth' capper.ConstraintFactor = constraint capper.NumberOfRings = rings capper.Interactive = 0 capper.Execute() write_surface(capper.Surface) assert compare_surfaces(capper.Surface, name) == True
def surface_capper(input_file, output_file): ''' 将网格变得端口封住 ''' reader = sr.vmtkSurfaceReader() reader.InputFileName = input_file reader.Execute() capper = sc.vmtkSurfaceCapper() capper.Surface = reader.Surface capper.Execute() writer = sw.vmtkSurfaceWriter() writer.OutputFileName = output_file writer.Surface = capper.Surface writer.Mode = 'ascii' writer.Execute()
def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') # feature edges are used to find any holes in the surface. fedges = vtk.vtkFeatureEdges() fedges.BoundaryEdgesOn() fedges.FeatureEdgesOff() fedges.ManifoldEdgesOff() fedges.SetInputData(self.Surface) fedges.Update() ofedges = fedges.GetOutput() # if numEdges is not 0, then there are holes which need to be capped numEdges = ofedges.GetNumberOfPoints() if numEdges != 0: tempcapper = vmtksurfacecapper.vmtkSurfaceCapper() tempcapper.Surface = self.Surface tempcapper.Interactive = 0 tempcapper.Execute() networkSurface = tempcapper.Surface else: networkSurface = self.Surface # randomly select one cell to delete so that there is an opening for # vmtkNetworkExtraction to use. numCells = networkSurface.GetNumberOfCells() cellToDelete = random.randrange(0, numCells-1) networkSurface.BuildLinks() networkSurface.DeleteCell(cellToDelete) networkSurface.RemoveDeletedCells() # extract the network of approximated centerlines net = vmtknetworkextraction.vmtkNetworkExtraction() net.Surface = networkSurface net.AdvancementRatio = 1.001 net.Execute() network = net.Network convert = vmtkcenterlinestonumpy.vmtkCenterlinesToNumpy() convert.Centerlines = network convert.LogOn = False convert.Execute() ad = convert.ArrayDict cellDataTopology = ad['CellData']['Topology'] # the network topology identifies an the input segment with the "0" id. # since we artificially created this segment, we don't want to use the # ends of the segment as source/target points of the centerline calculation nodeIndexToIgnore = np.where(cellDataTopology[:,0] == 0)[0][0] keepCellConnectivityList = [] pointIdxToKeep = np.array([]) removeCellLength = 0 # we remove the cell, points, and point data which are associated with the # segment we want to ignore for loopIdx, cellConnectivityList in enumerate(ad['CellData']['CellPointIds']): if loopIdx == nodeIndexToIgnore: removeCellStartIdx = cellConnectivityList[0] removeCellEndIdx = cellConnectivityList[-1] removeCellLength = cellConnectivityList.size if (removeCellEndIdx + 1) - removeCellStartIdx != removeCellLength: raise(ValueError) continue else: rescaledCellConnectivity = np.subtract(cellConnectivityList, removeCellLength, where=cellConnectivityList >= removeCellLength) keepCellConnectivityList.append(rescaledCellConnectivity) pointIdxToKeep = np.concatenate((pointIdxToKeep, cellConnectivityList)).astype(np.int) newPoints = ad['Points'][pointIdxToKeep] newRadius = ad['PointData']['Radius'][pointIdxToKeep] # precompute the delaunay tessellation for the whole surface. tessalation = vmtkdelaunayvoronoi.vmtkDelaunayVoronoi() tessalation.Surface = networkSurface tessalation.Execute() self.DelaunayTessellation = tessalation.DelaunayTessellation self.VoronoiDiagram = tessalation.VoronoiDiagram self.PoleIds = tessalation.PoleIds # vtk objects cannot be serialized in python. Instead of converting the inputs to numpy arrays and having # to reconstruct the vtk object each time the loop executes (a slow process), we can just pass in the # memory address of the data objects as a string, and use the vtk python bindings to create a python name # referring to the data residing at that memory address. This works because joblib executes each loop # iteration in a fork of the original process, providing access to the original memory space. # However, the process does not work for return arguments, since the original process will not have access to # the memory space of the fork. To return results we use the vmtkCenterlinesToNumpy converter. networkSurfaceMemoryAddress = networkSurface.__this__ delaunayMemoryAddress = tessalation.DelaunayTessellation.__this__ voronoiMemoryAddress = tessalation.VoronoiDiagram.__this__ poleIdsMemoryAddress = tessalation.PoleIds.__this__ # When using Joblib Under Windows, it is important to protect the main loop of code to avoid recursive spawning # of subprocesses. Since we cannot guarantee no code will run outside of “if __name__ == ‘__main__’” blocks # (only imports and definitions), we make Joblib execute each loop iteration serially on windows. # On unix-like os's (linux, Mac) we execute each loop iteration independently on as many cores as the system has. if (sys.platform == 'win32') or (sys.platform == 'win64') or (sys.platform == 'cygwin'): self.PrintLog('Centerlines extraction on windows computer will execute serially.') self.PrintLog('To speed up execution, please run vmtk on unix-like operating system') numParallelJobs = 1 else: numParallelJobs = -1 self.PrintLog('Computing Centerlines ...') # note about the verbose function: while Joblib can print a progress bar output (set verbose = 20), # it does not implement a callback function as of version 0.11, so we cannot report progress to the user # if we are redirecting standard out with the self.PrintLog method. outlist = Parallel(n_jobs=numParallelJobs, backend='multiprocessing', verbose=0)( delayed(_compute_centerlines_network)(networkSurfaceMemoryAddress, delaunayMemoryAddress, voronoiMemoryAddress, poleIdsMemoryAddress, cell, newPoints) for cell in keepCellConnectivityList) out = [] for item in outlist: npConvert = vmtknumpytocenterlines.vmtkNumpyToCenterlines() npConvert.ArrayDict = item npConvert.LogOn = 0 npConvert.Execute() out.append(npConvert.Centerlines) # Append each segment's polydata into a single polydata object centerlineAppender = vtk.vtkAppendPolyData() for data in out: centerlineAppender.AddInputData(data) centerlineAppender.Update() # clean and strip the output centerlines so that redundant points are merged and tracts are combined centerlineCleaner = vtk.vtkCleanPolyData() centerlineCleaner.SetInputData(centerlineAppender.GetOutput()) centerlineCleaner.Update() centerlineStripper = vtk.vtkStripper() centerlineStripper.SetInputData(centerlineCleaner.GetOutput()) centerlineStripper.JoinContiguousSegmentsOn() centerlineStripper.Update() self.Centerlines = centerlineStripper.GetOutput()