예제 #1
0
def signedDistanceFromPointCloud(mesh,
                                 maxradius=None,
                                 bounds=None,
                                 dims=(20, 20, 20)):
    """
    Compute signed distances over a volume from an input point cloud.
    The output is a ``Volume`` object whose voxels contains the signed distance from
    the cloud.

    :param float maxradius: how far out to propagate distance calculation
    :param list bounds: volume bounds.
    :param list dims: dimensions (nr. of voxels) of the output volume.
    """
    if bounds is None:
        bounds = mesh.GetBounds()
    if maxradius is None:
        maxradius = mesh.diagonalSize() / 10.
    dist = vtk.vtkSignedDistance()
    dist.SetInputData(mesh.polydata(True))
    dist.SetRadius(maxradius)
    dist.SetBounds(bounds)
    dist.SetDimensions(dims)
    dist.Update()
    vol = Volume(dist.GetOutput())
    vol.name = "signedDistanceVolume"
    return vol
예제 #2
0
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)
예제 #4
0
    def __init__(self,
                 infile,
                 grid,
                 radius=2,
                 offset=(0., 0., 0.),
                 toggle_normals=False,
                 sample=20):
        # Catch non-3D grids
        if np.shape(grid.dimensions) != (3, ):
            dim_count = np.shape(grid.dimensions)[0]
            dim_err = "The specified grid has {:n} dimensions, 3 are required"
            raise ValueError(dim_err.format(dim_count))

        self._grid = grid
        self._offset = offset
        self._reader = PolyReader(infile)
        self._norms = NormalCalculator(self._reader, toggle_normals, sample)

        self._dist = vtk.vtkSignedDistance()
        self._dist.SetInputConnection(self._norms.GetOutputPort())

        self._dist.SetRadius(radius * grid.spacing[0])

        self._dist.SetBounds(self._get_bounds())
        self._dist.SetDimensions(self._grid.shape)
        self._dist.Update()

        # Get the SDF as an array
        sdf_array = dsa.WrapDataObject(self._dist.GetOutput())

        # Reshape the array to the grid
        sdf_cube = np.reshape(sdf_array.PointData['ImageScalars'],
                              self._grid.shape[::-1])

        # Swap axis to get [x, y, z] order
        self._array = np.swapaxes(sdf_cube, 0, 2)
예제 #5
0
A mixed example with class vtkSignedDistance:

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())
norms.FlipNormalsOff()
norms.SetNormalOrientationToGraphTraversal()
#norms.SetNormalOrientationToPoint()
#norms.SetOrientationPoint(0.3,0.3,0.3)
norms.Update()

subMapper = vtk.vtkPointGaussianMapper()
subMapper.SetInputConnection(extract.GetOutputPort())
subMapper.EmissiveOff()
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()
예제 #7
0
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