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)
def __init__(self, input, toggle_normals, sample): self._norms = vtk.vtkPCANormalEstimation() self._norms.SetInputConnection(input.GetOutputPort()) self._norms.SetSampleSize(sample) if toggle_normals: self._norms.FlipNormalsOn() else: self._norms.FlipNormalsOff() self._norms.SetNormalOrientationToGraphTraversal()
def create_surface_actor(points, n=None, orientationPoint=None, negate=False): """Generate point normals using PCA (principal component analysis). Basically this estimates a local tangent plane around each sample point p by considering a small neighborhood of points around p, and fitting a plane to the neighborhood (via PCA). :param int n: neighborhood size to calculate the normal :param list orientationPoint: adjust the +/- sign of the normals so that the normals all point towards a specified point. If None, perform a traversal of the point cloud and flip neighboring normals so that they are mutually consistent. :param bool negate: flip all normals """ if n is not None: sampleSize = n else: sampleSize = points.GetNumberOfPoints() * .00005 if sampleSize < 10: sampleSize = 10 polydata = vtk.vtkPolyData() polydata.SetPoints(points) print('Estimating normals using PCANormalEstimation') normals = vtk.vtkPCANormalEstimation() normals.SetInputData(polydata) normals.SetSampleSize(sampleSize) if orientationPoint is not None: normals.SetNormalOrientationToPoint() normals.SetOrientationPoint(orientationPoint) else: normals.SetNormalOrientationToGraphTraversal() if negate: normals.FlipNormalsOn() normals.Update() points_array = vtk_to_numpy(points.GetData()) normals_array = vtk_to_numpy( normals.GetOutput().GetPointData().GetNormals()) faces, vertices = poisson_reconstruction(points_array, normals_array, depth=10) return create_mesh_actor(vertices, faces)
def normal_estimation_visual(filename, ply=None): ''' filename:文件名 顶点的法线评估 ''' reader = vtk.vtkSimplePointsReader() reader.SetFileName(filename) reader.Update() polyData = reader.GetOutput() sampleSize = polyData.GetNumberOfPoints() * .00005 if sampleSize < 10: sampleSize = 10 print('Estimating normals using PCANormalEstimation') normals = vtk.vtkPCANormalEstimation() normals.SetInputData(polyData) normals.SetSampleSize(sampleSize) normals.SetNormalOrientationToGraphTraversal() normals.FlipNormalsOff() normals.Update() render(normals.GetOutput(), None, ply)
def normal_estimation_write(infile, outfile): ''' infile:string, 输入的文件路径 outfile:string,输出的文件路径 ''' reader = vtk.vtkSimplePointsReader() reader.SetFileName(infile) reader.Update() polyData = reader.GetOutput() sampleSize = polyData.GetNumberOfPoints() * .00005 if sampleSize < 10: sampleSize = 10 print('Estimating normals using PCANormalEstimation') normals = vtk.vtkPCANormalEstimation() normals.SetInputData(polyData) normals.SetSampleSize(sampleSize) normals.SetNormalOrientationToGraphTraversal() normals.FlipNormalsOn() normals.Update() output = normals.GetOutput() arr_normal = output.GetPointData().GetNormals() num = arr_normal.GetNumberOfTuples() f = codecs.open(outfile, "w") for index in range(num): for i in range(3): f.write("%.6f " % polyData.GetPoint(index)[i]) for i in range(2): f.write("%.6f " % arr_normal.GetTuple(index)[i]) f.write("%.6f\n" % arr_normal.GetTuple(index)[2]) f.close()
points.Update() # Create a sphere implicit function sphere = vtk.vtkSphere() sphere.SetCenter(0,0,0) sphere.SetRadius(0.75) # Extract points along sphere surface extract = vtk.vtkFitImplicitFunction() extract.SetInputConnection(points.GetOutputPort()) extract.SetImplicitFunction(sphere) extract.SetThreshold(0.005) extract.Update() # Now generate normals from resulting points norms = vtk.vtkPCANormalEstimation() norms.SetInputConnection(extract.GetOutputPort()) norms.SetSampleSize(20) norms.FlipNormalsOn() norms.SetNormalOrientationToPoint() norms.SetOrientationPoint(0,0,0) # Time execution timer = vtk.vtkTimerLog() timer.StartTimer() norms.Update() timer.StopTimer() time = timer.GetElapsedTime() print("Points processed: {0}".format(NPts)) print(" Time to generate normals: {0}".format(time)) #print(hBin)
points.Update() # Create a sphere implicit function sphere = vtk.vtkSphere() sphere.SetCenter(0,0,0) sphere.SetRadius(0.75) # Extract points along sphere surface extract = vtk.vtkFitImplicitFunction() extract.SetInputConnection(points.GetOutputPort()) extract.SetImplicitFunction(sphere) extract.SetThreshold(0.005) extract.Update() # Now generate normals from resulting points norms = vtk.vtkPCANormalEstimation() norms.SetInputConnection(extract.GetOutputPort()) norms.SetSampleSize(20) norms.FlipNormalsOn() norms.SetNormalOrientationToGraphTraversal() # Time execution timer = vtk.vtkTimerLog() timer.StartTimer() norms.Update() timer.StopTimer() time = timer.GetElapsedTime() print("Points processed: {0}".format(NPts)) print(" Time to generate normals: {0}".format(time)) #print(hBin) #print(hBin.GetOutput())
def main(argv): colors = vtk.vtkNamedColors() polyData = ReadPolyData({True: argv[1], False: ""}[len(argv) > 1]) bounds = polyData.GetBounds() rng = [0, 0, 0] for i in range(3): rng[i] = bounds[2 * i + 1] - bounds[2 * i] sampleSize = polyData.GetNumberOfPoints() * .00005 if (sampleSize < 10): sampleSize = 10 print("Sample size is: %d" % (sampleSize)) normals = vtk.vtkPCANormalEstimation() normals.SetInputData(polyData) normals.SetSampleSize(sampleSize) normals.SetNormalOrientationToGraphTraversal() normals.FlipNormalsOn() print("Range: %f, %f, %f" % (rng[0], rng[1], rng[2])) dimension = 256 dimension = 128 radius = rng[0] / float(dimension) * 5 # ~5 voxels print("Radius: %f" % (radius)) distance = vtk.vtkSignedDistance() distance.SetInputConnection(normals.GetOutputPort()) distance.SetRadius(radius) distance.SetDimensions(dimension, dimension, dimension) distance.SetBounds(bounds[0] - rng[0] * 0.1, bounds[1] + rng[0] * 0.1, bounds[2] - rng[1] * 0.1, bounds[3] + rng[1] * 0.1, bounds[4] - rng[2] * 0.1, bounds[5] + rng[2] * 0.1) # Create a lookup table that consists of the full hue circle # (from HSV). belowRangeColor = colors.GetColor4d("Black") belowRangeColor[3] = 0.2 aboveRangeColor = colors.GetColor4d("White") aboveRangeColor[3] = 0.2 hueLut = vtk.vtkLookupTable() hueLut.SetTableRange(-0.99 * radius, 0.99 * radius) hueLut.SetHueRange(0.667, 0) hueLut.SetSaturationRange(1, 1) hueLut.SetValueRange(1, 1) hueLut.UseBelowRangeColorOn() hueLut.SetBelowRangeColor(belowRangeColor) hueLut.UseAboveRangeColorOn() hueLut.SetAboveRangeColor(aboveRangeColor) hueLut.SetNumberOfColors(5) hueLut.Build() last = hueLut.GetTableValue(4) hueLut.SetAboveRangeColor(last[0], last[1], last[2], 0) sagittalColors = vtk.vtkImageMapToColors() sagittalColors.SetInputConnection(distance.GetOutputPort()) sagittalColors.SetLookupTable(hueLut) sagittalColors.Update() sagittal = vtk.vtkImageActor() sagittal.GetMapper().SetInputConnection(sagittalColors.GetOutputPort()) sagittal.SetDisplayExtent(dimension // 2, dimension // 2, 0, dimension - 1, 0, dimension - 1) sagittal.ForceOpaqueOn() axialColors = vtk.vtkImageMapToColors() axialColors.SetInputConnection(distance.GetOutputPort()) axialColors.SetLookupTable(hueLut) axialColors.Update() axial = vtk.vtkImageActor() axial.GetMapper().SetInputConnection(axialColors.GetOutputPort()) axial.SetDisplayExtent(0, dimension - 1, 0, dimension - 1, dimension // 2, dimension // 2) axial.ForceOpaqueOn() coronalColors = vtk.vtkImageMapToColors() coronalColors.SetInputConnection(distance.GetOutputPort()) coronalColors.SetLookupTable(hueLut) coronalColors.Update() coronal = vtk.vtkImageActor() coronal.GetMapper().SetInputConnection(coronalColors.GetOutputPort()) coronal.SetDisplayExtent(0, dimension - 1, dimension // 2, dimension // 2, 0, dimension - 1) coronal.ForceOpaqueOn() # Create a scalar bar scalarBar = vtk.vtkScalarBarActor() scalarBar.SetLookupTable(hueLut) scalarBar.SetTitle("Distance") scalarBar.SetNumberOfLabels(5) # Create graphics stuff # ren1 = vtk.vtkRenderer() ren1.SetBackground(colors.GetColor3d("CornflowerBlue")) renWin = vtk.vtkRenderWindow() renWin.AddRenderer(ren1) renWin.SetSize(600, 400) renWin.SetWindowName("SignedDistance") iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(renWin) # Add the actors to the renderer, set the background and size # ren1.AddActor(sagittal) ren1.AddActor(axial) ren1.AddActor(coronal) ren1.AddActor2D(scalarBar) # Generate an interesting view # ren1.ResetCamera() ren1.GetActiveCamera().Azimuth(120) ren1.GetActiveCamera().Elevation(30) ren1.GetActiveCamera().Dolly(1.5) ren1.ResetCameraClippingRange() renWin.Render() iren.Initialize() iren.Start() print("%f, %f" % (distance.GetOutput().GetScalarRange()[0], distance.GetOutput().GetScalarRange()[1])) return distance