def recoSurface(points, bins=256, c='gold', alpha=1, wire=False, bc='t', legend=None): ''' Surface reconstruction from sparse points. [**Example**](https://github.com/marcomusy/vtkplotter/blob/master/examples/advanced/recosurface.py) ![reco](https://user-images.githubusercontent.com/32848391/46817107-b3263880-cd7e-11e8-985d-f5d158992f0c.png) ''' if isinstance(points, vtk.vtkActor): points = points.coordinates() N = len(points) if N < 50: print('recoSurface: Use at least 50 points.') return None points = np.array(points) ptsSource = vtk.vtkPointSource() ptsSource.SetNumberOfPoints(N) ptsSource.Update() vpts = ptsSource.GetOutput().GetPoints() for i, p in enumerate(points): vpts.SetPoint(i, p) polyData = ptsSource.GetOutput() distance = vtk.vtkSignedDistance() f = 0.1 x0, x1, y0, y1, z0, z1 = polyData.GetBounds() distance.SetBounds(x0-(x1-x0)*f, x1+(x1-x0)*f, y0-(y1-y0)*f, y1+(y1-y0)*f, z0-(z1-z0)*f, z1+(z1-z0)*f) if polyData.GetPointData().GetNormals(): distance.SetInputData(polyData) else: normals = vtk.vtkPCANormalEstimation() normals.SetInputData(polyData) normals.SetSampleSize(int(N/50)) normals.SetNormalOrientationToGraphTraversal() distance.SetInputConnection(normals.GetOutputPort()) print('Recalculating normals for', N, 'points, sample size=', int(N/50)) b = polyData.GetBounds() diagsize = np.sqrt((b[1]-b[0])**2 + (b[3]-b[2])**2 + (b[5]-b[4])**2) radius = diagsize/bins*5 distance.SetRadius(radius) distance.SetDimensions(bins, bins, bins) distance.Update() print('Calculating mesh from points with R =', radius) surface = vtk.vtkExtractSurface() surface.SetRadius(radius * .99) surface.HoleFillingOn() surface.ComputeNormalsOff() surface.ComputeGradientsOff() surface.SetInputConnection(distance.GetOutputPort()) surface.Update() return Actor(surface.GetOutput(), c, alpha, wire, bc, legend)
def recoSurface(points, bins=256, c='gold', alpha=1, wire=False, bc='t', edges=False, legend=None): ''' Surface reconstruction from sparse points. ''' if isinstance(points, vtk.vtkActor): points = vu.coordinates(points) N = len(points) if N < 50: print('recoSurface: Use at least 50 points.') return None points = np.array(points) ptsSource = vtk.vtkPointSource() ptsSource.SetNumberOfPoints(N) ptsSource.Update() vpts = ptsSource.GetOutput().GetPoints() for i, p in enumerate(points): vpts.SetPoint(i, p) polyData = ptsSource.GetOutput() distance = vtk.vtkSignedDistance() f = 0.1 x0, x1, y0, y1, z0, z1 = polyData.GetBounds() distance.SetBounds(x0 - (x1 - x0) * f, x1 + (x1 - x0) * f, y0 - (y1 - y0) * f, y1 + (y1 - y0) * f, z0 - (z1 - z0) * f, z1 + (z1 - z0) * f) if polyData.GetPointData().GetNormals(): distance.SetInputData(polyData) vu.setInput(distance, polyData) else: normals = vtk.vtkPCANormalEstimation() vu.setInput(normals, polyData) normals.SetSampleSize(int(N / 50)) normals.SetNormalOrientationToGraphTraversal() distance.SetInputConnection(normals.GetOutputPort()) print('Recalculating normals for', N, 'points, sample size=', int(N / 50)) radius = vu.diagonalSize(polyData) / bins * 5 distance.SetRadius(radius) distance.SetDimensions(bins, bins, bins) distance.Update() print('Calculating mesh from points with R =', radius) surface = vtk.vtkExtractSurface() surface.SetRadius(radius * .99) surface.HoleFillingOn() surface.ComputeNormalsOff() surface.ComputeGradientsOff() surface.SetInputConnection(distance.GetOutputPort()) surface.Update() return vu.makeActor(surface.GetOutput(), c, alpha, wire, bc, edges, legend)
generate a scalar field by the signed distance from a polydata, save it to stack.tif file, then extract an isosurface from the 3d image. """ from vtkplotter import Plotter, Points, Text, datadir vp = Plotter(verbose=0) act = vp.load(datadir + "290.vtk").normalize().subdivide().computeNormals() # Generate signed distance function and contour it import vtk dist = vtk.vtkSignedDistance() dist.SetInputData(act.polydata()) dist.SetRadius(0.2) # how far out to propagate distance calculation dist.SetBounds(-2, 2, -2, 2, -2, 2) dist.SetDimensions(80, 80, 80) dist.Update() # vp.write(dist.GetOutput(), 'stack.tif') fe = vtk.vtkExtractSurface() fe.SetInputConnection(dist.GetOutputPort()) fe.SetRadius(0.2) # this should match the signed distance radius fe.Update() pts = Points(act.coordinates()) vp.show(fe.GetOutput(), pts, Text(__doc__))
subMapper.SetScaleFactor(0.0) subActor = vtk.vtkActor() subActor.SetMapper(subMapper) # Generate signed distance function and contour it dist = vtk.vtkSignedDistance() dist.SetInputConnection(norms.GetOutputPort()) dist.SetRadius(0.1) #how far out to propagate distance calculation dist.SetBounds(-1,1, -1,1, -1,1) dist.SetDimensions(50,50,50) # Extract the surface with modified flying edges #fe = vtk.vtkFlyingEdges3D() #fe.SetValue(0,0.0) fe = vtk.vtkExtractSurface() fe.SetInputConnection(dist.GetOutputPort()) fe.SetRadius(0.1) # this should match the signed distance radius # Time the execution timer = vtk.vtkTimerLog() timer.StartTimer() fe.Update() timer.StopTimer() time = timer.GetElapsedTime() print("Points processed: {0}".format(NPts)) print(" Time to generate and extract distance function: {0}".format(time)) print(" Resulting bounds: {}".format(fe.GetOutput().GetBounds())) feMapper = vtk.vtkPolyDataMapper() feMapper.SetInputConnection(fe.GetOutputPort())