Example #1
0
    def onDisplayMeshButton(self):
        logic = PointCloudRegistrationLogic()
        # Display target points
        self.targetModelNode = slicer.util.loadModel(
            self.targetModelSelector.currentPath)
        blue = [0, 0, 1]

        # Display aligned source points
        self.sourceModelNode = slicer.util.loadModel(
            self.sourceModelSelector.currentPath)
        points = slicer.util.arrayFromModelPoints(self.sourceModelNode)
        points[:] = np.asarray(self.sourceData.points)
        self.sourceModelNode.GetPolyData().GetPoints().GetData().Modified()
        self.sourceModelNode.SetAndObserveTransformNodeID(
            self.ICPTransformNode.GetID())
        slicer.vtkSlicerTransformLogic().hardenTransform(self.sourceModelNode)
        logic.RAS2LPSTransform(self.sourceModelNode)
        red = [1, 0, 0]
        self.sourceModelNode.GetDisplayNode().SetColor(red)

        self.sourceCloudNode.GetDisplayNode().SetVisibility(False)
        self.targetCloudNode.GetDisplayNode().SetVisibility(False)
        sourceLM_vtk = logic.loadAndScaleFiducials(
            self.sourceFiducialSelector.currentPath, self.scaling)
        transform_vtk = self.ICPTransformNode.GetMatrixTransformToParent()
        self.alignedSourceLM_vtk = logic.applyTransform(
            transform_vtk, sourceLM_vtk)
        self.alignedSourceLM_np = vtk_np.vtk_to_numpy(
            self.alignedSourceLM_vtk.GetPoints().GetData())
        inputPoints = logic.exportPointCloud(self.alignedSourceLM_np,
                                             "Landmarks")
        green = [0, 1, 0]
        inputPoints.GetDisplayNode().SetColor(green)
        logic.RAS2LPSTransform(inputPoints)
        inputPoints.GetDisplayNode().SetPointLabelsVisibility(True)
Example #2
0
    def onAlignButton(self):
        logic = PointCloudRegistrationLogic()
        self.transformMatrix = logic.estimateTransform(
            self.sourcePoints, self.targetPoints, self.sourceFeatures,
            self.targetFeatures, self.voxelSize, self.parameterDictionary)
        self.ICPTransformNode = logic.convertMatrixToTransformNode(
            self.transformMatrix, 'Rigid Transformation Matrix')

        # For later analysis, apply transform to VTK arrays directly
        transform_vtk = self.ICPTransformNode.GetMatrixTransformToParent()
        self.alignedSourceSLM_vtk = logic.applyTransform(
            transform_vtk, self.sourceSLM_vtk)

        # Display aligned source points using transform that can be viewed/edited in the scene
        red = [1, 0, 0]
        self.sourceCloudNode = logic.displayPointCloud(self.sourceSLM_vtk,
                                                       self.voxelSize / 10,
                                                       'Source Pointcloud',
                                                       red)
        self.sourceCloudNode.SetAndObserveTransformNodeID(
            self.ICPTransformNode.GetID())
        slicer.vtkSlicerTransformLogic().hardenTransform(self.sourceCloudNode)
        logic.RAS2LPSTransform(self.sourceCloudNode)
        self.updateLayout()

        # Enable next step of analysis
        self.displayMeshButton.enabled = True
Example #3
0
    def flip(self, volumeNode, transformMatrix):
        transform = slicer.vtkMRMLTransformNode()
        transform.SetName('FlipTransformation')
        slicer.mrmlScene.AddNode(transform)
        transform.SetMatrixTransformFromParent(transformMatrix)

        volumeNode.SetAndObserveTransformNodeID(transform.GetID())
        slicer.vtkSlicerTransformLogic().hardenTransform(volumeNode)
        slicer.mrmlScene.RemoveNode(transform)
Example #4
0
 def RAS2LPSTransform(self, modelNode):
     matrix = vtk.vtkMatrix4x4()
     matrix.Identity()
     matrix.SetElement(0, 0, -1)
     matrix.SetElement(1, 1, -1)
     transform = vtk.vtkTransform()
     transform.SetMatrix(matrix)
     transformNode = slicer.mrmlScene.AddNewNodeByClass(
         'vtkMRMLTransformNode', 'RAS2LPS')
     transformNode.SetAndObserveTransformToParent(transform)
     modelNode.SetAndObserveTransformNodeID(transformNode.GetID())
     slicer.vtkSlicerTransformLogic().hardenTransform(modelNode)
     slicer.mrmlScene.RemoveNode(transformNode)
Example #5
0
def register_and_resample(input_node, reference_node, transform_node=None, interpolationMode="Linear"):
    # when loaded with slicer, the matrix in tfm file is multiplied with LPS_to_RAS transforms from both sides
    # furthermore the transformNode will be set to FromParent instead of ToParent, which has the same effect
    # as inverting it before application to the volume node

    if transform_node:
        # make a temporary copy of the input node on which the transform can be hardened
        copy_input_node = slicer.modules.volumes.logic().CloneVolume(slicer.mrmlScene, input_node, "translated")
        copy_input_node.SetAndObserveTransformNodeID(transform_node.GetID())
        logic = slicer.vtkSlicerTransformLogic()
        logic.hardenTransform(copy_input_node)
        print("hardened transformation")
    else:
        copy_input_node = slicer.modules.volumes.logic().CloneVolume(slicer.mrmlScene, input_node, "copy")

    # resample volume
    registered_and_resampled_node = slicer.mrmlScene.AddNewNodeByClass(copy_input_node.GetClassName())
    parameters = {
        "inputVolume": copy_input_node,
        "referenceVolume": reference_node,
        "outputVolume": registered_and_resampled_node,
        "interpolationMode": interpolationMode,
        "defaultValue": 0.0,
    }
    slicer.cli.run(slicer.modules.brainsresample, None, parameters, wait_for_completion=True)
    slicer.mrmlScene.RemoveNode(copy_input_node)  # remove temporary copy of input node
    registered_and_resampled_node.SetName(input_node.GetName() + "_registered_and_resampled")
    return registered_and_resampled_node
def harden_transform(polydata, transform, inverse, outdir):

    polydata_base_path, polydata_name = os.path.split(polydata)
    output_name = os.path.join(outdir, polydata_name)

    if os.path.exists(output_name):
        return

    check_load, polydata_node = slicer.util.loadModel(str(polydata), 1)
    if not check_load:
        print('Could not load polydata file:', polydata)
        return

    check_load, transform_node = slicer.util.loadTransform(str(transform), 1)
    if not check_load:
        print('Could not load transform file:', transform)
        return

    if inverse == "1":
        transform_node.Inverse()

    logic = slicer.vtkSlicerTransformLogic()
    t_node_id = transform_node.GetID()

    # harden transform
    polydata_node.SetAndObserveTransformNodeID(t_node_id)
    logic.hardenTransform(polydata_node)

    slicer.util.saveNode(polydata_node, output_name)
Example #7
0
  def export(self, node, extension, writerFilter, allExtensionsFilter = "", transformedFlag = False):
    if transformedFlag:
      shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene)
      itemIDToClone = shNode.GetItemByDataNode(node)
      clonedItemID = slicer.modules.subjecthierarchy.logic().CloneSubjectHierarchyItem(shNode, itemIDToClone)
      clonedNode = shNode.GetItemDataNode(clonedItemID)

      transformNode = slicer.mrmlScene.GetNodeByID(node.GetTransformNodeID())
      clonedNode.SetAndObserveTransformNodeID(transformNode.GetID())

      transformLogic = slicer.vtkSlicerTransformLogic()
      transformLogic.hardenTransform(clonedNode)

      node = clonedNode

    fileFilter = allExtensionsFilter + ";;" + writerFilter + ";;All files *"
    fileName = qt.QFileDialog.getSaveFileName(slicer.util.mainWindow(),
                                            "Export As...", node.GetName()+extension, fileFilter, None, qt.QFileDialog.DontUseNativeDialog)
    if not fileName.endswith(extension):
        fileName = fileName + extension
    if fileName == "":
      return
    writerType = slicer.app.coreIOManager().fileWriterFileType(node)
    success = slicer.app.coreIOManager().saveNodes(writerType, {"nodeID": node.GetID(), "fileName": fileName})
    if success:
      logging.info(f"Exported {node.GetName()} to {fileName}")
    else:
      slicer.util.errorDisplay(f"Could not save {node.GetName()} to {fileName}")

    if transformedFlag:
      slicer.mrmlScene.RemoveNode(clonedNode.GetStorageNode())
      slicer.mrmlScene.RemoveNode(clonedNode.GetDisplayNode())
      slicer.mrmlScene.RemoveNode(clonedNode)
def harden_transform(polydata, transform, inverse, outdir):

    check_load, polydata_node = slicer.util.loadModel(str(polydata), 1)
    if not check_load:
        print 'Could not load polydata file:', polydata
        return

    check_load, transform_node = slicer.util.loadTransform(str(transform), 1)
    if not check_load:
        print 'Could not load transform file:', transform
        return

    if inverse == "1":
        transform_node.Inverse()

    logic = slicer.vtkSlicerTransformLogic()
    t_node_id = transform_node.GetID()

    # harden transform
    polydata_node.SetAndObserveTransformNodeID(t_node_id)
    logic.hardenTransform(polydata_node)

    polydata_base_path, polydata_name = os.path.split(polydata)
    output_name = polydata_name
    slicer.util.saveNode(polydata_node, os.path.join(outdir, output_name))
    def onAlignButtonTB(self):

        self.RWButton.enabled = False
        self.alignButtonTB.enabled = False

        self.landmarkTransform = slicer.vtkMRMLTransformNode()
        slicer.mrmlScene.AddNode(self.landmarkTransform)

        logic = AlignCrop3DSlicerModuleLogic()
        if(self.movingFiducialNode.GetNumberOfFiducials() > 2):
            logic.runAlignmentRegistration(self.landmarkTransform, self.templateFidTB, self.movingFiducialNode, self.placementListTB)
        else:
            slicer.util.infoDisplay("At least 3 fiducials required for registration to proceed")

        #Apply Landmark transform on input Volume & Fiducials and Harden
        self.inputVolumeTB.SetAndObserveTransformNodeID(self.landmarkTransform.GetID())
        slicer.vtkSlicerTransformLogic().hardenTransform(self.inputVolumeTB)
        self.movingFiducialNode.SetAndObserveTransformNodeID(self.landmarkTransform.GetID())
        slicer.vtkSlicerTransformLogic().hardenTransform(self.movingFiducialNode)


        #TODO - Align output is incorrect!! Investigate (Jan 17th - 2018)

        #Set template to foreground in Slice Views
        applicationLogic 	= slicer.app.applicationLogic()
        selectionNode 		= applicationLogic.GetSelectionNode()
        selectionNode.SetSecondaryVolumeID(self.templateVolumeTB.GetID())
        applicationLogic.PropagateForegroundVolumeSelection(0)

        #set overlap of foreground & background in slice view
        sliceLayout = slicer.app.layoutManager()
        sliceLogicR = sliceLayout.sliceWidget('Red').sliceLogic()
        compositeNodeR = sliceLogicR.GetSliceCompositeNode()
        compositeNodeR.SetForegroundOpacity(0.5)
        sliceLogicY = sliceLayout.sliceWidget('Yellow').sliceLogic()
        compositeNodeY = sliceLogicY.GetSliceCompositeNode()
        compositeNodeY.SetForegroundOpacity(0.5)
        sliceLogicG = sliceLayout.sliceWidget('Green').sliceLogic()
        compositeNodeG = sliceLogicG.GetSliceCompositeNode()
        compositeNodeG.SetForegroundOpacity(0.5)

        #centre slice viewer on image
        slicer.app.applicationLogic().FitSliceToAll()
        #Make Atlas Fidcials visible
        self.templateFidTB.SetDisplayVisibility(1)
Example #10
0
  def applySkyscanTransform(self, volumeNode):
    #set up transform node
    transformNode = slicer.vtkMRMLTransformNode()
    slicer.mrmlScene.AddNode(transformNode)
    volumeNode.SetAndObserveTransformNodeID(transformNode.GetID())

    #set up Skyscan transform
    transformMatrixNp  = np.array([[1,0,0,0],[0,0,1,0],[0,1,0,0],[0,0,0,1]])
    transformMatrixVTK = vtk.vtkMatrix4x4()
    for row in range(4):
      for col in range(4):
        transformMatrixVTK.SetElement(row, col, transformMatrixNp[row,col])
        
    transformNode.SetMatrixTransformToParent(transformMatrixVTK) 
    
    #harden and clean up
    slicer.vtkSlicerTransformLogic().hardenTransform(volumeNode) 
    slicer.mrmlScene.RemoveNode(transformNode)
Example #11
0
	def onAlignButton(self):

		self.RWButton.enabled = False
		#Create Landmark transform placeholder
		self.LandmarkTrans = slicer.vtkMRMLTransformNode()
		slicer.mrmlScene.AddNode(self.LandmarkTrans)

		logic = AValue3DSlicerModuleLogic()

		#Run fiducial registration
		if(self.placedLandmarkNode.GetNumberOfFiducials() == 4):
			logic.runFiducialRegistration(self.rightAtlas.isChecked(), self.LandmarkTrans, self.placedLandmarkNode)
		else:
			slicer.util.infoDisplay("4 Fiducials required for registration") #TODO - add appropriate information to help user!

		#Apply Landmark transform on Atlas Volume then Harden
		self.atlasVolume.SetAndObserveTransformNodeID(self.LandmarkTrans.GetID())
		slicer.vtkSlicerTransformLogic().hardenTransform(self.atlasVolume)
		#Apply Landmark transform on Fiduicals then Harden
		self.atlasFid.SetAndObserveTransformNodeID(self.LandmarkTrans.GetID())
		slicer.vtkSlicerTransformLogic().hardenTransform(self.atlasFid)

		#Set Atlas to foreground in Slice Views
		applicationLogic 	= slicer.app.applicationLogic()
		selectionNode 		= applicationLogic.GetSelectionNode()
		selectionNode.SetSecondaryVolumeID(self.atlasVolume.GetID())
		applicationLogic.PropagateForegroundVolumeSelection(0)

		#set overlap of foreground & background in slice view
		sliceLayout = slicer.app.layoutManager()
		sliceLogicR = sliceLayout.sliceWidget('Red').sliceLogic()
		compositeNodeR = sliceLogicR.GetSliceCompositeNode()
		compositeNodeR.SetForegroundOpacity(0.4)
		sliceLogicY = sliceLayout.sliceWidget('Yellow').sliceLogic()
		compositeNodeY = sliceLogicY.GetSliceCompositeNode()
		compositeNodeY.SetForegroundOpacity(0.4)
		sliceLogicG = sliceLayout.sliceWidget('Green').sliceLogic()
		compositeNodeG = sliceLogicG.GetSliceCompositeNode()
		compositeNodeG.SetForegroundOpacity(0.4)

		self.defineCropButton.enabled	= True # enabled next step "Defining Crop region of interest"
		self.placedLandmarkNode.SetDisplayVisibility(0) #turn off display of placed landmarks -TODO - Is this needed
Example #12
0
    def runCleaning(self, projectedLM, sphere, spacingPercentage):
        # Convert projected surface points to a VTK array for transform
        p = [0, 0, 0]
        targetPoints = vtk.vtkPoints()
        for i in range(projectedLM.GetNumberOfFiducials()):
            projectedLM.GetMarkupPoint(0, i, p)
            targetPoints.InsertNextPoint(p)

        # Set up a transform between the sphere and the points projected to the surface
        transform = vtk.vtkThinPlateSplineTransform()
        transform.SetSourceLandmarks(sphere.GetPolyData().GetPoints())
        transform.SetTargetLandmarks(targetPoints)
        transform.SetBasisToR()

        # Apply the transform to the sphere to create a model with spherical topology
        transformNode = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLTransformNode", "TPS")
        transformNode.SetAndObserveTransformToParent(transform)
        sphere.SetAndObserveTransformNodeID(transformNode.GetID())
        slicer.vtkSlicerTransformLogic().hardenTransform(sphere)
        sphere.SetDisplayVisibility(False)

        # Clean up semi-landmarks within radius
        filter = vtk.vtkCleanPolyData()
        filter.SetToleranceIsAbsolute(False)
        filter.SetTolerance(spacingPercentage / 2)
        filter.SetInputData(sphere.GetPolyData())
        filter.Update()
        cleanPolyData = filter.GetOutput()

        # Create a landmark node from the cleaned polyData
        sphereSampleLMNode = slicer.mrmlScene.AddNewNodeByClass(
            'vtkMRMLMarkupsFiducialNode', "PseudoLandmarks")
        sphereSampleLMNode.CreateDefaultDisplayNodes()
        for i in range(cleanPolyData.GetNumberOfPoints()):
            point = cleanPolyData.GetPoint(i)
            sphereSampleLMNode.AddFiducialFromArray(point)

        landmarkTypeSemi = True
        self.setAllLandmarksType(sphereSampleLMNode, landmarkTypeSemi)
        return sphereSampleLMNode
 def createIntermediateHardenModel(self, model):
     hardenModel = slicer.mrmlScene.GetNodesByName("SurfaceRegistration_" + model.GetName() + "_hardenCopy_" + str(
         slicer.app.applicationPid())).GetItemAsObject(0)
     if hardenModel is None:
         hardenModel = slicer.vtkMRMLModelNode()
     hardenPolyData = vtk.vtkPolyData()
     hardenPolyData.DeepCopy(model.GetPolyData())
     hardenModel.SetAndObservePolyData(hardenPolyData)
     hardenModel.SetName(
         "SurfaceRegistration_" + model.GetName() + "_hardenCopy_" + str(slicer.app.applicationPid()))
     if model.GetParentTransformNode():
         hardenModel.SetAndObserveTransformNodeID(model.GetParentTransformNode().GetID())
     hardenModel.HideFromEditorsOn()
     slicer.mrmlScene.AddNode(hardenModel)
     logic = slicer.vtkSlicerTransformLogic()
     logic.hardenTransform(hardenModel)
     return hardenModel
 def transformNode(self, node, matrix):
   transform = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLLinearTransformNode')
   transformMatrix = vtk.vtkMatrix4x4()
   transformMatrix.Zero()
   
   for row in range(4):
     for col in range(4): 
       transformMatrix.SetElement(row, col, matrix[row][col])
   
   transform.SetMatrixTransformToParent(transformMatrix) 
   
   # Apply transform to node... 
   node.SetAndObserveTransformNodeID(transform.GetID())    
   # ... and harden it
   transformLogic = slicer.vtkSlicerTransformLogic()
   transformLogic.hardenTransform(node)
   # delete transform node
   slicer.mrmlScene.RemoveNode(transform)
 def createIntermediateHardenModel(self, model):
     hardenModel = slicer.mrmlScene.GetNodesByName(
         "SurfaceRegistration_" + model.GetName() + "_hardenCopy_" +
         str(slicer.app.applicationPid())).GetItemAsObject(0)
     if hardenModel is None:
         hardenModel = slicer.vtkMRMLModelNode()
     hardenPolyData = vtk.vtkPolyData()
     hardenPolyData.DeepCopy(model.GetPolyData())
     hardenModel.SetAndObservePolyData(hardenPolyData)
     hardenModel.SetName("SurfaceRegistration_" + model.GetName() +
                         "_hardenCopy_" + str(slicer.app.applicationPid()))
     if model.GetParentTransformNode():
         hardenModel.SetAndObserveTransformNodeID(
             model.GetParentTransformNode().GetID())
     hardenModel.HideFromEditorsOn()
     slicer.mrmlScene.AddNode(hardenModel)
     logic = slicer.vtkSlicerTransformLogic()
     logic.hardenTransform(hardenModel)
     return hardenModel
 def isUnderTransform(self, markups):
     if markups.GetParentTransformNode():
         messageBox = ctk.ctkMessageBox()
         messageBox.setWindowTitle(" /!\ WARNING /!\ ")
         messageBox.setIcon(messageBox.Warning)
         messageBox.setText("Your Markup Fiducial Node is currently modified by a transform,"
                            "if you choose to continue the program will apply the transform"
                            "before doing anything else!")
         messageBox.setInformativeText("Do you want to continue?")
         messageBox.setStandardButtons(messageBox.No | messageBox.Yes)
         choice = messageBox.exec_()
         if choice == messageBox.Yes:
             logic = slicer.vtkSlicerTransformLogic()
             logic.hardenTransform(markups)
             return False
         else:
             messageBox.setText(" Node not modified")
             messageBox.setStandardButtons(messageBox.Ok)
             messageBox.setInformativeText("")
             messageBox.exec_()
             return True
     else:
         return False
 def isUnderTransform(self, markups):
     if markups.GetParentTransformNode():
         messageBox = ctk.ctkMessageBox()
         messageBox.setWindowTitle(" /!\ WARNING /!\ ")
         messageBox.setIcon(messageBox.Warning)
         messageBox.setText(
             "Your Markup Fiducial Node is currently modified by a transform,"
             "if you choose to continue the program will apply the transform"
             "before doing anything else!")
         messageBox.setInformativeText("Do you want to continue?")
         messageBox.setStandardButtons(messageBox.No | messageBox.Yes)
         choice = messageBox.exec_()
         if choice == messageBox.Yes:
             logic = slicer.vtkSlicerTransformLogic()
             logic.hardenTransform(markups)
             return False
         else:
             messageBox.setText(" Node not modified")
             messageBox.setStandardButtons(messageBox.Ok)
             messageBox.setInformativeText("")
             messageBox.exec_()
             return True
     else:
         return False
Example #18
0
    def run(self, templateMesh, templateLM, templateSLM, meshDirectory,
            lmDirectory, slmDirectory, outDirectory, signedDistanceOption):

        if (bool(templateSLM) and bool(slmDirectory)):
            templateLMTotal = self.mergeLandmarks(templateLM, templateSLM)
        else:
            templateLMTotal = templateLM
        #get template points as vtk array
        templatePoints = vtk.vtkPoints()
        p = [0, 0, 0]
        for i in range(templateLMTotal.GetNumberOfMarkups()):
            templateLMTotal.GetMarkupPoint(0, i, p)
            templatePoints.InsertNextPoint(p)

        # write selected triangles to table
        tableNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLTableNode',
                                                       'Mean Mesh Distances')
        col1 = tableNode.AddColumn()
        col1.SetName('Subject ID')
        col2 = tableNode.AddColumn()
        col2.SetName('Mesh RMSE')
        tableNode.SetColumnType('Subject ID', vtk.VTK_STRING)
        tableNode.SetColumnType('Mean Mesh Distance', vtk.VTK_STRING)

        subjectCount = 0
        for meshFileName in os.listdir(meshDirectory):
            if (not meshFileName.startswith(".")):
                #get corresponding landmarks
                lmFilePath, subjectID = self.findCorrespondingFilePath(
                    lmDirectory, meshFileName)
                if (lmFilePath):
                    currentLMNode = slicer.util.loadMarkupsFiducialList(
                        lmFilePath)
                    if bool(slmDirectory):  # add semi-landmarks if present
                        slmFilePath, sID = self.findCorrespondingFilePath(
                            slmDirectory, meshFileName)
                        if (slmFilePath):
                            currentSLMNode = slicer.util.loadMarkupsFiducialList(
                                slmFilePath)
                            currentLMTotal = self.mergeLandmarks(
                                templateLM, currentSLMNode)
                        else:
                            print("problem with reading semi-landmarks")
                            return False
                    else:
                        currentLMTotal = currentLMNode
                else:
                    print("problem with reading landmarks")
                    return False
                    # if mesh and lm file with same subject id exist, load into scene
                meshFilePath = os.path.join(meshDirectory, meshFileName)
                currentMeshNode = slicer.util.loadModel(meshFilePath)

                #get subject points into vtk array
                subjectPoints = vtk.vtkPoints()
                p = [0, 0, 0]
                for i in range(currentLMTotal.GetNumberOfMarkups()):
                    currentLMTotal.GetMarkupPoint(0, i, p)
                    subjectPoints.InsertNextPoint(p)

                transform = vtk.vtkThinPlateSplineTransform()
                transform.SetSourceLandmarks(subjectPoints)
                transform.SetTargetLandmarks(templatePoints)
                transform.SetBasisToR()  # for 3D transform

                transformNode = slicer.mrmlScene.AddNewNodeByClass(
                    "vtkMRMLTransformNode", "TPS")
                transformNode.SetAndObserveTransformToParent(transform)

                currentMeshNode.SetAndObserveTransformNodeID(
                    transformNode.GetID())
                slicer.vtkSlicerTransformLogic().hardenTransform(
                    currentMeshNode)

                distanceFilter = vtk.vtkDistancePolyDataFilter()
                distanceFilter.SetInputData(0, templateMesh.GetPolyData())
                distanceFilter.SetInputData(1, currentMeshNode.GetPolyData())
                distanceFilter.SetSignedDistance(signedDistanceOption)
                distanceFilter.Update()

                distanceMap = distanceFilter.GetOutput()
                distanceArray = distanceMap.GetPointData().GetArray('Distance')
                #meanDistance = np.average(distanceArray)
                meanDistance = self.rmse(distanceArray)

                #save output distance map
                outputNode = slicer.mrmlScene.AddNewNodeByClass(
                    "vtkMRMLModelNode", "ouputDistanceMap")
                outputNode.SetAndObservePolyData(distanceMap)
                outputFilename = os.path.join(outDirectory,
                                              str(subjectID) + '.vtp')
                slicer.util.saveNode(outputNode, outputFilename)

                #update table and subjectCount
                tableNode.AddEmptyRow()
                tableNode.SetCellText(subjectCount, 0, str(subjectID))
                tableNode.SetCellText(subjectCount, 1, str(meanDistance))
                subjectCount += 1

                # clean up
                slicer.mrmlScene.RemoveNode(outputNode)
                slicer.mrmlScene.RemoveNode(transformNode)
                slicer.mrmlScene.RemoveNode(currentMeshNode)
                slicer.mrmlScene.RemoveNode(currentLMNode)
Example #19
0
  def onrunTransformButtonClicked(self):
	  
    inputDirPath = self.inputDirSelector.currentPath
    outputDirPath = self.outputDirSelector.currentPath
    transformFilePath = self.transformationSelector.currentPath
	  
    if not (inputDirPath) or not (outputDirPath) or not (transformFilePath):
      qt.QMessageBox.critical(slicer.util.mainWindow(),
          'Harden Transform', 'Tranformation file, input and output directories are required')
      return
	# model files with these extensions are loaded and transformed
    extensions = ('.vtk', '.vtp', '.stl', '.ply')

    # function to check if a dir2 is a subdirectory of dir1
    # returns true if dir2 is a subdirectory of dir1 or dir1 == dir2
    def is_subdir(dir1, dir2):
      path = os.path.realpath(dir1)
      directory = os.path.realpath(dir2)
      relative = os.path.relpath(dir1, dir2)
      return not (relative == os.pardir or relative.startswith(os.pardir + os.sep))  

    # check if input and output folders are identical or output is subdirectory of input, if so, do nothing to avoid overwriting
    if is_subdir(inputDirPath,outputDirPath):
	  qt.QMessageBox.critical(slicer.util.mainWindow(),'Harden Transform', 'Please select an output directory that is different from the input directory and not a subdirectory of the input to avoid overwriting')
    else:
      # load transform file
      checkSuccessT, transformNode = slicer.util.loadTransform(str(transformFilePath),returnNode = True)
      if not checkSuccessT:
		  print 'Could not load transform file'
		  qt.QMessageBox.information(slicer.util.mainWindow(),'Harden Transform', 'Could not load transform file')
		  exit()

      logic = slicer.vtkSlicerTransformLogic()
      tNodeID = transformNode.GetID()
      
      transformCounter = 0;
      for root, subfolders, files in os.walk(inputDirPath):
        for file in files:
		  # only consider model filetypes slicer an read and write (vtk,vtp,stl,ply)
          ext = os.path.splitext(file)[-1].lower()
          if ext in extensions:
            filePath = os.path.join(root,file)
            checkSuccessM, modelNode = slicer.util.loadModel(filePath,returnNode = True)
            if not checkSuccessM:
              print 'Could not load model file ' + str(filepath)
              qt.QMessageBox.information(slicer.util.mainWindow(),'Harden Transform', 'Could not load model file' + str(filepath))

            modelFileName, modelFileExt = os.path.splitext(ntpath.basename(filePath))

            modelNode.SetAndObserveTransformNodeID(tNodeID)
                      
            # harden transform
            logic.hardenTransform(modelNode)    

            ## save transformed node
            # if file with this name already exists in the output folder, append '_new'
            app = ''
            while os.path.isfile(os.path.join(outputDirPath,os.path.splitext(ntpath.basename(file))[0]+app+modelFileExt)):
              app += '_new'

            newFileName = modelFileName+app+modelFileExt
            slicer.util.saveNode(modelNode, os.path.join(outputDirPath,newFileName)) 

            slicer.mrmlScene.RemoveNode(modelNode)

            transformCounter += 1

    slicer.mrmlScene.RemoveNode(transformNode)
    statusString = 'Transformed ' + str(transformCounter) + ' models'
    print statusString
    qt.QMessageBox.information(slicer.util.mainWindow(),'Harden Transform', statusString)
Example #20
0
	def run(self, inputVolume, outputVolume, atlasVolume, initialTrans, outputTrans, atlasFid):
		"""
		Run the actual algorithm
		"""
		#check appropriate volume is selected
		if not self.isValidInputOutputData(inputVolume, outputVolume):
			slicer.util.errorDisplay('Input volume is the same as output volume. Choose a different output volume.')
			return False

		logging.info('.....Printing Initial Transform....')
		logging.info(initialTrans)

		#Create intermediate linear transform node
		self.linearTrans = slicer.vtkMRMLTransformNode()
		slicer.mrmlScene.AddNode(self.linearTrans)

		#Set parameters and run affine registration Step 1
		cliParamsAffine = { 'fixedVolume' 		: inputVolume.GetID(),
							'movingVolume'		: atlasVolume.GetID(),
							'linearTransform' 	: self.linearTrans.GetID() }
		cliParamsAffine.update({'samplingPercentage'	: 1,
								'initialTransformMode' 	: 'off',
								'transformType'			: 'Affine'})
		cliParamsAffine.update({'numberOfIterations' 	: 3000,
								'minimumStepLength'		: 0.00001,
								'maximumStepLength'		: 0.05})
		cliAffineTransREG = slicer.cli.run(slicer.modules.brainsfit, None, cliParamsAffine, wait_for_completion=True)

		logging.info('....Printing Affine Transform....')
		logging.info(self.linearTrans)

		#Apply linear transform result from step 1 on Atlas Volume
		atlasVolume.SetAndObserveTransformNodeID(self.linearTrans.GetID())
		slicer.vtkSlicerTransformLogic().hardenTransform(atlasVolume)

		# Set parameters and run BSpline registration Step 2
		cliParams = {	'fixedVolume'		: inputVolume.GetID(),
		 				'movingVolume'		: atlasVolume.GetID(),
						'bsplineTransform' 	: outputTrans.GetID() }
						#'initialTransform' 	: self.linearTrans.GetID()
		cliParams.update({	'samplingPercentage'	: 1,
		 					'initialTransfomMode' 	: 'off' })
		cliParams.update({	'transformType'	: 'BSpline',
							'splineGridSize': '3,3,3'})
		cliParams.update({	'numberOfIterations' 	: 3000,
		 					'minimumStepLength'		: 0.00001,
							'maximumStepLength'		: 0.05})
		cliParams.update({'costMetric' : 'NC' })
		cliBSplineREG = slicer.cli.run(slicer.modules.brainsfit, None, cliParams, wait_for_completion=True)

		logging.info('....Printing BSpline Transform....')
		logging.info(outputTrans)

		#Apply BSpline transform on A-Value Fiducials
		atlasFid.SetAndObserveTransformNodeID(outputTrans.GetID())
		slicer.vtkSlicerTransformLogic().hardenTransform(atlasFid)

		#Calculate New A-Value
		numOfFids = atlasFid.GetNumberOfFiducials()
		fidXYZ_RW = [0,0,0] #Round Window placeholder
		fidXYZ_LW = [0,0,0] #Lateral Wall placeholder
		print numOfFids
		for index in range(numOfFids):
			if index == 0:
				atlasFid.GetNthFiducialPosition(index, fidXYZ_RW)
				print fidXYZ_RW
			else:
				atlasFid.GetNthFiducialPosition(index, fidXYZ_LW)
				print fidXYZ_LW

		newAValue = math.sqrt(	((fidXYZ_RW[0] - fidXYZ_LW[0])**2) + \
								((fidXYZ_RW[1] - fidXYZ_LW[1])**2) + \
								((fidXYZ_LW[2] - fidXYZ_RW[2])**2)		)


		#Calculating CDL Estimates
		AlexiadesCDLoc 	= 4.16 * newAValue - 4 		#CDL estimate from Alexiades et al. (2015)
		KochCDLoc 		= 4.16 * newAValue - 5.05	#CDL estimate from Koch et al. (2017)
		KochCDLlw		= 3.86 * newAValue + 4.99	#CDL estimtae from Koch et al. (2017)

		#Display Patient ID and Estimated A Valuee
		outputDisp = "Patient ID:\n" + inputVolume.GetName() + \
					"\n\nEstimated A Value:\n" + format(newAValue, '0.1f') + 'mm\n\n' + \
					"Estimated CDL Values\n" + "CDL(oc)-1: " + format(AlexiadesCDLoc, '0.1f') + 'mm\n' + \
					"CDL(oc)-2: " + format(KochCDLoc, '0.1f') + "mm\n" + \
					"CDL(lw)-1: " + format(KochCDLlw, '0.1f') + "mm\n"

		slicer.util.infoDisplay(outputDisp)

		logging.info('Processing completed') #TODO - Deal with output Volume!!

		return True
Example #21
0
    def run(self, landmarkDirectory, meshDirectory, gridLandmarks,
            outputDirectory):
        #read all landmarks
        #landmarks = self.getLandmarks(landmarkDirectory)
        #print("landmark file shape: ", landmarks.shape)
        #[landmarkNumber,dim,subjectNumber] = landmarks.shape
        #get grid points
        #newGridPoints = self.getGridPoints(landmarks, gridLandmarks)
        #reflect gridPoints onto each surface
        #meshList = self.getAllSubjectMeshes(meshDirectory)
        #for i in range(subjectNumber):
        #mesh = self.readMesh(meshList(i))
        #stickToSurface(newGridPoints(:,:,i), mesh)
        # save semi-landmarks
        #self.saveSemiLandmarks(newGridPoints, outputDirectory)

        #Read data
        S = slicer.util.getNode("gor_skull")
        L = slicer.util.getNode("Gorilla_template_LM1")
        surfacePolydata = S.GetPolyData()

        # Set up point locator for later
        pointLocator = vtk.vtkPointLocator()
        pointLocator.SetDataSet(surfacePolydata)
        pointLocator.BuildLocator()
        #set up locater for intersection with normal vector rays
        obbTree = vtk.vtkOBBTree()
        obbTree.SetDataSet(surfacePolydata)
        obbTree.BuildLocator()

        #Set up fiducial grid
        print("Set up grid")
        fiducialPoints = vtk.vtkPoints()
        point = [0, 0, 0]
        for pt in range(L.GetNumberOfControlPoints()):
            L.GetMarkupPoint(pt, 0, point)
            fiducialPoints.InsertNextPoint(point)

        fiducialPolydata = vtk.vtkPolyData()
        fiducialPolydata.SetPoints(fiducialPoints)
        delaunayFilter = vtk.vtkDelaunay2D()
        delaunayFilter.SetInputData(fiducialPolydata)
        delaunayFilter.Update()
        fiducialMesh = delaunayFilter.GetOutput()
        fiducialMeshModel = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLModelNode", "fiducialMesh")
        fiducialMeshModel.SetAndObservePolyData(fiducialMesh)

        #Set up triangle grid for projection
        gridPoints = vtk.vtkPoints()
        sampleRate = 3

        for row in range(sampleRate):
            for col in range(sampleRate):
                if (row + col) < sampleRate:
                    gridPoints.InsertNextPoint(row, col, 0)

        gridPolydata = vtk.vtkPolyData()
        gridPolydata.SetPoints(gridPoints)

        #Set up source and target for triangle transform
        sourcePoints = vtk.vtkPoints()
        targetPoints = vtk.vtkPoints()

        sourcePoints.InsertNextPoint(gridPoints.GetPoint(0))
        sourcePoints.InsertNextPoint(gridPoints.GetPoint(sampleRate - 1))
        sourcePoints.InsertNextPoint(
            gridPoints.GetPoint(gridPoints.GetNumberOfPoints() - 1))

        #set up transform
        transform = vtk.vtkThinPlateSplineTransform()
        transform.SetSourceLandmarks(sourcePoints)
        transform.SetBasisToR()
        transformNode = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLTransformNode", "TPS")
        transformNode.SetAndObserveTransformToParent(transform)

        #Iterate through each triangle in fiducial mesh and project sampled triangle
        idList = vtk.vtkIdList()
        triangleArray = fiducialMesh.GetPolys()
        triangleArray.InitTraversal()

        #define new landmark sets
        semilandmarkPoints = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLMarkupsFiducialNode", "semiLM")
        gridPoints = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLMarkupsFiducialNode", "grid")

        print("Iterate through cells")
        #iterate through each triangle cell in the landmark mesh
        for triangle in range(4):  #(triangleArray.GetNumberOfCells()):
            print("Semilandmark n: ",
                  semilandmarkPoints.GetNumberOfFiducials())
            print("Triangle: ", triangle)
            triangleArray.GetNextCell(idList)
            print(idList)
            targetPoints.Reset()
            for verticeIndex in range(3):
                verticeID = idList.GetId(verticeIndex)
                verticeLocation = fiducialMesh.GetPoint(verticeID)
                targetPoints.InsertNextPoint(verticeLocation)
                print("Adding target point: ", verticeLocation)

            transform.SetTargetLandmarks(targetPoints)
            model = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLModelNode",
                                                       "mesh_resampled")
            model.SetAndObservePolyData(gridPolydata)
            model.SetAndObserveTransformNodeID(transformNode.GetID())
            slicer.vtkSlicerTransformLogic().hardenTransform(model)
            transformedPolydata = model.GetPolyData()

            # #get surface normal from each landmark point
            rayDirection = [0, 0, 0]
            normalArray = surfacePolydata.GetPointData().GetArray("Normals")

            # #calculate average normal from cell landmarks
            for verticeIndex in range(3):
                verticeLocation = targetPoints.GetPoint(verticeIndex)
                closestPointId = pointLocator.FindClosestPoint(verticeLocation)
                tempNormal = normalArray.GetTuple(closestPointId)
                print("Normal: ", tempNormal)
                rayDirection[0] += tempNormal[0]
                rayDirection[1] += tempNormal[1]
                rayDirection[2] += tempNormal[2]

            for dim in range(len(rayDirection)):
                rayDirection[dim] = rayDirection[dim] / 3

            #get a sample distance for quality control
            m1 = model.GetPolyData().GetPoint(0)
            m2 = model.GetPolyData().GetPoint(1)
            #sampleDistance = 3*abs( (m1[0] - m2[0])+(m1[1] - m2[1])+ (m1[2] - m2[2]))
            sampleDistance = fiducialMesh.GetLength() / 10
            print("Sample distance: ", sampleDistance)

            # iterate through each point in the resampled triangle
            for index in range(model.GetPolyData().GetNumberOfPoints()):
                print("Point: ", index)
                modelPoint = model.GetPolyData().GetPoint(index)
                gridPoints.AddFiducialFromArray(modelPoint)
                rayEndPoint = [0, 0, 0]
                for dim in range(len(rayEndPoint)):
                    rayEndPoint[
                        dim] = modelPoint[dim] + rayDirection[dim] * 1000
                intersectionIds = vtk.vtkIdList()
                intersectionPoints = vtk.vtkPoints()
                obbTree.IntersectWithLine(modelPoint, rayEndPoint,
                                          intersectionPoints, intersectionIds)
                #print("Intersections: ", intersectionIds.GetNumberOfIds())
                #if there are intersections, update the point to most external one.
                if intersectionPoints.GetNumberOfPoints() > 0:
                    exteriorPoint = intersectionPoints.GetPoint(
                        intersectionPoints.GetNumberOfPoints() - 1)
                    projectionDistance = abs(
                        (exteriorPoint[0] - modelPoint[0]) +
                        (exteriorPoint[1] - modelPoint[1]) +
                        (exteriorPoint[2] - modelPoint[2]))
                    semilandmarkPoints.AddFiducialFromArray(exteriorPoint)
                #if there are no intersections, reverse the normal vector
                else:
                    for dim in range(len(rayEndPoint)):
                        rayEndPoint[
                            dim] = modelPoint[dim] + rayDirection[dim] * -1000
                    obbTree.IntersectWithLine(modelPoint, rayEndPoint,
                                              intersectionPoints,
                                              intersectionIds)
                    if intersectionPoints.GetNumberOfPoints() > 0:
                        exteriorPoint = intersectionPoints.GetPoint(0)
                        projectionDistance = abs(
                            (exteriorPoint[0] - modelPoint[0]) +
                            (exteriorPoint[1] - modelPoint[1]) +
                            (exteriorPoint[2] - modelPoint[2]))
                        if projectionDistance < sampleDistance:
                            semilandmarkPoints.AddFiducialFromArray(
                                exteriorPoint)
                        else:
                            print("projectionDistance distance: ",
                                  projectionDistance)
                            closestPointId = pointLocator.FindClosestPoint(
                                modelPoint)
                            rayOrigin = surfacePolydata.GetPoint(
                                closestPointId)
                            semilandmarkPoints.AddFiducialFromArray(rayOrigin)

                    #if none in reverse direction, use closest mesh point
                    else:
                        closestPointId = pointLocator.FindClosestPoint(
                            modelPoint)
                        rayOrigin = surfacePolydata.GetPoint(closestPointId)
                        semilandmarkPoints.AddFiducialFromArray(rayOrigin)
            #remove temporary model node
            #slicer.mrmlScene.RemoveNode(model)

        slicer.mrmlScene.RemoveNode(transformNode)
        return True
Example #22
0
    def applyPatch(self,
                   meshNode,
                   LMNode,
                   gridLandmarks,
                   sampleRate,
                   polydataNormalArray,
                   maximumProjectionDistance=.25):
        surfacePolydata = meshNode.GetPolyData()

        gridPoints = vtk.vtkPoints()

        gridPoints.InsertNextPoint(0, 0, 0)
        gridPoints.InsertNextPoint(0, sampleRate - 1, 0)
        gridPoints.InsertNextPoint(sampleRate - 1, 0, 0)
        for row in range(1, sampleRate - 1):
            for col in range(1, sampleRate - 1):
                if (row + col) < (sampleRate - 1):
                    gridPoints.InsertNextPoint(row, col, 0)

        gridPolydata = vtk.vtkPolyData()
        gridPolydata.SetPoints(gridPoints)

        sourcePoints = vtk.vtkPoints()
        targetPoints = vtk.vtkPoints()

        sourcePoints.InsertNextPoint(gridPoints.GetPoint(0))
        sourcePoints.InsertNextPoint(gridPoints.GetPoint(1))
        sourcePoints.InsertNextPoint(gridPoints.GetPoint(2))

        point = [0, 0, 0]
        for gridVertex in gridLandmarks:
            LMNode.GetMarkupPoint(0, int(gridVertex - 1), point)
            targetPoints.InsertNextPoint(point)

        #transform grid to triangle
        transform = vtk.vtkThinPlateSplineTransform()
        transform.SetSourceLandmarks(sourcePoints)
        transform.SetTargetLandmarks(targetPoints)
        transform.SetBasisToR()

        transformNode = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLTransformNode", "TPS")
        transformNode.SetAndObserveTransformToParent(transform)

        model = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLModelNode",
                                                   "mesh_resampled")
        model.SetAndObservePolyData(gridPolydata)
        model.SetAndObserveTransformNodeID(transformNode.GetID())
        slicer.vtkSlicerTransformLogic().hardenTransform(model)

        resampledPolydata = model.GetPolyData()

        pointLocator = vtk.vtkPointLocator()
        pointLocator.SetDataSet(surfacePolydata)
        pointLocator.BuildLocator()

        #get surface normal from each landmark point
        rayDirection = [0, 0, 0]

        for gridVertex in gridLandmarks:
            LMNode.GetMarkupPoint(0, int(gridVertex - 1), point)
            closestPointId = pointLocator.FindClosestPoint(point)
            tempNormal = polydataNormalArray.GetTuple(closestPointId)
            rayDirection[0] += tempNormal[0]
            rayDirection[1] += tempNormal[1]
            rayDirection[2] += tempNormal[2]

        #normalize
        vtk.vtkMath().Normalize(rayDirection)

        # # get normal at each grid point
        # gridNormals = np.zeros((3,3))
        # gridIndex=0
        # for gridVertex in gridLandmarks:
        # print(gridVertex)
        # LMNode.GetMarkupPoint(0,int(gridVertex-1),point)
        # closestPointId = pointLocator.FindClosestPoint(point)
        # tempNormal = polydataNormalArray.GetTuple(closestPointId)
        # print(tempNormal)
        # gridNormals[gridIndex] = tempNormal
        # gridIndex+=1
        # print(gridNormals)

        #set up locater for intersection with normal vector rays
        obbTree = vtk.vtkOBBTree()
        obbTree.SetDataSet(surfacePolydata)
        obbTree.BuildLocator()

        #define new landmark sets
        semilandmarkNodeName = "semiLM_" + str(gridLandmarks[0]) + "_" + str(
            gridLandmarks[1]) + "_" + str(gridLandmarks[2])
        semilandmarkPoints = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLMarkupsFiducialNode", semilandmarkNodeName)

        #get a sample distance for quality control
        m1 = model.GetPolyData().GetPoint(0)
        m2 = model.GetPolyData().GetPoint(1)
        m3 = model.GetPolyData().GetPoint(2)
        d1 = math.sqrt(vtk.vtkMath().Distance2BetweenPoints(m1, m2))
        d2 = math.sqrt(vtk.vtkMath().Distance2BetweenPoints(m2, m3))
        d3 = math.sqrt(vtk.vtkMath().Distance2BetweenPoints(m1, m3))
        sampleDistance = (d1 + d2 + d3)

        # set initial three grid points
        for index in range(0, 3):
            origLMPoint = resampledPolydata.GetPoint(index)
            #landmarkLabel = LMNode.GetNthFiducialLabel(gridLandmarks[index]-1)
            landmarkLabel = str(gridLandmarks[index])
            semilandmarkPoints.AddFiducialFromArray(origLMPoint, landmarkLabel)

        # calculate maximum projection distance
        projectionTolerance = maximumProjectionDistance / .25
        #boundingBox = vtk.vtkBoundingBox()
        #boundingBox.AddBounds(surfacePolydata.GetBounds())
        #diagonalDistance = boundingBox.GetDiagonalLength()
        #rayLength = math.sqrt(diagonalDistance) * projectionTolerance
        rayLength = sampleDistance * projectionTolerance

        # get normal projection intersections for remaining semi-landmarks
        for index in range(3, resampledPolydata.GetNumberOfPoints()):
            modelPoint = resampledPolydata.GetPoint(index)

            # ## get estimated normal vector
            # rayDirection = [0,0,0]
            # distance1=math.sqrt(vtk.vtkMath().Distance2BetweenPoints(modelPoint,resampledPolydata.GetPoint(0)))
            # distance2=math.sqrt(vtk.vtkMath().Distance2BetweenPoints(modelPoint,resampledPolydata.GetPoint(1)))
            # distance3=math.sqrt(vtk.vtkMath().Distance2BetweenPoints(modelPoint,resampledPolydata.GetPoint(2)))
            # distanceTotal = distance1 + distance2 + distance3
            # weights=[(distance3+distance2)/distanceTotal, (distance1+distance3)/distanceTotal,(distance1+distance2)/distanceTotal]

            # for gridIndex in range(0,3):
            # rayDirection+=(weights[gridIndex]*gridNormals[gridIndex])
            # vtk.vtkMath().Normalize(rayDirection)
            # ##

            rayEndPoint = [0, 0, 0]
            for dim in range(len(rayEndPoint)):
                rayEndPoint[
                    dim] = modelPoint[dim] + rayDirection[dim] * rayLength
            intersectionIds = vtk.vtkIdList()
            intersectionPoints = vtk.vtkPoints()
            obbTree.IntersectWithLine(modelPoint, rayEndPoint,
                                      intersectionPoints, intersectionIds)
            #if there are intersections, update the point to most external one.
            if intersectionPoints.GetNumberOfPoints() > 0:
                exteriorPoint = intersectionPoints.GetPoint(
                    intersectionPoints.GetNumberOfPoints() - 1)
                semilandmarkPoints.AddFiducialFromArray(exteriorPoint)
            #if there are no intersections, reverse the normal vector
            else:
                for dim in range(len(rayEndPoint)):
                    rayEndPoint[
                        dim] = modelPoint[dim] + rayDirection[dim] * -rayLength
                obbTree.IntersectWithLine(modelPoint, rayEndPoint,
                                          intersectionPoints, intersectionIds)
                if intersectionPoints.GetNumberOfPoints() > 0:
                    exteriorPoint = intersectionPoints.GetPoint(0)
                    semilandmarkPoints.AddFiducialFromArray(exteriorPoint)
                else:
                    print("No intersection, using closest point")
                    closestPointId = pointLocator.FindClosestPoint(modelPoint)
                    rayOrigin = surfacePolydata.GetPoint(closestPointId)
                    semilandmarkPoints.AddFiducialFromArray(rayOrigin)

        # update lock status and color
        semilandmarkPoints.SetLocked(True)
        semilandmarkPoints.GetDisplayNode().SetColor(random.random(),
                                                     random.random(),
                                                     random.random())
        semilandmarkPoints.GetDisplayNode().SetSelectedColor(
            random.random(), random.random(), random.random())
        semilandmarkPoints.GetDisplayNode().PointLabelsVisibilityOff()
        #clean up
        slicer.mrmlScene.RemoveNode(transformNode)
        slicer.mrmlScene.RemoveNode(model)
        print("Total points:", semilandmarkPoints.GetNumberOfFiducials())
        return semilandmarkPoints
  def run(self, inputT1Volume, inputFLAIRVolume, inputT2Volume, inputPDVolume,
          inputFAVolume, inputADCVolume, returnSpace, isBET, isMNI,
          lesionLoad, isLongitudinal, numberFollowUp, balanceHI, outputFolder,
          cutFraction, samplingPerc, grid, initiationMethod, numberOfThreads):
    """
    Run the actual algorithm
    """

    #
    # Defines reference image modality based on pre-defined order if data is not in MNI space
    #
    if not isMNI:
      if inputT1Volume is not None:
        referenceVolume = inputT1Volume
        logging.info('T1 volume found. Will be used as reference space.')
      elif inputT2Volume is not None:
        referenceVolume = inputT2Volume
        logging.info('T2 volume found. Will be used as reference space.')
      elif inputFLAIRVolume is not None:
        referenceVolume = inputFLAIRVolume
        logging.info('FLAIR volume found. Will be used as reference space.')
      elif inputPDVolume is not None:
        referenceVolume = inputPDVolume
        logging.info('PD volume found. Will be used as reference space.')
      else:
        logging.info('ERROR: At least one structural image should be provided. Aborting.')
        return False

    #
    # Defines count variable for step progression log
    #
    currentStep = 1

    logging.info('Processing started')
    slicer.util.showStatusMessage("Processing started")
    #
    # Data space normalization to T1 space
    #
    volumesLogic = slicer.modules.volumes.logic()
    if not isMNI:
      if inputT2Volume is not None and inputT2Volume is not referenceVolume:
        try:
          slicer.util.showStatusMessage("Pre-processing: Conforming T2 volume to reference space...")
          regT2toRefTransform = slicer.vtkMRMLLinearTransformNode()
          slicer.mrmlScene.AddNode(regT2toRefTransform)
          clonedT2Volume = volumesLogic.CloneVolume(slicer.mrmlScene, inputT2Volume, "Cloned T2")

          self.conformInputSpace(referenceVolume, inputT2Volume, inputT2Volume, regT2toRefTransform, numberOfThreads)
        except:
          logging.info("Exception caught when trying to conform T2 image to reference space.")
      if inputFLAIRVolume is not None and inputFLAIRVolume is not referenceVolume:
        try:
          slicer.util.showStatusMessage("Pre-processing: Conforming T2-FLAIR volume to reference space...")
          regFLAIRtoRefTransform = slicer.vtkMRMLLinearTransformNode()
          slicer.mrmlScene.AddNode(regFLAIRtoRefTransform)
          clonedFLAIRVolume = volumesLogic.CloneVolume(slicer.mrmlScene, inputFLAIRVolume, "Cloned FLAIR")

          self.conformInputSpace(referenceVolume, inputFLAIRVolume, inputFLAIRVolume, regFLAIRtoRefTransform, numberOfThreads)
        except:
          logging.info("Exception caught when trying to create node for T2-FLAIR image in reference space.")
      if inputPDVolume is not None and inputPDVolume is not referenceVolume:
        try:
          slicer.util.showStatusMessage("Pre-processing: Conforming PD volume to reference space...")
          regPDtoRefTransform = slicer.vtkMRMLLinearTransformNode()
          slicer.mrmlScene.AddNode(regPDtoRefTransform)
          clonedPDVolume = volumesLogic.CloneVolume(slicer.mrmlScene, inputPDVolume, "Cloned PD")

          self.conformInputSpace(referenceVolume, inputPDVolume, inputPDVolume, regPDtoRefTransform, numberOfThreads)
        except:
          logging.info("Exception caught when trying to create node for PD image in reference space.")
      if inputFAVolume is not None:
        try:
          slicer.util.showStatusMessage("Pre-processing: Conforming DTI-FA map to reference space...")
          regFAtoRefTransform = slicer.vtkMRMLLinearTransformNode()
          slicer.mrmlScene.AddNode(regFAtoRefTransform)
          clonedFAVolume = volumesLogic.CloneVolume(slicer.mrmlScene, inputFAVolume, "Cloned FA")

          self.conformInputSpace(referenceVolume, inputFAVolume, inputFAVolume, regFAtoRefTransform, numberOfThreads)
        except:
          logging.info("Exception caught when trying to create node for FA image in reference space.")
      if inputADCVolume is not None:
        try:
          slicer.util.showStatusMessage("Pre-processing: Conforming DTI-ADC map to reference space...")
          regADCtoRefTransform = slicer.vtkMRMLLinearTransformNode()
          slicer.mrmlScene.AddNode(regADCtoRefTransform)
          clonedADCVolume = volumesLogic.CloneVolume(slicer.mrmlScene, inputADCVolume, "Cloned ADC")

          self.conformInputSpace(referenceVolume, inputADCVolume, inputADCVolume, regADCtoRefTransform, numberOfThreads)
        except:
          logging.info("Exception caught when trying to create node for ADC image in reference space.")

    slicer.util.showStatusMessage("Step "+str(currentStep)+": Reading brain templates...")
    logging.info("Step "+str(currentStep)+": Reading brain templates...")
    currentStep+=1

    modulePath = os.path.dirname(slicer.modules.mslesionsimulator.path)

    if platform.system() is "Windows":

      databasePath = modulePath + "\\Resources\\MSlesion_database"
    else:

      databasePath = modulePath + "/Resources/MSlesion_database"

    if isBET:
      if platform.system() is "Windows":
        (readSuccess, MNINode)=slicer.util.loadVolume(databasePath+"\\MNI152_T1_1mm_brain.nii.gz",{},True)
      else:
        (readSuccess,MNINode)=slicer.util.loadVolume(databasePath + "/MNI152_T1_1mm_brain.nii.gz",{},True)
    else:
      if platform.system() is "Windows":
        (readSuccess, MNINode)=slicer.util.loadVolume(databasePath + "\\MNI152_T1_1mm.nii.gz",{},True)
      else:
        (readSuccess, MNINode)=slicer.util.loadVolume(databasePath + "/MNI152_T1_1mm.nii.gz",{},True)

    if not isMNI:
      #
      # Registration between Input Image and MNI Image Space
      #

      slicer.util.showStatusMessage("Step " + str(currentStep) + ": MNI152 template to native space...")
      logging.info("Step " + str(currentStep) + ": MNI152 template to native space...")
      currentStep += 1

      MNI_ref = slicer.vtkMRMLScalarVolumeNode()
      slicer.mrmlScene.AddNode(MNI_ref)
      regMNItoRefTransform = slicer.vtkMRMLBSplineTransformNode()
      slicer.mrmlScene.AddNode(regMNItoRefTransform)

      self.doNonLinearRegistration(referenceVolume, MNINode, MNI_ref, regMNItoRefTransform, samplingPerc, grid, initiationMethod, numberOfThreads)

    #
    # Find lesion mask using Probability Image, lesion labels and desired Lesion Load
    #
    slicer.util.showStatusMessage("Step "+str(currentStep)+": Simulating MS lesion map...")
    logging.info("Step "+str(currentStep)+": Simulating MS lesion map...")
    currentStep+=1

    lesionMap = slicer.vtkMRMLLabelMapVolumeNode()
    slicer.mrmlScene.AddNode(lesionMap)
    if platform.system() is "Windows":
      self.doGenerateMask(MNINode, lesionLoad, lesionMap, databasePath+"\\labels-database")
    else:
      self.doGenerateMask(MNINode, lesionLoad, lesionMap, databasePath + "/labels-database")


    # Transforming lesion map to native space

    if not isMNI:
      # Get transform logic for hardening transforms
      transformLogic = slicer.vtkSlicerTransformLogic()

      self.applyRegistrationTransform(lesionMap,referenceVolume,lesionMap,regMNItoRefTransform,False, True)
      transformLogic.hardenTransform(lesionMap)

    # Filtering lesion map to minimize or exclude regions outside of WM
    if inputT1Volume is not None:
      # Lesion Map: T1
      lesionMapT1 = slicer.vtkMRMLLabelMapVolumeNode()
      slicer.mrmlScene.AddNode(lesionMapT1)
      lesionMapT1.SetName("T1_lesion_label")
      self.doFilterMask(inputT1Volume, lesionMap, lesionMapT1, cutFraction)

    if inputFLAIRVolume is not None:
      # Lesion Map: T2-FLAIR
      lesionMapFLAIR = slicer.vtkMRMLLabelMapVolumeNode()
      slicer.mrmlScene.AddNode(lesionMapFLAIR)
      lesionMapFLAIR.SetName("T2FLAIR_lesion_label")
      self.doFilterMask(inputFLAIRVolume, lesionMap, lesionMapFLAIR, cutFraction)

    if inputT2Volume is not None:
      # Lesion Map: T2
      lesionMapT2 = slicer.vtkMRMLLabelMapVolumeNode()
      slicer.mrmlScene.AddNode(lesionMapT2)
      lesionMapT2.SetName("T2_lesion_label")
      self.doFilterMask(inputT2Volume, lesionMap, lesionMapT2, cutFraction)

    if inputPDVolume is not None:
      # Lesion Map: PD
      lesionMapPD = slicer.vtkMRMLLabelMapVolumeNode()
      slicer.mrmlScene.AddNode(lesionMapPD)
      lesionMapPD.SetName("PD_lesion_label")
      self.doFilterMask(inputPDVolume, lesionMap, lesionMapPD, cutFraction)

    if inputFAVolume is not None:
      # Lesion Map: DTI-FA
      lesionMapFA = slicer.vtkMRMLLabelMapVolumeNode()
      slicer.mrmlScene.AddNode(lesionMapFA)
      lesionMapFA.SetName("FA_lesion_label")
      self.doFilterMask(inputFAVolume, lesionMap, lesionMapFA, cutFraction)

    if inputADCVolume is not None:
      # Lesion Map: DTI-FA
      lesionMapADC = slicer.vtkMRMLLabelMapVolumeNode()
      slicer.mrmlScene.AddNode(lesionMapADC)
      lesionMapADC.SetName("ADC_lesion_label")
      self.doFilterMask(inputADCVolume, lesionMap, lesionMapADC, cutFraction)


    #
    # Generating lesions in each input image
    #
    # List of parameters: Sigma
    Sigma= {}
    Sigma["T1"]=0.75
    Sigma["T2"]=0.75
    Sigma["PD"]=0.75
    Sigma["T2FLAIR"]=0.75
    Sigma["DTI-FA"]=1.5
    Sigma["DTI-ADC"]=1.3

    variability = 0.5

    if not isLongitudinal:
      if inputT1Volume is not None:
        try:
          slicer.util.showStatusMessage("Step "+str(currentStep)+": Applying lesion deformation on T1 volume...")
          logging.info("Step "+str(currentStep)+": Applying lesion deformation on T1 volume...")
          self.doSimulateLesions(inputT1Volume, "T1", lesionMapT1, inputT1Volume, Sigma["T1"], variability)
        except:
          logging.info("Exception caught when trying to apply lesion deformation in T1 volume.")
      if inputFLAIRVolume is not None:
        try:
          slicer.util.showStatusMessage("Step "+str(currentStep)+": Applying lesion deformation on T2-FLAIR volume...")
          logging.info("Step "+str(currentStep)+": Applying lesion deformation on T2-FLAIR volume...")
          self.doSimulateLesions(inputFLAIRVolume, "T2-FLAIR", lesionMapFLAIR, inputFLAIRVolume, Sigma["T2FLAIR"], variability)
        except:
          logging.info("Exception caught when trying to apply lesion deformation in T2-FLAIR volume.")
      if inputT2Volume is not None:
        try:
          slicer.util.showStatusMessage("Step "+str(currentStep)+": Applying lesion deformation on T2 volume...")
          logging.info("Step "+str(currentStep)+": Applying lesion deformation on T2 volume...")
          self.doSimulateLesions(inputT2Volume, "T2", lesionMapT2, inputT2Volume, Sigma["T2"], variability)
        except:
          logging.info("Exception caught when trying to apply lesion deformation in T2 volume.")
      if inputPDVolume is not None:
        try:
          slicer.util.showStatusMessage("Step "+str(currentStep)+": Applying lesion deformation on PD volume...")
          logging.info("Step "+str(currentStep)+": Applying lesion deformation on PD volume...")
          self.doSimulateLesions(inputPDVolume, "PD", lesionMapPD, inputPDVolume, Sigma["PD"], variability)
        except:
          logging.info("Exception caught when trying to apply lesion deformation in PD volume.")
      if inputFAVolume is not None:
        try:
          slicer.util.showStatusMessage("Step "+str(currentStep)+": Applying lesion deformation on DTI-FA map...")
          logging.info("Step "+str(currentStep)+": Applying lesion deformation on DTI-FA volume...")
          self.doSimulateLesions(inputFAVolume, "DTI-FA", lesionMapFA, inputFAVolume, Sigma["DTI-FA"], variability)
        except:
          logging.info("Exception caught when trying to apply lesion deformation in FA volume.")
      if inputADCVolume is not None:
        try:
          slicer.util.showStatusMessage("Step "+str(currentStep)+": Applying lesion deformation on DTI-ADC map...")
          logging.info("Step "+str(currentStep)+": Applying lesion deformation on DTI-ADC volume...")
          self.doSimulateLesions(inputADCVolume, "DTI-ADC", lesionMapADC, inputADCVolume, Sigma["DTI-ADC"], variability)
        except:
          logging.info("Exception caught when trying to apply lesion deformation in ADC volume.")
    else:
      #
      # Simulate Longitudinal Exams
      #
      if inputT1Volume is not None:
        try:
          slicer.util.showStatusMessage("Extra: Generating longitudinal lesion deformation on T1 volume...")
          logging.info("Extra: Generating longitudinal lesion deformation on T1 volume......")
          self.doLongitudinalExams(inputT1Volume, "T1", lesionMapT1, outputFolder, numberFollowUp, balanceHI, Sigma["T1"], variability)
        except:
          logging.info("Exception caught when trying to generate longitudinal lesion deformation in T1 volume.")
      if inputFLAIRVolume is not None:
        try:
          slicer.util.showStatusMessage("Extra: Generating longitudinal lesion deformation on T2-FLAIR volume...")
          logging.info("Extra: Generating longitudinal lesion deformation on T2-FLAIR volume......")
          self.doLongitudinalExams(inputFLAIRVolume, "T2-FLAIR", lesionMapFLAIR, outputFolder, numberFollowUp, balanceHI, Sigma["T2FLAIR"], variability)
        except:
          logging.info("Exception caught when trying to generate longitudinal lesion deformation in T2-FLAIR volume.")
      if inputT2Volume is not None:
        try:
          slicer.util.showStatusMessage("Extra: Generating longitudinal lesion deformation on T2 volume...")
          logging.info("Extra: Generating longitudinal lesion deformation on T2 volume...")
          self.doLongitudinalExams(inputT2Volume, "T2", lesionMapT2, outputFolder, numberFollowUp, balanceHI, Sigma["T2"], variability)
        except:
          logging.info("Exception caught when trying to generate longitudinal lesion deformation in T2 volume.")
      if inputPDVolume is not None:
        try:
          slicer.util.showStatusMessage("Extra: Generating longitudinal lesion deformation on PD volume...")
          logging.info("Extra: Generating longitudinal lesion deformation on PD volume...")
          self.doLongitudinalExams(inputPDVolume, "PD", lesionMapPD, outputFolder, numberFollowUp, balanceHI, Sigma["PD"], variability)
        except:
          logging.info("Exception caught when trying to generate longitudinal lesion deformation in PD volume.")
      if inputFAVolume is not None:
        try:
          slicer.util.showStatusMessage("Extra: Generating longitudinal lesion deformation on DTI-FA volume...")
          logging.info("Extra: Generating longitudinal lesion deformation on DTI-FA volume...")
          self.doLongitudinalExams(inputFAVolume, "DTI-FA", lesionMapFA, outputFolder, numberFollowUp, balanceHI, Sigma["DTI-FA"], variability)
        except:
          logging.info("Exception caught when trying to generate longitudinal lesion deformation in FA volume.")
      if inputADCVolume is not None:
        try:
          slicer.util.showStatusMessage("Extra: Generating longitudinal lesion deformation on DTI-ADC volume...")
          logging.info("Extra: Generating longitudinal lesion deformation on DTI-ADC volume...")
          self.doLongitudinalExams(inputADCVolume, "DTI-ADC", lesionMapADC, outputFolder, numberFollowUp, balanceHI, Sigma["DTI-ADC"], variability)
        except:
          logging.info("Exception caught when trying to generate longitudinal lesion deformation in ADC volume.")

    currentStep+=1
    #
    # Return inputs to its original space
    #
    if returnSpace and not isMNI:
      if inputT2Volume is not None and inputT2Volume is not referenceVolume:
        try:
          slicer.util.showStatusMessage("post-processing: Returning T2 image space...")
          logging.info("post-processing: Returning T2 image space...")
          # T2 inverse transform
          self.applyRegistrationTransform(inputT2Volume,clonedT2Volume,inputT2Volume,regT2toRefTransform,True,False)
        except:
          logging.info("Exception caught when trying to return T2 image space.")
      if inputFLAIRVolume is not None and inputFLAIRVolume is not referenceVolume:
        try:
          slicer.util.showStatusMessage("post-processing: Returning T2-FLAIR image space...")
          logging.info("post-processing: Returning T2-FLAIR image space...")
          # T2-FLAIR inverse transform
          self.applyRegistrationTransform(inputFLAIRVolume,clonedFLAIRVolume,inputFLAIRVolume,regFLAIRtoRefTransform,True,False)
        except:
          logging.info("Exception caught when trying to return T2-FLAIR image space.")
      if inputPDVolume is not None and inputPDVolume is not referenceVolume:
        try:
          slicer.util.showStatusMessage("post-processing: Returning PD image space...")
          logging.info("post-processing: Returning PD image space...")
          # PD inverse transform
          self.applyRegistrationTransform(inputPDVolume, clonedPDVolume, inputPDVolume, regPDtoRefTransform, True, False)
        except:
          logging.info("Exception caught when trying to return PD image space.")
      if inputFAVolume is not None:
        try:
          slicer.util.showStatusMessage("post-processing: Returning DTI-FA map space...")
          logging.info("post-processing: Returning DTI-FA image space...")
          # DTI-FA inverse transform
          self.applyRegistrationTransform(inputFAVolume, clonedFAVolume, inputFAVolume, regFAtoRefTransform, True, False)
        except:
          logging.info("Exception caught when trying to return FA image space.")
      if inputADCVolume is not None:
        try:
          slicer.util.showStatusMessage("post-processing: Returning DTI-ADC map space...")
          logging.info("post-processing: Returning DTI-ADC image space...")
          # DTI-ADC inverse transform
          self.applyRegistrationTransform(inputADCVolume, clonedADCVolume, inputADCVolume, regADCtoRefTransform, True, False)
        except:
          logging.info("Exception caught when trying to return ADC image space.")

    # Removing unnecessary nodes
    slicer.mrmlScene.RemoveNode(lesionMap)
    slicer.mrmlScene.RemoveNode(MNINode)
    if not isMNI:
      slicer.mrmlScene.RemoveNode(MNI_ref)
      slicer.mrmlScene.RemoveNode(regMNItoRefTransform)

      if inputFLAIRVolume is not None and inputFLAIRVolume is not referenceVolume:
        try:
          slicer.mrmlScene.RemoveNode(regFLAIRtoRefTransform)
          slicer.mrmlScene.RemoveNode(clonedFLAIRVolume)
        except:
          logging.info('Exception caught when trying to delete FLAIR in T1 space node.')
      if inputT2Volume is not None and inputT2Volume is not referenceVolume:
        try:
          slicer.mrmlScene.RemoveNode(regT2toRefTransform)
          slicer.mrmlScene.RemoveNode(clonedT2Volume)
        except:
          logging.info('Exception caught when trying to delete T2 in T1 space node.')
      if inputPDVolume is not None and inputPDVolume is not referenceVolume:
        try:
          slicer.mrmlScene.RemoveNode(regPDtoRefTransform)
          slicer.mrmlScene.RemoveNode(clonedPDVolume)
        except:
          logging.info('Exception caught when trying to delete PD in T1 space node.')
      if inputFAVolume is not None:
        try:
          slicer.mrmlScene.RemoveNode(regFAtoRefTransform)
          slicer.mrmlScene.RemoveNode(clonedFAVolume)
        except:
          logging.info('Exception caught when trying to delete FA in T1 space node.')
      if inputADCVolume is not None:
        try:
          slicer.mrmlScene.RemoveNode(regADCtoRefTransform)
          slicer.mrmlScene.RemoveNode(clonedADCVolume)
        except:
          logging.info('Exception caught when trying to delete ADC in T1 space node.')

    slicer.util.showStatusMessage("Processing completed")
    logging.info('Processing completed')

    return True
Example #24
0
    def run(self, meshNode, LMNode, gridLandmarks, sampleRate):
        surfacePolydata = meshNode.GetPolyData()

        gridPoints = vtk.vtkPoints()

        gridPoints.InsertNextPoint(0, 0, 0)
        gridPoints.InsertNextPoint(0, sampleRate - 1, 0)
        gridPoints.InsertNextPoint(sampleRate - 1, 0, 0)
        for row in range(1, sampleRate - 1):
            for col in range(1, sampleRate - 1):
                if (row + col) < (sampleRate - 1):
                    gridPoints.InsertNextPoint(row, col, 0)

        gridPolydata = vtk.vtkPolyData()
        gridPolydata.SetPoints(gridPoints)

        sourcePoints = vtk.vtkPoints()
        targetPoints = vtk.vtkPoints()

        #sourcePoints.InsertNextPoint(gridPoints.GetPoint(0))
        #sourcePoints.InsertNextPoint(gridPoints.GetPoint(sampleRate-1))
        #sourcePoints.InsertNextPoint(gridPoints.GetPoint(gridPoints.GetNumberOfPoints()-1))
        sourcePoints.InsertNextPoint(gridPoints.GetPoint(0))
        sourcePoints.InsertNextPoint(gridPoints.GetPoint(1))
        sourcePoints.InsertNextPoint(gridPoints.GetPoint(2))

        point = [0, 0, 0]
        for gridVertex in gridLandmarks:
            LMNode.GetMarkupPoint(int(gridVertex - 1), 0, point)
            targetPoints.InsertNextPoint(point)

        #transform grid to triangle
        transform = vtk.vtkThinPlateSplineTransform()
        transform.SetSourceLandmarks(sourcePoints)
        transform.SetTargetLandmarks(targetPoints)
        transform.SetBasisToR()

        transformNode = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLTransformNode", "TPS")
        transformNode.SetAndObserveTransformToParent(transform)

        model = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLModelNode",
                                                   "mesh_resampled")
        model.SetAndObservePolyData(gridPolydata)
        model.SetAndObserveTransformNodeID(transformNode.GetID())
        slicer.vtkSlicerTransformLogic().hardenTransform(model)

        resampledPolydata = model.GetPolyData()

        pointLocator = vtk.vtkPointLocator()
        pointLocator.SetDataSet(surfacePolydata)
        pointLocator.BuildLocator()

        #get surface normal from each landmark point
        rayDirection = [0, 0, 0]
        normalArray = surfacePolydata.GetPointData().GetArray("Normals")
        if (not normalArray):
            normalFilter = vtk.vtkPolyDataNormals()
            normalFilter.ComputePointNormalsOn()
            normalFilter.SetInputData(surfacePolydata)
            normalFilter.Update()
            normalArray = normalFilter.GetOutput().GetPointData().GetArray(
                "Normals")
            if (not normalArray):
                print("Error: no normal array")

        for gridVertex in gridLandmarks:
            LMNode.GetMarkupPoint(int(gridVertex - 1), 0, point)
            closestPointId = pointLocator.FindClosestPoint(point)
            tempNormal = normalArray.GetTuple(closestPointId)
            rayDirection[0] += tempNormal[0]
            rayDirection[1] += tempNormal[1]
            rayDirection[2] += tempNormal[2]

        #calculate average
        for dim in range(len(rayDirection)):
            rayDirection[dim] = rayDirection[dim] / 4

        #set up locater for intersection with normal vector rays
        obbTree = vtk.vtkOBBTree()
        obbTree.SetDataSet(surfacePolydata)
        obbTree.BuildLocator()

        #define new landmark sets
        semilandmarkNodeName = "semiLM_" + str(gridLandmarks[0]) + "_" + str(
            gridLandmarks[1]) + "_" + str(gridLandmarks[2])
        semilandmarkPoints = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLMarkupsFiducialNode", semilandmarkNodeName)

        #get a sample distance for quality control
        m1 = model.GetPolyData().GetPoint(0)
        m2 = model.GetPolyData().GetPoint(1)
        m3 = model.GetPolyData().GetPoint(1)
        d1 = math.sqrt(vtk.vtkMath().Distance2BetweenPoints(m1, m2))
        d2 = math.sqrt(vtk.vtkMath().Distance2BetweenPoints(m2, m3))
        d3 = math.sqrt(vtk.vtkMath().Distance2BetweenPoints(m1, m3))
        sampleDistance = (d1 + d2 + d3)

        # set initial three grid points
        for index in range(0, 3):
            origLMPoint = resampledPolydata.GetPoint(index)
            #landmarkLabel = LMNode.GetNthFiducialLabel(gridLandmarks[index]-1)
            landmarkLabel = str(gridLandmarks[index])
            semilandmarkPoints.AddFiducialFromArray(origLMPoint, landmarkLabel)

        # calculate maximum projection distance
        projectionTolerance = 2
        boundingBox = vtk.vtkBoundingBox()
        boundingBox.AddBounds(surfacePolydata.GetBounds())
        diagonalDistance = boundingBox.GetDiagonalLength()
        #rayLength = math.sqrt(diagonalDistance) * projectionTolerance
        rayLength = sampleDistance

        # get normal projection intersections for remaining semi-landmarks
        print("Target number of points: ",
              resampledPolydata.GetNumberOfPoints())
        for index in range(3, resampledPolydata.GetNumberOfPoints()):
            modelPoint = resampledPolydata.GetPoint(index)
            rayEndPoint = [0, 0, 0]
            for dim in range(len(rayEndPoint)):
                rayEndPoint[
                    dim] = modelPoint[dim] + rayDirection[dim] * rayLength
            intersectionIds = vtk.vtkIdList()
            intersectionPoints = vtk.vtkPoints()
            obbTree.IntersectWithLine(modelPoint, rayEndPoint,
                                      intersectionPoints, intersectionIds)
            #if there are intersections, update the point to most external one.
            if intersectionPoints.GetNumberOfPoints() > 0:
                exteriorPoint = intersectionPoints.GetPoint(
                    intersectionPoints.GetNumberOfPoints() - 1)
                #projectionDistance=math.sqrt(vtk.vtkMath().Distance2BetweenPoints(exteriorPoint, modelPoint))
                semilandmarkPoints.AddFiducialFromArray(exteriorPoint)
            #if there are no intersections, reverse the normal vector
            else:
                for dim in range(len(rayEndPoint)):
                    rayEndPoint[
                        dim] = modelPoint[dim] + rayDirection[dim] * -rayLength
                obbTree.IntersectWithLine(modelPoint, rayEndPoint,
                                          intersectionPoints, intersectionIds)
                if intersectionPoints.GetNumberOfPoints() > 0:
                    exteriorPoint = intersectionPoints.GetPoint(0)
                    semilandmarkPoints.AddFiducialFromArray(exteriorPoint)
                    #projectionDistance=math.sqrt(vtk.vtkMath().Distance2BetweenPoints(exteriorPoint, modelPoint))
                    #if projectionDistance < sampleDistance:
                    #  semilandmarkPoints.AddFiducialFromArray(exteriorPoint)
                    #else:
                    #  closestPointId = pointLocator.FindClosestPoint(modelPoint)
                    #  rayOrigin = surfacePolydata.GetPoint(closestPointId)
                    #  semilandmarkPoints.AddFiducialFromArray(rayOrigin)

                #if none in reverse direction, use closest mesh point
                else:
                    closestPointId = pointLocator.FindClosestPoint(modelPoint)
                    rayOrigin = surfacePolydata.GetPoint(closestPointId)
                    semilandmarkPoints.AddFiducialFromArray(rayOrigin)

        # update lock status and color
        semilandmarkPoints.SetLocked(True)
        semilandmarkPoints.GetDisplayNode().SetColor(random.random(),
                                                     random.random(),
                                                     random.random())
        semilandmarkPoints.GetDisplayNode().SetSelectedColor(
            random.random(), random.random(), random.random())
        semilandmarkPoints.GetDisplayNode().PointLabelsVisibilityOff()
        #clean up
        slicer.mrmlScene.RemoveNode(transformNode)
        slicer.mrmlScene.RemoveNode(model)
        print("Total points:", semilandmarkPoints.GetNumberOfFiducials())
        return semilandmarkPoints
Example #25
0
 def confirmMove(self):
   logic = slicer.vtkSlicerTransformLogic()
   logic.hardenTransform(self.activeNode)
   self.confirmAction()
   self.endMove()
Example #26
0
    def run(self, baseMeshNode, baseLMNode, semiLMNode, meshDirectory,
            lmDirectory, ouputDirectory, outputExtension, scaleProjection):
        SLLogic = CreateSemiLMPatches.CreateSemiLMPatchesLogic()
        targetPoints = vtk.vtkPoints()
        point = [0, 0, 0]
        # estimate a sample size usingn semi-landmark spacing
        sampleArray = np.zeros(shape=(25, 3))
        for i in range(25):
            semiLMNode.GetMarkupPoint(0, i, point)
            sampleArray[i, :] = point
        sampleDistances = self.distanceMatrix(sampleArray)
        minimumMeshSpacing = sampleDistances[sampleDistances.nonzero()].min(
            axis=0)
        rayLength = minimumMeshSpacing * (scaleProjection)

        for i in range(baseLMNode.GetNumberOfFiducials()):
            baseLMNode.GetMarkupPoint(0, i, point)
            targetPoints.InsertNextPoint(point)

        for meshFileName in os.listdir(meshDirectory):
            if (not meshFileName.startswith(".")):
                print(meshFileName)
                lmFileList = os.listdir(lmDirectory)
                meshFilePath = os.path.join(meshDirectory, meshFileName)
                regex = re.compile(r'\d+')
                subjectID = [int(x) for x in regex.findall(meshFileName)][0]
                for lmFileName in lmFileList:
                    if str(subjectID) in lmFileName:
                        # if mesh and lm file with same subject id exist, load into scene
                        currentMeshNode = slicer.util.loadModel(meshFilePath)
                        lmFilePath = os.path.join(lmDirectory, lmFileName)
                        success, currentLMNode = slicer.util.loadMarkupsFiducialList(
                            lmFilePath)

                        # set up transform between base lms and current lms
                        sourcePoints = vtk.vtkPoints()
                        for i in range(currentLMNode.GetNumberOfMarkups()):
                            currentLMNode.GetMarkupPoint(0, i, point)
                            sourcePoints.InsertNextPoint(point)

                        transform = vtk.vtkThinPlateSplineTransform()
                        transform.SetSourceLandmarks(sourcePoints)
                        transform.SetTargetLandmarks(targetPoints)
                        transform.SetBasisToR()  # for 3D transform

                        transformNode = slicer.mrmlScene.AddNewNodeByClass(
                            "vtkMRMLTransformNode", "TPS")
                        transformNode.SetAndObserveTransformToParent(transform)

                        # apply transform to the current surface mesh
                        currentMeshNode.SetAndObserveTransformNodeID(
                            transformNode.GetID())
                        slicer.vtkSlicerTransformLogic().hardenTransform(
                            currentMeshNode)

                        # project semi-landmarks
                        resampledLandmarkNode = slicer.mrmlScene.AddNewNodeByClass(
                            'vtkMRMLMarkupsFiducialNode',
                            meshFileName + '_SL_warped')
                        success = SLLogic.projectPoints(
                            baseMeshNode, currentMeshNode, semiLMNode,
                            resampledLandmarkNode, rayLength)

                        transformNode.Inverse()
                        resampledLandmarkNode.SetAndObserveTransformNodeID(
                            transformNode.GetID())
                        slicer.vtkSlicerTransformLogic().hardenTransform(
                            resampledLandmarkNode)

                        # transfer point data
                        for index in range(
                                semiLMNode.GetNumberOfControlPoints()):
                            fiducialLabel = semiLMNode.GetNthControlPointLabel(
                                index)
                            fiducialDescription = semiLMNode.GetNthControlPointDescription(
                                index)
                            resampledLandmarkNode.SetNthControlPointLabel(
                                index, fiducialLabel)
                            resampledLandmarkNode.SetNthControlPointDescription(
                                index, fiducialDescription)

                        # save output file
                        outputFileName = meshFileName + '_SL_warped' + outputExtension
                        outputFilePath = os.path.join(ouputDirectory,
                                                      outputFileName)
                        slicer.util.saveNode(resampledLandmarkNode,
                                             outputFilePath)

                        # clean up
                        slicer.mrmlScene.RemoveNode(resampledLandmarkNode)
                        slicer.mrmlScene.RemoveNode(currentLMNode)
                        slicer.mrmlScene.RemoveNode(currentMeshNode)
                        slicer.mrmlScene.RemoveNode(transformNode)