Hey everyone,
I was trying to write a quick Pyton script to track the mouse movement with ‘Crosshair’ and return the voxel value using the ijk position. I ran the script within Slicer’s Python Interactor and launched Slicer from Command Line in order to be able to see error messages. This is the Script I wrote:
The Script did not break upon printing ras and returned coordinate values upon pressing SHIFT.
But when I added the rest of the code to transform ras coordinates to ijk, Slicer started breaking without any errors which before where shown in command line.
Now I hope someone is able to clarify how I am breaking Slicer or whether the approach to the transformation is wrong within itself.
Also it would be helpful to see error outputs on the command line where I invoked Slicer
This is the line that is causing the crash. There is no constructor for vtkGeneralTransform that takes a string. I believe the crash is caused because the constructor is trying to interpret it as a hexadecimal memory address.
There are a couple of other issues with your script:
The input to slicer.util.arrayFromVolume should be the volume node that you are inspecting, not a vtkGeneralTransform
Hey thankyou very much for you reply!! indeed I see my fallacies there. I am sorry that I haven’t got back to you earlier, but I am only able to access this PC twice a week. May I ask you if there is an alternate way to go from RAS to Volume RAS using Cosshair since right now I have tried this slicer.vtkMRMLTransformNode.GetTransformBetweenNodes(None, crosshairNode, transform_ras_to_volume_ras) but my issue is that the transform function cannot be applied to a CrossairNode.
If I get you right my next steps should be Volume Ras → IJK by Matrix tranformation and then accessing voxel Value from IJK.
My Matrix generation has thrown errors Volume_RAS_toIJK = vtk.vtkMatrix4x4() ijk_node = Volume_RAS_toIJK.GetRASToIJKMatrix(Volume_RAS_toIJK) gets me this error: ‘vtkmodules.vtkCommonMath.vtkMatrix4x4’ object has no attribute ‘GetRASToIJKMatrix’.
HI Kyle, thank you for helping us on this (I work with Leo).
I’m posting in case other people can benefit from our attempt - I believe we managed to get it working by simply moving the computationally-expensive calls outside the mouse movement loop. The console is now printing reasonable values for voxels at coordinates:
This is our current code:
import numpy as np
ras = [0, 0, 0]
volumeNode = slicer.util.getNode("MRHead")
# Apply that transform to get volume's RAS coordinates
transform_ras_to_volume_ras = vtk.vtkGeneralTransform()
slicer.vtkMRMLTransformNode.GetTransformBetweenNodes(None, volumeNode.GetParentTransformNode(), transform_ras_to_volume_ras)
# Get volume as slicer array
a = arrayFromVolume(volumeNode)
def onMouseMoved(observer,eventid):
# Get point coordinate in RAS
ras = [0, 0, 0]
crosshairNode.GetCursorPositionRAS(ras)
point_volume_ras = transform_ras_to_volume_ras.TransformPoint(ras[0:3])
# Get voxel coordinates from physical coordinates
volume_ras_to_ijk = vtk.vtkMatrix4x4()
volumeNode.GetRASToIJKMatrix(volume_ras_to_ijk)
point_ijk = [0, 0, 0, 1]
volume_ras_to_ijk.MultiplyPoint(np.append(point_volume_ras, 1.0), point_ijk)
point_ijk = [ int(round(c)) for c in point_ijk[0:3] ]
# Get markup's position
x, y, z = point_ijk[0], point_ijk[1], point_ijk[2]
value = a[z,y,x]
print(value)
crosshairNode=slicer.util.getNode("Crosshair")
observerId = crosshairNode.AddObserver(slicer.vtkMRMLCrosshairNode.CursorPositionModifiedEvent, onMouseMoved)
If you need to do relatively expensive computations to display information about the current mouse position then a good technique is “delayed update”: you don’t compute while the mouse is moving but immediately when it stops. Implementation: Instead of calling the computation directly from the mouse event callback, you only trigger a QTimer with a short timeout (e.g., 100ms). If a new mouse event arrives then you restart the timer. When mouse movement stops then the timer elapses, which triggers the computation.