Skip to content

Conversation

@jdtournier
Copy link
Member

This is an alternative solution to #956, using standard read()/write() calls to avoids a few oddities with using memory-mapping to read the MGH data. This allows a lot more re-use of the code between the compressed and non-compressed cases, and seems to work well on my system. The code also seems more readable (to me, at least...)

Yet to be tested thoroughly against FreeSurfer, but as far as I can tell, the output is bit-wise identical, apart from a rounding difference in the TE entry, and a zero FOV entry (which is stated as unused in the docs). So if things fall over with FreeSurfer, that zero FOV entry is likely to be the problem...

We might also need to add a bit more error detection, particularly to avoid cases where there is no data at the end of the file. I'm not sure what would happen in this case currently...

Lestropie and others added 14 commits April 6, 2017 17:36
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.
- 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.
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.
@jdtournier jdtournier force-pushed the mgh_mgz_write_fix_take2 branch from d340fa5 to 29c93a9 Compare April 19, 2017 21:38
@jdtournier
Copy link
Member Author

OK, got FreeSurfer installed, and tested this with mri_info and mri_convert, for both .mgh and .mgz, in various combinations, with changes in datatype and strides - everything seems to check out OK. Just waiting on the final checks to finish, and we should be good to merge as far as I'm concerned...?

One final change I had planned was to substitute suitable alternative datatypes when those requested aren't available. Most other formats handle this behind the scenes to avoid causing extra confusion. Ideally, I'd like the backend to figure out when the datatype has been explicitly requested by the user and error out when that request can't be fulfilled, while substitute a suitable alternative otherwise, but that's another story...

@jdtournier
Copy link
Member Author

jdtournier commented Apr 19, 2017

OK, had a go at dealing with the datatype substitution, and also added a warning in case datatype has been substituted (for any format, not just MGH/MGZ). Hopefully that'll be it for this pull request...

- Clearer mapping from requested header datatype to MGH format datatype on write.
Removed errant VAR() call.
Copy link
Member

@Lestropie Lestropie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Survived my testing.

My remaining concern though is that the reason this version creates files that can be read by FreeSurfer is that it preserves all the null filling. This is fine in terms of not crashing FreeSurfer on a direct convert, but it means that e.g. gedit damn near hangs if you try to open a .mih file containing those comments, and e.g. if those comments are edited in any way (or if a user were to add comments prepended with "MGH_TAG_") there's every possibility that FreeSurfer could then crash again. Not the end of the world, but if I had more time I'd have preferred to convert to & from MGH/MGZ while keeping those comments human-readable.

@jdtournier
Copy link
Member Author

My remaining concern though is that the reason this version creates files that can be read by FreeSurfer is that it preserves all the null filling.

Yes, it does. But I'm not sure how FreeSurfer interprets some of these fields. The MGH_TAG_MRI_FRAME entry in particular is massive (~12000 bytes), mostly NULL, and the text bit that you see in the mrinfo output appears somewhere in the middle of all that. So there's a good chance that this is being interpreted in a binary way by FreeSurfer. If we do convert that field to text, we'd need knowledge of exactly how FreeSurfer will interpret that tag if we're to write it back to an MGH/MGZ file - safer just to preserve it as-is, I think.

And I agree that there's always scope for someone to mess with the tags by adding their own MGH_TAG_ entries in the comments field, but I don't think we can prevent this. The other option is to have these entries listed as full entries in the mif/mih header, not as comments. I'd be happy enough with that, in some respects it would simplify their handling. But it certainly doesn't prevent the kind of user interference you're talking about here, especially since we've added the -set_property option to mrconvert...

@Lestropie
Copy link
Member

Did some prodding...

  • MGH_TAG_FIELDSTRENGTH needs at least 2 \0's.

  • MFG_TAG_MRI_FRAME is OK as long as the field is at least 1364 bytes (59 bytes more than the sum of the initial nullspace and the actual data present), regardless of whether you delete nulls from the start or the end of the field. 1363 bytes and mri_info calloc errors.
    Edit: Precise numbers seem to not be reproducible; may depend on lengths of other fields read previously.

  • All other fields seem to be OK with the nulls stripped.

@jdtournier
Copy link
Member Author

OK, given the above, my gut feeling is it's safest just to keep them as-is - at least for now. We might be able to revisit later.

On the other hand, there's a strong case to be made for getting this right from the outset. If we allow conversion from MGH to .mif, and later change the handling of those fields, there's every chance the conversion back to MGH will fail or not work as expected. Maybe we really do need to nail this properly before merging...

On a different note, any opinions on my previous suggestion below?

The other option is to have these entries listed as full entries in the mif/mih header, not as comments.

@Lestropie
Copy link
Member

On the other hand, there's a strong case to be made for getting this right from the outset.

If we want to get it right:
https://surfer.nmr.mgh.harvard.edu/fswiki/FsTutorial/MghFormat?action=AttachFile&do=view&target=mriio.c
Line 11406 for read, 11686 for write.

If we want to merge in the next 7 days and include this I don't like my own chances, I've barely started my Thursday talk slides and haven't done a run through of Monday's talk. Question then is whether or not this is more critical than doing the merge for ISMRM (bearing in mind the PR started in September...)

The other option is to have these entries listed as full entries in the mif/mih header, not as comments.

Not sure that really solves any fundamental issues. Could still be modified via mrconvert, and would still produce weirdness in mrinfo output. Would only marginally reduce the burden of parsing comments, but that code's already in place.

@jdtournier
Copy link
Member Author

If we want to get it right:
https://surfer.nmr.mgh.harvard.edu/fswiki/FsTutorial/MghFormat?action=AttachFile&do=view&target=mriio.c
Line 11406 for read, 11686 for write.

😵 14,000 lines of code! That's a monster...

If we want to merge in the next 7 days and include this I don't like my own chances, I've barely started my Thursday talk slides and haven't done a run through of Monday's talk. Question then is whether or not this is more critical than doing the merge for ISMRM (bearing in mind the PR started in September...)

I'm starting to feel that way too... Thinking about it, I think we really want to avoid introducing changes now that will be changed again later, and screw up the handling of data converted with the different versions. Best to hold on with these changes, deal with the big merge, finalise all of the modifications we want to do to the MGH handling (including updating #962) , and merge those changes at a later time - as you say, they're not critical for the big merge...

The other option is to have these entries listed as full entries in the mif/mih header, not as comments.

Not sure that really solves any fundamental issues. Could still be modified via mrconvert, and would still produce weirdness in mrinfo output. Would only marginally reduce the burden of parsing comments, but that code's already in place.

It's not supposed to solve any of these fundamental issues, it's more about where we think that information ought to live. We currently store them as comments, but they're not really comments as such... Likewise, the TE/TR/TI/flip angle fields might also be better stored as dedicated entries in their own right, but in this case we have to agree on the correct header key, since it would essentially become part of the .mif storage 'standard' if we do this - it's no longer purely about MGH format handling.

But in any case, since we'll probably be delaying these changes till after the big merge, we can discuss these issues further at that point.

@Lestropie
Copy link
Member

Worth checking this file also.

@Lestropie
Copy link
Member

The other option is to have these entries listed as full entries in the mif/mih header, not as comments.

My initial reaction was to leave them as comments, since I don't think we want the nuances of other people's formats 'intruding' into our own. But on second thought, they are key-value pairs after all, so making them standard entries makes more sense in that respect. In terms of naming, I'd prefix all of them (including TE, TR, TI, flip angle, FOV) with MGH_, to make it clear that these aren't 'standardised' in any way within the MRtrix3 image format, and that these are the fields being sought when converting to MGH / MGZ.

Lestropie added 3 commits May 10, 2017 10:40
Fixes for compiling against 3.0_RC1 branch.
Moved contents of MGH format "other" field from header comment entries to header key/value pairs.
Add contents of MGH_TAG_CMDLINE to header key/value entry "command_history" as in #962, and vice-versa.
Write tag data in the same order as what appears to be performed in the FreeSurfer code: transform matrix, then general tags, then cmdline history.
@Lestropie Lestropie self-assigned this May 10, 2017
Lestropie added 2 commits May 12, 2017 20:31
Mimic FreeSurfer's own code in order to properly import additional header data that are stored in the 'other' section, and convert all data into text in order to be readable as header key-value entries. Convert back to binary when writing to MGH / MGZ format.
@Lestropie Lestropie removed their assignment May 12, 2017
@Lestropie
Copy link
Member

@jdtournier: I probably spent too much time on it, but I've mimicked the FreeSurfer import / export code for each tag, and converted the content of each to/from text form so that they're all readable in the header key/value entries.

@thijsdhollander
Copy link
Contributor

(don't mind the commits, they just bring the copyright message for the new files up to date)

@Lestropie
Copy link
Member

I'm content that this is doing as it should. For all three problematic images I've been provided with, I can convert from MGZ to .mif and back to .mgz, everything is preserved, and all header entries are readable in the .mif (as opposed to capturing bytecode). If anybody would like to test, go ahead; otherwise I'd prefer to merge given the current master is causing FreeSurfer crashes.

@thijsdhollander
Copy link
Contributor

If anybody would like to test, go ahead; otherwise I'd prefer to merge given the current master is causing FreeSurfer crashes.

As long as all current evidence shows this works, I'd go ahead and merge asap. If crashes are fixed, that's quite important. Testing can continue independently of course.

@Lestropie Lestropie merged commit dbf495e into master Jun 5, 2017
@Lestropie Lestropie deleted the mgh_mgz_write_fix_take2 branch June 5, 2017 02:36
Lestropie added a commit that referenced this pull request Jan 3, 2018
Echoes changes introduced in #970.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants