Conversation
Creating .mgh / .mgz images with little-endian encoding causes faults in other softwares; therefore enforce big-endianness regardless of header datatype.
Consistently read flip angle in radians and convert to degrees for header storage, and convert from degrees to radians when writing from header into MGHO.
|
OK, had a look at this - not fun... First off, the docs state clearly that it's supposed to be stored big-endian - I think we can safely skip all the endian-ness checks and just assume big-endian. Otherwise, I had a go at understanding their storage conventions, and I think it's not too difficult. Obscure to figure out, but otherwise pretty easy. The relevant sources are their tags.h and tags.c files. But essentially, it boils down to:
I've had a quick go at getting this working for reading, check out branch As to supporting these entries for |
|
Here is relevant up-to-date excerpt from PEDIR means phase encoding direction. I have tested the branch |
|
OK, had a shot at getting full read/write support working for tags with both |
|
I have tested this on several files and it worked OK: The tags have been correctly preserved and read by |
Well, the file you sent through has 3 such tags... 😉
We have discussed including such an option within MRtrix3 quite a few times in the past. Maybe now is the time... Part of the reason we haven't been too bothered about it so far is that the command history won't survive conversion to other formats, notably NIfTI. So passing data through e.g. Note that if we do go along with it, it'll probably be as part of the next release, which shouldn't be too far now. In this case, we'd need to handle that MGH tag differently - not a problem, just needs to handled properly. On the other hand, I'm not too sure how to handle that tag 41 |
Looking at the code, the maximum number of command line tags limits
http://dicomlookup.com/lookup.asp?sw=Tnumber&q=(0018,1312) is copied into During |
Such cases could (should!) be dealt with explicitly. Ideally each script would grab the |
|
@Lestropie: are you happy to merge this as-is to |
|
Sounds good to me 👍 . Administrative announcement: @Lestropie will probably not respond until after the long Easter weekend. (he left camping with only pen and paper as a means to do science) |
|
Man, writing TCP-IP packets using pen and paper is hard... :-P Don't have time to muck around with this extensively. If the addition is to properly read the MGHO "tags" field, and it's tested for both
|
- remove detection of byte order, now hard-coded to Big-endian as per documentation; - use sized types throughout in MGH header structures to ensure correct byte swapping, etc.; - convert tag IDs to text and vice-versa for known tags, and substitute with raw number if unknown; - general cleanup to maximise code reuse between .mgh and .mgz formats.
|
OK, had a shot at cleaning things up a bit more, should be good to go. Tags are now named according to the table supplied by @ansk, and convert back and forth OK as far as I can tell. The After that, I guess we can start thinking about #962... |
Note that now the contents of struct mgh_tag will appear as big-endian in all ciircumstances, and therefore conversion is necessary whenever reading or writing; this is to be consistent with the other mgh header structures.
|
Have had a look and a tweak, but it's still not ready to go. MRtrix3 will now happily read |
|
I got the idea of Yes, it was confirmed working at one point; but there were changes subsequent to that. I've also been looking at null terminations (or lack thereof) wondering if that's causing issues. Also not sure if all combinations were tested, i.e. Freesurfer export to MRtrix import, MRtrix export to FreeSurfer import, MRtrix export to MRtrix import, zipped v.s. unzipped. |
| for (const auto& tag : MGHO.tags) { | ||
| out.write (reinterpret_cast<const char*> (&tag.id), sizeof(tag.id)); | ||
| out.write (reinterpret_cast<const char*> (&tag.size), sizeof(tag.size)); | ||
| assert (size_t(ByteOrder::BE (tag.size)) == tag.content.size()); |
There was a problem hiding this comment.
That assert will fail routinely, because of the null termination on the tag.content string. For example, in the data sent through by @ansk:
...
mrinfo [lib/formats/mgh.cpp: 63]: tag.id = 33
mrinfo [lib/formats/mgh.cpp: 64]: tag.size = 1600
mrinfo [lib/formats/mgh.cpp: 65]: tag.content.size() = 185
mrinfo [lib/formats/mgh.cpp: 66]: tag.content = AutoAlign 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000
...
Not sure whether this has anything to do with FreeSurfer not accepting these data, but that's how it worked before when it was confirmed as working. I'm guessing it'll be something else...
There was a problem hiding this comment.
That specific case is a write, so it's only testing that MRtrix has set the tag.size value appropriately. Nothing to do with input data.
I'm pretty sure that FreeSurfer does not include null terminators (at least not always) in the length calculation: the phase encode direction tag gave a size of 7 for the string UNKNOWN.
I figured it might have been something like that... My only concern with your changes is that it looks like you're keeping big-endian versions of the tags once read in RAM. I think it would be much cleaner to convert at the read or write time, and maintain native-endian versions in RAM at all times otherwise. I'll have a go at that.
Pretty sure the testing wouldn't have been extensive, at least not on my side - I don't have FreeSurfer installed... It will need some more thorough testing before merging. |
Trouble then is that you have these tags being stored in RAM with native endianness, but the header & other structs being represented as big-endian at all times. Was just another source of confusion when I was looking through it all. |
OK, I see. It might be that we'd be better off not using memory-mapping for the read then. Would also avoid this issue with alignment and the |
|
Canned in favour of #970 |
|
@ansk: Where did you get that up-to-date |
|
@Lestropie, |
|
OK thanks @ansk; that looks more up-to-date than a forked version of the repository I found after sending that message. For reference for future me: Implementation code is found in |
|
@ansk (and anybody else interested): I've mimiced much of the FreeSurfer code in MRtrix3 to further improve the handling of MGH / MGZ files in #970. If anybody has image files that have consistently caused problems in MRtrix3, it would be appreciated to test them against the |
Creating .mgh / .mgz images with little-endian encoding causes faults in other softwares; therefore enforce big-endianness regardless of header datatype.
Closes #952.