def setVectorVolume(self): vectorVolume = slicer.vtkMRMLGridTransformNode() slicer.mrmlScene.AddNode(vectorVolume) storageNode = vectorVolume.CreateDefaultStorageNode() slicer.mrmlScene.AddNode(storageNode) vectorVolume.SetAndObserveStorageNodeID(storageNode.GetID()) self.vectorVolume = vectorVolume
def onExportGrid(self): """Converts the current thin plate transform to a grid""" state = self.registationState() # since the transform is ras-to-ras, we find the extreme points # in ras space of the fixed (target) volume and fix the unoriented # box around it. Sample the grid transform at the resolution of # the fixed volume, which may be a bit overkill but it should aways # work without too much loss. rasBounds = [0,]*6 state.fixed.GetRASBounds(rasBounds) from math import floor, ceil origin = map(int,map(floor,rasBounds[::2])) maxes = map(int,map(ceil,rasBounds[1::2])) boundSize = [m - o for m,o in zip(maxes,origin) ] spacing = state.fixed.GetSpacing() samples = [ceil(b / s) for b,s in zip(boundSize,spacing)] extent = [0,]*6 extent[::2] = [0,]*3 extent[1::2] = samples extent = map(int,extent) toGrid = vtk.vtkTransformToGrid() toGrid.SetGridOrigin(origin) toGrid.SetGridSpacing(state.fixed.GetSpacing()) toGrid.SetGridExtent(extent) toGrid.SetInput(state.transform.GetTransformFromParent()) # same in VTKv 5 & 6 toGrid.Update() gridTransform = vtk.vtkGridTransform() if vtk.VTK_MAJOR_VERSION < 6: gridTransform.SetDisplacementGrid(toGrid.GetOutput()) # different in VTKv 5 & 6 else: gridTransform.SetDisplacementGridData(toGrid.GetOutput()) gridNode = slicer.vtkMRMLGridTransformNode() gridNode.SetAndObserveTransformFromParent(gridTransform) gridNode.SetName(state.transform.GetName()+"-grid") slicer.mrmlScene.AddNode(gridNode)
def createAcquisitionTransform(self, volumeNode, metadata): # Creates transform that applies scan conversion transform probeRadius = metadata['CurvatureRadiusProbe'] trackRadius = metadata['CurvatureRadiusTrack'] if trackRadius != 0.0: raise ValueError( f"Curvature Radius (Track) is {trackRadius}. Currently, only volume with zero radius can be imported." ) # Create a sampling grid for the transform import numpy as np spacing = np.array(volumeNode.GetSpacing()) averageSpacing = (spacing[0] + spacing[1] + spacing[2]) / 3.0 voxelsPerTransformControlPoint = 20 # the transform is changing smoothly, so we don't need to add too many control points gridSpacingMm = averageSpacing * voxelsPerTransformControlPoint gridSpacingVoxel = np.floor(gridSpacingMm / spacing).astype(int) gridAxesIJK = [] imageData = volumeNode.GetImageData() extent = imageData.GetExtent() for axis in range(3): gridAxesIJK.append( list( range(extent[axis * 2], extent[axis * 2 + 1] + gridSpacingVoxel[axis], gridSpacingVoxel[axis]))) samplingPoints_shape = [ len(gridAxesIJK[0]), len(gridAxesIJK[1]), len(gridAxesIJK[2]), 3 ] # create a grid transform with one vector at the corner of each slice # the transform is in the same space and orientation as the volume node from __main__ import vtk gridImage = vtk.vtkImageData() gridImage.SetOrigin(*volumeNode.GetOrigin()) gridImage.SetDimensions(samplingPoints_shape[:3]) gridImage.SetSpacing(gridSpacingVoxel[0] * spacing[0], gridSpacingVoxel[1] * spacing[1], gridSpacingVoxel[2] * spacing[2]) gridImage.AllocateScalars(vtk.VTK_DOUBLE, 3) transform = slicer.vtkOrientedGridTransform() directionMatrix = vtk.vtkMatrix4x4() volumeNode.GetIJKToRASDirectionMatrix(directionMatrix) transform.SetGridDirectionMatrix(directionMatrix) transform.SetDisplacementGridData(gridImage) # create the grid transform node gridTransform = slicer.vtkMRMLGridTransformNode() gridTransform.SetName( slicer.mrmlScene.GenerateUniqueName(volumeNode.GetName() + ' acquisition transform')) slicer.mrmlScene.AddNode(gridTransform) gridTransform.SetAndObserveTransformToParent(transform) # populate the grid so that each corner of each slice # is mapped from the source corner to the target corner nshape = tuple(reversed(gridImage.GetDimensions())) import vtk.util.numpy_support nshape = nshape + (3, ) displacements = vtk.util.numpy_support.vtk_to_numpy( gridImage.GetPointData().GetScalars()).reshape(nshape) # Get displacements from math import sin, cos ijkToRas = vtk.vtkMatrix4x4() volumeNode.GetIJKToRASMatrix(ijkToRas) spacing = volumeNode.GetSpacing() center_IJK = [(extent[0] + extent[1]) / 2.0, extent[2], (extent[4] + extent[5]) / 2.0] sourcePoints_RAS = numpy.zeros(shape=samplingPoints_shape) targetPoints_RAS = numpy.zeros(shape=samplingPoints_shape) for k in range(samplingPoints_shape[2]): for j in range(samplingPoints_shape[1]): for i in range(samplingPoints_shape[0]): samplingPoint_IJK = [ gridAxesIJK[0][i], gridAxesIJK[1][j], gridAxesIJK[2][k], 1 ] sourcePoint_RAS = np.array( ijkToRas.MultiplyPoint(samplingPoint_IJK)[:3]) radius = probeRadius - (samplingPoint_IJK[1] - center_IJK[1]) * spacing[1] angleRad = (samplingPoint_IJK[0] - center_IJK[0]) * spacing[0] / probeRadius targetPoint_RAS = np.array([ -radius * sin(angleRad), radius * cos(angleRad) - probeRadius, spacing[2] * (samplingPoint_IJK[2] - center_IJK[2]) ]) displacements[k][j][i] = targetPoint_RAS - sourcePoint_RAS return gridTransform
def demonregister(self, fixedfile, movingfile): print 'Loading fixed from %s' % fixedfile print 'Loading moving from %s' % movingfile slicer.util.loadVolume(fixedfile) # Load fixed volume slicer.util.loadVolume(movingfile) # Load moving Volume fixedimgid = self._findimgid(fixedfile)[0] print 'Found Fixed Image ID: %s' % fixedimgid movingimgid = self._findimgid(movingfile)[0] print 'Found Moving Image ID: %s' % movingimgid fixedvol = slicer.util.getNode(pattern="*%s*" % fixedimgid) movingvol = slicer.util.getNode(pattern="*%s*" % movingimgid) print 'Found Nodes', fixedvol.GetID(), movingvol.GetID() # Create Output Volume if it does not exist outputvol = slicer.util.getNode('outputvol') if outputvol is None: outputvol = slicer.vtkMRMLScalarVolumeNode() outputvol.SetName('outputvol') slicer.mrmlScene.AddNode(outputvol) assert slicer.util.getNode('outputvol') is not None gridtransnode = slicer.vtkMRMLGridTransformNode() self.transname = '%s-%s' % (movingimgid[1:], fixedimgid[1:]) # Avoid from being taken as a volume gridtransnode.SetName(self.transname) slicer.mrmlScene.AddNode(gridtransnode) assert slicer.util.getNode(self.transname) is not None # Set parameters parameters = {} parameters['fixedVolume'] = fixedvol.GetID() parameters['movingVolume'] = movingvol.GetID() parameters['outputVolume'] = outputvol.GetID() parameters['outputDisplacementFieldVolume'] = gridtransnode.GetID() parameters['inputPixelType'] = 'float' parameters['outputPixelType'] = 'float' parameters['interpolationMode'] = 'WindowedSinc' parameters['registrationFilterType'] = 'Diffeomorphic' parameters['smoothDisplacementFieldSigma'] = '1' parameters['numberOfPyramidLevels'] = '5' parameters['numberOfPyramidLevels'] = '5' parameters['minimumFixedPyramid'] = '16,16,16' parameters['minimumMovingPyramid'] = '16,16,16' parameters['arrayOfPyramidLevelIterations'] = '300,50,30,20,15' parameters['numberOfHistogramBins'] = '256' parameters['numberOfMatchPoints'] = '10' parameters['medianFilterSize'] = '0,0,0' parameters['maskProcessingMode'] = 'NOMASK' parameters['lowerThresholdForBOBF'] = '0' parameters['upperThresholdForBOBF'] = '70' parameters['backgroundFillValue'] = '0' parameters['seedForBOBF'] = '0,0,0' parameters['neighborhoodForBOBF'] = '1,1,1' parameters['outputDisplacementFieldPrefix'] = 'none' parameters['checkerboardPatternSubdivisions'] = '4,4,4' parameters['gradient_type'] = '0' parameters['upFieldSmoothing'] = '0' parameters['max_step_length'] = '2' parameters['numberOfBCHApproximationTerms'] = '2' parameters['numberOfThreads'] = str(multiprocessing.cpu_count()) parameters['histogramMatch'] = True # Run Demons Registration CLI demonscli = self.getCLINode(slicer.modules.brainsdemonwarp) self.addObserver(demonscli, self.StatusModifiedEvent, self.onFinishDemon) demonnode = slicer.cli.run(slicer.modules.brainsdemonwarp, demonscli, parameters, wait_for_completion=True) return True