# Tracking cursor movements to access voxel values

**URL:** <https://discourse.slicer.org/t/tracking-cursor-movements-to-access-voxel-values/24568>\
**Category:** Development\
**Tags:** python\
**Created:** [July 29, 2022, 4:40pm UTC](https://discourse.slicer.org/t/tracking-cursor-movements-to-access-voxel-values/24568 "2022-07-29T16:40:48Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![leo](https://avatars.discourse-cdn.com/v4/letter/l/c2a13f/32.png) [@leo](https://discourse.slicer.org/u/leo)\
**Post date:** [July 29, 2022, 4:40pm UTC](https://discourse.slicer.org/t/tracking-cursor-movements-to-access-voxel-values/24568/1 "2022-07-29T16:40:48Z")

</div>

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:

```auto

def onMouseMoved(observer,eventid):
	crosshair=slicer.mrmlScene.GetFirstNodeByClass("vtkMRMLCrosshairNode")
	crosshair.SetCrosshairBehavior(crosshair.CenteredJumpSlice)
	ras = [0.0, 0.0, 0.0]
	crosshairNode.GetCursorPositionRAS(ras)
	#slicer.vtkMRMLSliceNode.JumpAllSlices(slicer.mrmlScene, *ras, slicer.vtkMRMLSliceNode.CenteredJumpSlice)
	#print(ras)
	transform_ras_to_volume_ras = vtk.vtkGeneralTransform("Crosshair")
	voxel_value_array = slicer.util.arrayFromVolume(transform_ras_to_volume_ras)
	voxel_value = voxel_value_array[ras[2], ras[1],ras[0]]
	ras_to_voxel = vtk.vtkMatrix4x4()
	crosshairNode.GetRASToIJKNatrix(ras_to_voxel)
	voxel_point = [0,0,0,1]
	ras_to_voxel.MultiplyPoint(np.append(voxel_value,1.0),voxel_point)
	voxel_point = [int(round(c) for c in voxel_point[0:3]) ]
	print(voxel_point)

crosshairNode = slicer.util.getNode("Crosshair")
id = crosshairNode.AddObserver(slicer.vtkMRMLCrosshairNode.CursorPositionModifiedEvent, onMouseMoved)

```

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

---

<div class="post-metadata">

**Author:** ![Sunderlandkyl](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/sunderlandkyl/32/79987_2.png) [@Sunderlandkyl](https://discourse.slicer.org/u/Sunderlandkyl)\
**Post date:** [July 29, 2022, 5:06pm UTC](https://discourse.slicer.org/t/tracking-cursor-movements-to-access-voxel-values/24568/2 "2022-07-29T17:06:53Z")

</div>

> [@leo](#):
>
> `transform_ras_to_volume_ras = vtk.vtkGeneralTransform("Crosshair")`

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
- GetRASToIJKNatrix → GetRASToIJKMatrix
- voxel\_value\_array cannot be accessed using RAS, you should use the IJK coordinates. See [Script repository — 3D Slicer documentation](https://slicer.readthedocs.io/en/latest/developer_guide/script_repository.html#get-value-of-a-volume-at-specific-voxel-coordinates)

---

<div class="post-metadata">

**Author:** ![leo](https://avatars.discourse-cdn.com/v4/letter/l/c2a13f/32.png) [@leo](https://discourse.slicer.org/u/leo)\
**Post date:** [August 3, 2022, 4:15pm UTC](https://discourse.slicer.org/t/tracking-cursor-movements-to-access-voxel-values/24568/3 "2022-08-03T16:15:54Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![Sunderlandkyl](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/sunderlandkyl/32/79987_2.png) [@Sunderlandkyl](https://discourse.slicer.org/u/Sunderlandkyl)\
**Post date:** [August 3, 2022, 4:25pm UTC](https://discourse.slicer.org/t/tracking-cursor-movements-to-access-voxel-values/24568/4 "2022-08-03T16:25:24Z")

</div>

The crosshair node is already in “World” coordinates. If the volume node is not under a transform, then World coordinates == Volume RAS coordinates.

You can get a transform from WorldToVolumeRAS with:

```python
worldToVolumeRAS = vtk.vtkGeneralTransform()
slicer.vtkMRMLTransformNode.GetTransformBetweenNodes(None, volume.GetParentTransformNode(), worldToVolumeRAS)

```

---

<div class="post-metadata">

**Author:** ![leo](https://avatars.discourse-cdn.com/v4/letter/l/c2a13f/32.png) [@leo](https://discourse.slicer.org/u/leo)\
**Post date:** [August 3, 2022, 5:35pm UTC](https://discourse.slicer.org/t/tracking-cursor-movements-to-access-voxel-values/24568/5 "2022-08-03T17:35:41Z")

</div>

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’.

---

<div class="post-metadata">

**Author:** ![Sunderlandkyl](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/sunderlandkyl/32/79987_2.png) [@Sunderlandkyl](https://discourse.slicer.org/u/Sunderlandkyl)\
**Post date:** [August 3, 2022, 6:23pm UTC](https://discourse.slicer.org/t/tracking-cursor-movements-to-access-voxel-values/24568/6 "2022-08-03T18:23:05Z")

</div>

Yeah, you’re on the right track.

> [@leo](#):
>
> Volume\_RAS\_toIJK.GetRASToIJKMatrix(Volume\_RAS\_toIJK)

It should be volumeNode.GetRASToIJKMatrix(Volume\_RAS\_toIJK). Where volumeNode is the vtkMRMLVolumeNode that you are trying to inspect.

---

<div class="post-metadata">

**Author:** ![siqueirl](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/siqueirl/32/12320_2.png) [@siqueirl](https://discourse.slicer.org/u/siqueirl)\
**Post date:** [August 5, 2022, 1:53pm UTC](https://discourse.slicer.org/t/tracking-cursor-movements-to-access-voxel-values/24568/7 "2022-08-05T13:53:37Z")

</div>

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:

```auto
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)

```

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [August 7, 2022, 6:42am UTC](https://discourse.slicer.org/t/tracking-cursor-movements-to-access-voxel-values/24568/8 "2022-08-07T06:42:57Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![siqueirl](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/siqueirl/32/12320_2.png) [@siqueirl](https://discourse.slicer.org/u/siqueirl)\
**Post date:** [August 8, 2022, 2:32pm UTC](https://discourse.slicer.org/t/tracking-cursor-movements-to-access-voxel-values/24568/9 "2022-08-08T14:32:17Z")

</div>

Thank you for sharing this tip. I will eventually need to optimize this tracking loop, so it’s good to know about this pattern.
