FZJ-INM1-BDA / voluba

Browser based tool for interactive alignment of high-resolution volumes of interest to 3D reference brain models
https://voluba.readthedocs.io
Apache License 2.0
4 stars 0 forks source link

Set qform in updated NIfTI #170

Closed JThoennissen closed 1 year ago

JThoennissen commented 1 year ago

Clicking "Download volumes with updated transform" gives a NIfTI with an updated sform, but the qform/qform_code is not properly set. This leads to e.g. 3D Slicer not being able to open the file.

JThoennissen commented 1 year ago

NIfTI documentation says:

The qform and sform stored in a nifti file are intended to fulfil the following functions:

  • specify the handedness of the coordinate system (important for getting left and right correct)
  • specify the original scanner coordinates (qform only; figure)
  • specify standard space coordinates (sform only)
  • specify a relationship with another image's coordinates (sform only)

This means in voluba the header needs to be set like: sform_code = 2 (aligned) qform_code = 1 (scanner) sform = transformation qform = scanner-transformation

In theory qform_code and qform could be copied from the original NIfTI. I'm not sure if most people stick to the standard, so maybe the actual qform is inside the sform. This can be checked via sform_code==1.

xgui3783 commented 1 year ago

ping @pacher

pacher commented 1 year ago

I am really surprised that 3D Slicer is not happy with just sform.

As per documentation linked above: the qform of the resampled image need not be set (although a transformed version could be used) and applying an affine transformation can modify sform but should set the qform to UNKNOWN This is what voluba does. It sets sform to 2 (aligned) and qform to 0 (unknown)

Otherwise what can we put into the qform to make 3D Slicer happy?

  1. The same matrix as in sform? In this case I would expect any software just to use sform, but 3D Slicer is not satisfied with only sform, which makes me think it expects something else in qform and I don't know what. According to the documentation above we can't even use aligned for qform.
  2. Copy from original? We can, but I am not sure about it. I think it has to be somehow transformed as well. At least handedness should be checked/changed.

How does 3D Slicer deal with other nifties where qform is not set? What does it want qform for? Why sform is not enough? Are there any open issues or documentation in 3D Slicer about this? What does error message say?

JThoennissen commented 1 year ago

Unfortunately 3D Slicer didn't give an expressive error message, but ITK-Snap says:

image

I'm fine with putting qform_code = unknown. But the qform matrix seems to be missing the translation part:

image

So I would suggest copying the qform from the original and setting it to unkown. This would fix the error ... What do you think?

pacher commented 1 year ago

Did you use landmarks for anchoring?

In this case it is almost certain that the transform matrix contains shearing and as I understand ITK does not support sheared matrices. I don't see how it is related to qform and it shouldn't. Could you try to export nifti with just some translation and/or rotation + scaling to make sure it works with 3D Slicer?

So I would suggest copying the qform from the original and setting it to unkown. This would fix the error ... What do you think?

unknown means "not set, should not be used" so it does not matter what we write as values. What you see in get_qform is probably pixel dimensions displayed as matrix, because voluba just fills it with zeroes.

And to answer my own questions from above:

  1. We can not write to qform the same matrix as sform because our matrices has shearing and we can't encode shearing in qform. That's why sform exists and should be preferred by software.
  2. We can copy qform from the original IF and only if it has qform_code 1 (scanner). In this case it is some other transform related to the scanner and it would be more correct to keep it, otherwise the information is lost. But I am still on the fence about it. While the benefit is only hypothetical correctness, we could get the whole new bunch of problems in practice:
    • older versions of ITK will actually pick qform over sform thus ignoring anchoring result leading to user confusion
    • some tools will expect matrices to be the same if both present and I am not sure everybody will handle different codes correctly, not to mention numerical issues
    • handedness should be checked/changed. We can implement it, but we don't have means to robustly test it
    • etc.

Anyway, I believe the problem with 3D Slicer is not related to qform and changing it will not fix it.

JThoennissen commented 1 year ago

No, I didn't use landmarks for this anchoring, so it's not an affine matrix anyway. But even if it was, voluba puts it into the sform, which isn't a problem for 3D Slicer and ITK-Snap.

For testing I copied the original qform into the transformed NIfTI's qform and left the qform_code = 0 (unkown) and the error resolved in 3D Slicer and ITK-Snap. I don't know why Slicer and ITK-Snap care about the qform even if the qform_code is set to unknown. But when a user downloads the updated NIfTI he should be able to open it in the most common tools. And it seems voluba puts something into the qform that is similar to the original one, but the difference causes the error ...

pacher commented 1 year ago

Ok. Fine. Voluba now copying original qform but sets qform_code to 0. Since the code is zero and the values should not be used, I don't see any harm in keeping them.