Setting an MNI origo to a volume

I would like to ask whether there is a possibility to set and/or visualize of the MNI-origo of a volume.
A bit more detail about the question:

  • I’m working with MRI images of different (mostly dog) brains. Looking at them in the MATLAB, MRIcron, or MRIcroGL shows the origo of the MNI coordinate system in a given (defined) point. You can see this on the below volume, where I set the origo to the anterior commissure:

  • When I open the same nifti file with Slicer, I can only see the image origin (according to its physical space) and its slice number (showing also in the Data Probe window), but not this specific starting point:

What is your opinion, is there a way to show that pre-defined origo in Slicer?

  • if there is, then my next related question is whether one can be able to manually re-set this origo with the program? (like in the MATLAB’s SPM module with the ‘Reorient image(s)/Set origin to Xhairs…’ option.

Thanks in advance!

Would a keyboard shortcut to jump to the (0,0,0) position in all slice views would fulfill your needs?

Dear Andras,

It would be a good thing to have in the first place!
Besides, I’m also interested in:
~ whether the MNI coordinate of a given point can be shown (e.g. in the Data Probe, or in another window)? /As sometimes we need to refer to these coordinates in the publications./
~ is there an option to re-set this MNI origo if I would like to change that to another point (to correct its placement)?

As I work work brain normalization for dog studies, the co-registration is the major part (which can be done well with the Transforms modul), but to visualize and analyze them in this common reference space (e.g., in MATLAB) we need to set manually an MNI-origo to a volume. Currently I’m only able to do that with the SPM, but it would be nice if I could handle the entire workflow with the Slicer.

Thanks for your advice!
Best regards, Kalman

You can copy-paste this into the Python console to jump slice views to (0,0,0) position on Ctrl+e:

shortcut = qt.QShortcut(qt.QKeySequence('Ctrl+e'), slicer.util.mainWindow())
shortcut.connect('activated()',
  lambda: slicer.modules.markups.logic().JumpSlicesToLocation(0,0,0, True))

If you want to make this keyboard shortcut permanent then copy-paste the code into your startup script
(you can find its location in menu: Edit / Application settings / General / Application startup script).

The Data probe only shows coordinate values in the world coordinate system. You can make the world coordinate system mean anything you want (e.g., MNI) by applying a transform to the volume that transforms it into that space.

You only need a small custom script (or if you want to be fancy then a custom module) to display coordinate values in multiple coordinate systems at the same time. For example, if you have a transform that moves your image to MNI space then you can use this code snippet to display world and MNI coordinates in the status bar as you move across the viewers:

def onMouseMoved(observer,eventid):
  mniToWorldTransformNode = getNode('LinearTransform_3')  # replace this by the name of your actual transform
  worldToMniTransform = vtk.vtkGeneralTransform()
  mniToWorldTransformNode.GetTransformToWorld(worldToMniTransform)
  ras=[0,0,0]
  mni=[0,0,0]
  crosshairNode.GetCursorPositionRAS(ras)
  worldToMniTransform.TransformPoint(ras, mni)
  slicer.util.showStatusMessage(f"RAS={.3:ras}   MNI={mni}")

crosshairNode=slicer.util.getNode('Crosshair') 
observationId = crosshairNode.AddObserver(slicer.vtkMRMLCrosshairNode.CursorPositionModifiedEvent, onMouseMoved)

# Run this to stop displaying values:
# crosshairNode.RemoveObserver(observationId)

Yes, by applying a transform. You can create a transform in Transforms module and set the coordinates in Translation section, click “Invert”, and then apply this transform to the volume.

I’m not sure if it is relevant for you, but you can compute ACPC transform using ACPC transform module.

2 Likes

Dear Andras,

Thank you very much for your help and the detailed answer, it’s the function I needed!

Still I found some interesting issues regarding which I would like to ask your opinion.
When I first used the shortcut-code, the position of the cursor was out of the volume:

My colleague - who is more expert in programming - found that there is a difference in the qform/sform space, which causes this alteration. I share here the links he sent me in this topic:

Finally he found that if he runs this code below in FSL, then afterwards the shortcut works well on the new volume:

fslorient -copysform2qform sample_file.nii

.
A question: Is there a way that this modification (qform/sform reset) can be done in the Slicer (without having FSL and the required Linux environment)?

Also to share with the community - maybe some could have the same question - Adam made a little modification in the script you’ve sent (as for some reason an error message was received on its initial run), and now everything displayed correctly just as you have said:

def onMouseMoved(observer,eventid):
  mniToWorldTransformNode = getNode('LinearTransform_3')  # replace this by the name of your actual transform
  worldToMniTransform = vtk.vtkGeneralTransform()
  mniToWorldTransformNode.GetTransformToWorld(worldToMniTransform)
  ras=[0,0,0]
  mni=[0,0,0]    
  crosshairNode.GetCursorPositionRAS(ras)
  worldToMniTransform.TransformPoint(ras, mni)
  _ras = "; ".join([str(k) for k in ras])
  _mni = "; ".join([str(k) for k in mni])
  slicer.util.showStatusMessage(f"RAS={_ras}   MNI={_mni}")

crosshairNode=slicer.util.getNode('Crosshair')
observationId = crosshairNode.AddObserver(slicer.vtkMRMLCrosshairNode.CursorPositionModifiedEvent, onMouseMoved)

I will try the transformations, and if any question rises, I’ll let you know.

1 Like

NIFTI format is simply terrible. It is OK to have a simple and limited file format (such as NRRD) or complicated but very powerful format (such as DICOM). But somehow NIFTI managed to be both overcomplicated and limited at the same time with various redundancies and ambiguities. Unfortunately, this is the file format what the neuroimaging community has come up with and although many people are really unhappy with it, nobody wants to take on the work to redesign it. So, you just need to apply whatever workaround works.

Yes, I’m sure you can fix the corrupted files by a few commands for example using nibabel.

Thanks for sharing the code, I’ll add it to the script repository for future reference.

Thanks for everything, Andras!
Okay, I’ll keep that in mind, and try to shift the focus from NIFTI to NRRD in the future. It seemed first easier to handle compared to the DICOM, but now I’m also aware of its limitations.

I will check the nibabel, thank you for the suggestion!