def pointDensity(mesh, dims=(40, 40, 40), bounds=None, radius=None, computeGradient=False, locator=None): """ Generate a density field from a point cloud. Input can also be a set of 3D coordinates. Output is a ``Volume``. The local neighborhood is specified as the `radius` around each sample position (each voxel). The density is expressed as the number of counts in the radius search. :param int,list dims: numer of voxels in x, y and z of the output Volume. :param bool computeGradient: Turn on/off the generation of the gradient vector, gradient magnitude scalar, and function classification scalar. By default this is off. Note that this will increase execution time and the size of the output. (The names of these point data arrays are: "Gradient", "Gradient Magnitude", and "Classification".) :param vtkStaticPointLocator locator: can be assigned from a previous call for speed. See example script: |pointDensity.py|_ """ if not utils.isSequence(dims): dims = (dims, dims, dims) pdf = vtk.vtkPointDensityFilter() if utils.isSequence(mesh): # user passing coords if len(mesh) == 3: mesh = np.c_[mesh[0], mesh[1], mesh[2]] poly = utils.buildPolyData(mesh) b = poly.GetBounds() diag = np.sqrt((b[1] - b[0])**2 + (b[3] - b[2])**2 + (b[5] - b[4])**2) else: poly = mesh.polydata() b = poly.GetBounds() diag = mesh.diagonalSize() pdf.SetInputData(poly) pdf.SetSampleDimensions(dims) pdf.SetDensityEstimateToFixedRadius() pdf.SetDensityFormToNumberOfPoints() if locator: pdf.SetLocator(locator) if radius is None: radius = diag / 15 pdf.SetRadius(radius) if bounds is None: bounds = b pdf.SetModelBounds(bounds) pdf.SetComputeGradient(computeGradient) pdf.Update() img = pdf.GetOutput() vol = Volume(img) vol.name = "PointDensity" vol.info['radius'] = radius vol.locator = pdf.GetLocator() return vol
extract.SetImplicitFunction(sphere) extract.SetThreshold(0.005) extract.GenerateVerticesOn() # Clip out some of the points with a plane; requires vertices plane = vtk.vtkPlane() plane.SetOrigin(sphere.GetCenter()) plane.SetNormal(1, 1, 1) clipper = vtk.vtkClipPolyData() clipper.SetInputConnection(extract.GetOutputPort()) clipper.SetClipFunction(plane) # Generate density field from points # Use fixed radius dens0 = vtk.vtkPointDensityFilter() dens0.SetInputConnection(clipper.GetOutputPort()) dens0.SetSampleDimensions(res, res, res) dens0.SetDensityEstimateToFixedRadius() dens0.SetRadius(0.05) # dens0.SetDensityEstimateToRelativeRadius() dens0.SetRelativeRadius(2.5) # dens0.SetDensityFormToVolumeNormalized() dens0.SetDensityFormToNumberOfPoints() dens0.ComputeGradientOn() dens0.Update() vrange = dens0.GetOutput().GetPointData().GetArray("Gradient Magnitude").GetRange() # Show the gradient magnitude assign0 = vtk.vtkAssignAttribute() assign0.SetInputConnection(dens0.GetOutputPort())
extract.SetImplicitFunction(sphere) extract.SetThreshold(0.005) extract.GenerateVerticesOn() # Clip out some of the points with a plane; requires vertices plane = vtk.vtkPlane() plane.SetOrigin(sphere.GetCenter()) plane.SetNormal(1,1,1) clipper = vtk.vtkClipPolyData() clipper.SetInputConnection(extract.GetOutputPort()) clipper.SetClipFunction(plane); # Generate density field from points # Use fixed radius dens0 = vtk.vtkPointDensityFilter() dens0.SetInputConnection(clipper.GetOutputPort()) dens0.SetSampleDimensions(res,res,res) dens0.SetDensityEstimateToFixedRadius() dens0.SetRadius(0.05) #dens0.SetDensityEstimateToRelativeRadius() dens0.SetRelativeRadius(2.5) #dens0.SetDensityFormToVolumeNormalized() dens0.SetDensityFormToNumberOfPoints() dens0.ComputeGradientOn() dens0.Update() vrange = dens0.GetOutput().GetPointData().GetArray("Gradient Magnitude").GetRange() # Show the gradient magnitude assign0 = vtk.vtkAssignAttribute() assign0.SetInputConnection(dens0.GetOutputPort())
extract.SetImplicitFunction(sphere) extract.SetThreshold(0.005) extract.GenerateVerticesOn() # Clip out some of the points with a plane; requires vertices plane = vtk.vtkPlane() plane.SetOrigin(sphere.GetCenter()) plane.SetNormal(1,1,1) clipper = vtk.vtkClipPolyData() clipper.SetInputConnection(extract.GetOutputPort()) clipper.SetClipFunction(plane); # Generate density field from points # Use fixed radius dens0 = vtk.vtkPointDensityFilter() dens0.SetInputConnection(clipper.GetOutputPort()) dens0.SetSampleDimensions(res,res,res) dens0.SetDensityEstimateToFixedRadius() dens0.SetRadius(0.05) #dens0.SetDensityEstimateToRelativeRadius() dens0.SetRelativeRadius(2.5) dens0.SetDensityFormToVolumeNormalized() # Time execution timer = vtk.vtkTimerLog() timer.StartTimer() dens0.Update() timer.StopTimer() time = timer.GetElapsedTime() print("Time to compute density field: {0}".format(time))
extract.SetImplicitFunction(sphere) extract.SetThreshold(0.005) extract.GenerateVerticesOn() # Clip out some of the points with a plane; requires vertices plane = vtk.vtkPlane() plane.SetOrigin(sphere.GetCenter()) plane.SetNormal(1, 1, 1) clipper = vtk.vtkClipPolyData() clipper.SetInputConnection(extract.GetOutputPort()) clipper.SetClipFunction(plane) # Generate density field from points # Use fixed radius dens0 = vtk.vtkPointDensityFilter() dens0.SetInputConnection(clipper.GetOutputPort()) dens0.SetSampleDimensions(res, res, res) dens0.SetDensityEstimateToFixedRadius() dens0.SetRadius(0.05) #dens0.SetDensityEstimateToRelativeRadius() dens0.SetRelativeRadius(2.5) dens0.SetDensityFormToVolumeNormalized() # Time execution timer = vtk.vtkTimerLog() timer.StartTimer() dens0.Update() timer.StopTimer() time = timer.GetElapsedTime() print("Time to compute density field: {0}".format(time))
def generateSurfaceModel(self, markupsNode, modelNode, pointDistanceFactor): svnode = slicer.mrmlScene.CreateNodeByClass('vtkMRMLScalarVolumeNode') print('Generating a surface model from tracking data... ') ## Generate a scalar volume node # Get the bounding box print('Calculating bounding box... ') bounds = [0.0] * 6 markupsNode.GetBounds(bounds) print(bounds) b = numpy.array(bounds) b = b.reshape((3, 2)) origin = numpy.mean(b, axis=1) fov = numpy.abs(b[:, 1] - b[:, 0]) fovMax = numpy.max(fov) boundingBoxRange = ( fovMax * 1.5 ) / 2.0 # 1.5 times larger than the bounding box; from the center to the end (1/2 of each dimension) b[:, 0] = origin - boundingBoxRange b[:, 1] = origin + boundingBoxRange bounds = b.reshape(-1) print(bounds) res = 256 print('Converting fiducials to poly data...') poly = self.fiducialsToPoly(markupsNode) #Note: Altenatively, vtkImageEllipsoidSource may be used to generate a volume. # Generate density field from points # Use fixed radius print('Running vtkPointDensityFilter...') dens = vtk.vtkPointDensityFilter() dens.SetInputData(poly) # TODO - is the resolution good enoguh? dens.SetSampleDimensions(res, res, res) dens.SetDensityEstimateToFixedRadius() # TODO - Does this radius work for every case? pixelSize = boundingBoxRange * 2 / res # Note: the algorithm fails when the bounding box is too small.. if pixelSize < 0.5: pixelSize = 0.5 radius = pixelSize dens.SetRadius(radius) #dens.SetDensityEstimateToRelativeRadius() #dens.SetRelativeRadius(2.5) #dens.SetDensityFormToVolumeNormalized() dens.SetDensityFormToNumberOfPoints() dens.SetModelBounds(bounds) dens.ComputeGradientOn() dens.Update() print('Creating an image node...') # Crete an image node - geometric parameters (origin, spacing) must be moved to the node object #imnode = slicer.vtkMRMLScalarVolumeNode() imnode = slicer.mrmlScene.CreateNodeByClass('vtkMRMLScalarVolumeNode') imnode.SetName('MRTracking_SurfaceMap_tmp') imdata = dens.GetOutput() imnode.SetAndObserveImageData(imdata) imnode.SetOrigin(imdata.GetOrigin()) imnode.SetSpacing(imdata.GetSpacing()) #imdata.SetOrigin([0.0, 0.0, 0.0]) #imdata.SetSpacing([1.0, 1.0, 1.0]) slicer.mrmlScene.AddNode(imnode) print('Applying BinaryThreshold...') image = sitkUtils.PullVolumeFromSlicer(imnode.GetID()) binImage = sitk.BinaryThreshold(image, lowerThreshold=1.0, upperThreshold=256, insideValue=1, outsideValue=0) # Calculate the radius parameter for dilation and erosion radiusInPixel = int(numpy.ceil(pointDistanceFactor / pixelSize)) if radiusInPixel < 1.0: radiusInPixel = 1 # Dilate the target label print('Dilating the image...') dilateFilter = sitk.BinaryDilateImageFilter() dilateFilter.SetBoundaryToForeground(False) dilateFilter.SetKernelRadius(radiusInPixel) dilateFilter.SetKernelType(sitk.sitkBall) dilateFilter.SetForegroundValue(1) dilateFilter.SetBackgroundValue(0) dilateImage = dilateFilter.Execute(binImage) # Fill holes in the target label print('Filling holes...') fillHoleFilter = sitk.BinaryFillholeImageFilter() fillHoleFilter.SetForegroundValue(1) fillHoleFilter.SetFullyConnected(True) fillHoleImage = fillHoleFilter.Execute(dilateImage) # Erode the label print('Eroding the image...') erodeFilter = sitk.BinaryErodeImageFilter() erodeFilter.SetBoundaryToForeground(False) erodeFilter.SetKernelType(sitk.sitkBall) erodeFilter.SetKernelRadius( radiusInPixel - 1) # 1 pixel smaller than the radius for dilation. erodeFilter.SetForegroundValue(1) erodeFilter.SetBackgroundValue(0) erodeImage = erodeFilter.Execute(fillHoleImage) print('Pushing the volume to the MRML scene...') sitkUtils.PushVolumeToSlicer(erodeImage, imnode.GetName(), 0, True) imdata = imnode.GetImageData() imdata.SetOrigin(imnode.GetOrigin()) imdata.SetSpacing(imnode.GetSpacing()) print('Running marching cubes...') poly = self.marchingCubes(imdata) modelNode.SetAndObservePolyData(poly) slicer.mrmlScene.RemoveNode(imnode) print('Done.')