Clarification on qform and sform

Hi MRtrixperts,

I am trying to wrap my head around the confusion with regards to qform sform and transformations, and was hoping you could clear up something for me.

My understand is that:

  • The qform transformation (as stored in a NIfTI header) relates the voxel co-ordinates (in mm) to scanner space (aka some frame of reference on the scanner), and is a rigid transform.
  • The sform transformation relates the voxel co-ordinates to some standard space (eg. MNI space), is an affine transform.
  • Sometimes a NIfTI image has one or both, and therefore MRtrix3 picks one based on predefined rules defined here*.

My question is: When looking at the transform output my mrinfo (in the absence of simplifying greater than 90 degree transformations through stride changes), is this simply the qform/sform transform (depending on which is available given the above rule)? Or is there some relation to this transform and the qform/sform?

If it is, by definition does this mean that if the transformation displayed by mrinfo is affine, then it must be the sform transform? Or can the qform be set to an affine transform even if it is not supposed to be?

Many thanks


*moved to NIfTI transform ambiguity

You’re not alone.

Your hope may be misplaced… :grimacing:

Yes and no. The information is indeed derived from the qform or sform, according to the rules you’re linking to. There’s quite a bit that happens in the process – see this GitHub post for details.

This is exactly the problem that I’m grappling with in this pull request. Essentially, qform can only represent a rigid body rotation (and with some loss of precision, as we found out recently). So on image read, we check whether the two are equivalent to some precision, and (by default) use the sform if they match (based on the observation that it’s higher precision than the qform).

The remaining issues that I’m trying to deal with in the pull request above is whether we should write an empty qform if we detect a non-rigid transform, and a more worrying issue about how to interpret a non-rigid sform correctly, given that it encodes the voxel size as well, but that is also stored elsewhere in the header. I’m not convinced I’ve completely wrapped my head around that one… Happy to hear opinions on the topic though!