Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MRG Freesurfer coordinate frame tutorial #7578

Merged
merged 9 commits into from
Jul 11, 2020
Merged

Conversation

larsoner
Copy link
Member

@larsoner larsoner commented Apr 7, 2020

The idea is to help people gain fluency with the Freesurfer coordinate frame (since we use it extensively), as well as some stuff about relationships between MRI voxels and affines/MRI coordinate frame. It's not done but at least gets some content out there.

Also makes much nicer some of our info repr stuff (dig, chs entries) by ensuring that on read the constants become "named constants", so that instead of seeing this on master:

>>> import mne
>>> from pprint import pprint
>>> info = mne.io.read_info(mne.datasets.sample.data_path() + '/MEG/sample/sample_audvis_raw.fif')
>>> pprint(info['chs'][0])
{'cal': 3.1600000394149674e-09,
 'ch_name': 'MEG 0113',
 'coil_type': 3012,
 'coord_frame': 1 (FIFFV_COORD_DEVICE),
 'kind': 1,
 'loc': array([-0.1066    ,  0.0464    , -0.0604    , -0.0127    ,  0.0057    ,
       -0.99990302, -0.186801  , -0.98240298, -0.0033    , -0.98232698,
        0.18674099,  0.013541  ]),
 'logno': 113,
 'range': 0.00030517578125,
 'scanno': 1,
 'unit': 201,
 'unit_mul': 0}

You get:

>>> pprint(info['chs'][0])
{'cal': 3.1600000394149674e-09,
 'ch_name': 'MEG 0113',
 'coil_type': 3012 (FIFFV_COIL_VV_PLANAR_T1),
 'coord_frame': 1 (FIFFV_COORD_DEVICE),
 'kind': 1 (FIFFV_MEG_CH),
 'loc': array([-0.1066    ,  0.0464    , -0.0604    , -0.0127    ,  0.0057    ,
       -0.99990302, -0.186801  , -0.98240298, -0.0033    , -0.98232698,
        0.18674099,  0.013541  ]),
 'logno': 113,
 'range': 0.00030517578125,
 'scanno': 1,
 'unit': 201 (FIFF_UNIT_T_M),
 'unit_mul': 0 (FIFF_UNITM_NONE)}

Todo:

  • Better explanation of Freesurfer surface RAS (how it's defined)
  • Surfaces (read in, show, units)
  • Surface alignment (fsave, fsave sph, sample sph, sample)
  • Surface decimation (show sphere, etc.)
  • Link to forward tutorial or something that talks about vertex removal, probably a .. warn to take care of DOC: morph generated from src does not work because fwd exlcude some vertices #7007 (modify the morph tutorials and errors also?)
  • Source space entries (use_tris, etc.)

@codecov
Copy link

codecov bot commented Apr 7, 2020

Codecov Report

Merging #7578 into master will decrease coverage by 0.00%.
The diff coverage is 100.00%.

@@            Coverage Diff             @@
##           master    #7578      +/-   ##
==========================================
- Coverage   90.13%   90.13%   -0.01%     
==========================================
  Files         452      452              
  Lines       82876    82973      +97     
  Branches    13101    13121      +20     
==========================================
+ Hits        74697    74784      +87     
- Misses       5350     5356       +6     
- Partials     2829     2833       +4     

@drammock
Copy link
Member

drammock commented Apr 9, 2020

@larsoner I've pushed an expansion of the freesurfer tutorial, mostly just adding prose to the explanations without changing the code very substantively. I feel like it ends kind of abruptly, not sure if there's a good way of summarizing / wrapping up / adding some "see also" text?

@larsoner
Copy link
Member Author

I updated the top comment with other stuff I plan to add, WDYT?

@drammock
Copy link
Member

TODO list seems reasonable. I added one item: explanation of how "freesurfer surface RAS" is defined. So far we only say "it's different from nibabel's RAS, and the transform from voxels is called..." without ever saying how it's different. I tried reading the Freesurfer PPT slides that allegedly explain it, but if the answer is in there I was not smart/patient enough to extract it.

@larsoner
Copy link
Member Author

Yes, that has been my experience as well :)

I'll have to read and/or talk more to figure that out, but I agree it's worth doing...

@larsoner
Copy link
Member Author

larsoner commented Jul 9, 2020

@wmvanvliet @hoechenberger I think I addressed your comments with the latest commit. (Had to force push to deal with a rebase problem)

Copy link
Member

@hoechenberger hoechenberger left a comment

Choose a reason for hiding this comment

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

Awesome work, @larsoner! No change requests from my side :)

@susamerz
Copy link

I like the hands on, step by step approach of the rest of the tutorial, but the following sentence had my (slightly sleep deprived) brain run out of processing capacity, even though I know the underlying theory:

" These data are voxel intensity values (unsigned integers in the range 0-255). A value data[i, j, k] at a given index triplet (i, j, k) is located at real-world (x, y, z) positions (in RAS orientation) in the scanner’s native coordinate frame (defined during acquisition) by the image’s affine transformation"

Trying to parse this I get:
These data are voxel intensity values (unsigned integers in the range 0-255). A value data[i, j, k] at a given index triplet (i, j, k) is located at real-world (x, y, z) positions (in RAS orientation).
The x y and z positions are in the scanners coordinate frame, which is defined during acquisition.
The relationship between the [i,j,k] index and the x, y, z coordinates is saved (or written?) in the images affine transformation.

Is this interpretation the intended one? If yes, feel free to use that wording, if no, please clarify :)

@wmvanvliet
Copy link
Contributor

I agree with @susamerz's comment. Otherwise, I'm very happy with this, great work @larsoner!

@larsoner
Copy link
Member Author

Okay addressed comments hopefully, @susamerz can you look again at the description of the affine?

I also added the rest of the missing content. @wmvanvliet @hoechenberger want to take another look to see if the new sections make sense to you?

https://21085-1301584-gh.circle-artifacts.com/0/dev/auto_tutorials/source-modeling/plot_background_freesurfer_mne.html

@GuillaumeFavelier can you look at the 3D plotting bits and advise how to avoid using a private function? Maybe we need to expose how to get a renderer? Also take a look at the changes I needed to make to the renderer code in general, it was necessary to:

  1. get things to plot the same in mayavi and PyVista
  2. allow wireframe rendering (needed for this tutorial)

Once the 3D plotting issues are taken care of this will be ready for review/merge.

Copy link
Member

@drammock drammock left a comment

Choose a reason for hiding this comment

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

some suggestions for clarity/flow

@agramfort agramfort changed the title WIP: Freesurfer coordinate frame tutorial MRG Freesurfer coordinate frame tutorial Jul 11, 2020
@drammock drammock merged commit d839a6c into mne-tools:master Jul 11, 2020
@hoechenberger
Copy link
Member

Awesome!

@wmvanvliet
Copy link
Contributor

cool!

@larsoner larsoner deleted the freetut branch July 12, 2020 13:35
larsoner added a commit to larsoner/mne-python that referenced this pull request Jul 14, 2020
* upstream/master: (21 commits)
  MRG: Add SSP projectors to Report (mne-tools#7991)
  BUG: Fix warning (mne-tools#8006)
  WIP: TFR Doc/test changes (mne-tools#7998)
  MAINT: Remove numpydoc test on 3.6 (mne-tools#8005)
  MAINT: Better error message for mismatch (mne-tools#8007)
  MRG: Allow removal of active projectors if channels they applied to have meanwhile been dropped (mne-tools#8003)
  MRG Freesurfer coordinate frame tutorial (mne-tools#7578)
  FIX: Fix stockwell checks (mne-tools#7996)
  MRG, ENH: Add array-spacing plugin and reorganize deps (mne-tools#7997)
  MRG, ENH: Reduce memory usage of Welch PSD (mne-tools#7994)
  STY: One more [ci skip]
  STY: Docstyle [ci skip]
  Report parsing (mne-tools#7990)
  MRG, ENH: BrainVision impedance parsing (mne-tools#7974)
  BUG: Fix missing source space points (mne-tools#7988)
  [MRG] Strip base directory name from Report captions when using parse_folder (mne-tools#7986)
  DOC: Update estimates [skip travis] (mne-tools#7987)
  DOC: Try to improve find_bad_channels_maxwell doc (mne-tools#7982)
  VIZ, BUG: fix tickmarks in evoked topomap colorbar (mne-tools#7980)
  Add low-pass filter to find_bad_channels_maxwell() (mne-tools#7983)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants