Created
November 5, 2021 19:56
-
-
Save mauigna06/434784dac9e5704198b80b179e037d0e to your computer and use it in GitHub Desktop.
Create a frame for the model in the principal components directions, set up a plane with interaction handles to move it.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Create a frame for the model in the principal components directions, | |
# set up a plane with interaction handles to move it. | |
import numpy as np | |
#Change this number for more accuracy (more points, take more time to compute) | |
numberOfSampledPointsOfModel = 2000 | |
model = getNode('mymodel') | |
if model.GetPolyData().GetNumberOfPoints() > numberOfSampledPointsOfModel: | |
maskPointsFilter = vtk.vtkMaskPoints() | |
maskPointsFilter.SetInputData(model.GetPolyData()) | |
# | |
ratio = round(model.GetPolyData().GetNumberOfPoints()/numberOfSampledPointsOfModel) | |
# | |
# This works but the sampling could be biased spatially I think | |
# If you have vtk9 you should use UNIFORM_SPATIAL_SURFACE option | |
maskPointsFilter.SetOnRatio(ratio) | |
maskPointsFilter.RandomModeOn() | |
maskPointsFilter.Update() | |
# | |
polydata = vtk.vtkPolyData() | |
polydata.ShallowCopy(maskPointsFilter.GetOutput()) | |
# | |
# Calculate the SVD and mean | |
from vtk.util.numpy_support import vtk_to_numpy | |
modelPoints = vtk_to_numpy(polydata.GetPoints().GetData()) | |
else: | |
from vtk.util.numpy_support import vtk_to_numpy | |
modelPoints = vtk_to_numpy(model.GetPolyData().GetPoints().GetData()) | |
# Calculate the mean of the points, i.e. the 'center' of the cloud | |
modelPointsMean = modelPoints.mean(axis=0) | |
# Do an SVD on the mean-centered data. | |
uu, dd, rightSingularVectors = np.linalg.svd(modelPoints - modelPointsMean) | |
# Create a frame for the model | |
modelZ = np.zeros(3) | |
modelX = rightSingularVectors[0] | |
modelY = rightSingularVectors[1] | |
vtk.vtkMath.Cross(modelX, modelY, modelZ) | |
modelZ = modelZ/np.linalg.norm(modelZ) | |
modelOrigin = modelPointsMean | |
# Create the plane to move the model | |
planeNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsPlaneNode", slicer.mrmlScene.GetUniqueNameByString("modelToWorldPlane")) | |
slicer.modules.markups.logic().AddNewDisplayNodeForMarkupsNode(planeNode) | |
displayNode = planeNode.GetDisplayNode() | |
displayNode.SetGlyphScale(2.5) | |
displayNode.SetOpacity(0) | |
displayNode.HandlesInteractiveOn() | |
planeNode.SetAxes(modelX,modelY,modelZ) | |
planeNode.SetOrigin(modelOrigin) | |
planeToWorldTransformNode = slicer.vtkMRMLLinearTransformNode() | |
planeToWorldTransformNode.SetName(slicer.mrmlScene.GetUniqueNameByString("planeToWorld")) | |
slicer.mrmlScene.AddNode(planeToWorldTransformNode) | |
# Save the inverse of the initial transform of the plane | |
worldToInitialModelTransformNode = slicer.vtkMRMLLinearTransformNode() | |
worldToInitialModelTransformNode.SetName(slicer.mrmlScene.GetUniqueNameByString("worldToInitialModel")) | |
slicer.mrmlScene.AddNode(worldToInitialModelTransformNode) | |
model.SetAndObserveTransformNodeID(worldToInitialModelTransformNode.GetID()) | |
worldToInitialModelTransformNode.SetAndObserveTransformNodeID(planeToWorldTransformNode.GetID()) | |
# function to update the model's position/orientation interactively | |
def onPlaneModified(sourceNode,event=None): | |
planeToWorldMatrix = vtk.vtkMatrix4x4() | |
try: | |
sourceNode.GetObjectToWorldMatrix(planeToWorldMatrix) | |
except: | |
sourceNode.GetPlaneToWorldMatrix(planeToWorldMatrix) | |
# | |
planeNodeToWorldTransformNode = model.GetParentTransformNode().GetParentTransformNode() | |
planeNodeToWorldTransformNode.SetMatrixTransformToParent(planeToWorldMatrix) | |
onPlaneModified(planeNode) | |
planeToWorldMatrix = vtk.vtkMatrix4x4() | |
# This call is done to give the transformNode time to update its matrixToParent | |
planeNodeToWorldTransformNode = model.GetParentTransformNode().GetParentTransformNode() | |
planeNodeToWorldTransformNode.GetMatrixTransformToParent(planeToWorldMatrix) | |
worldToInitialModelMatrix = vtk.vtkMatrix4x4() | |
worldToInitialModelMatrix.DeepCopy(planeToWorldMatrix) | |
worldToInitialModelMatrix.Invert() | |
worldToInitialModelTransformNode.SetMatrixTransformToParent(worldToInitialModelMatrix) | |
observer = planeNode.AddObserver(slicer.vtkMRMLMarkupsNode.PointModifiedEvent,onPlaneModified) | |
#If you want to stop interactions for plane i, do this: | |
#planeNode.RemoveObserver(observer) | |
#If you want the model to world transform AFTER YOU MOVE IT, do this: | |
worldToInitialModelTransformNode = model.GetParentTransformNode() | |
modelToWorldMatrix = vtk.vtkMatrix4x4() | |
worldToInitialModelTransformNode.GetMatrixTransformToWorld(modelToWorldMatrix) | |
print(modelToWorldMatrix) | |
#If you just want to define a frame for the model, do this: | |
worldToInitialModelTransformNode = model.GetParentTransformNode() | |
initialModelToWorldMatrix = vtk.vtkMatrix4x4() | |
worldToInitialModelTransformNode.GetMatrixTransformToParent(initialModelToWorldMatrix) | |
initialModelToWorldMatrix.Invert() | |
print(initialModelToWorldMatrix) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment