mne-tools / mne-bids

MNE-BIDS is a Python package that allows you to read and write BIDS-compatible datasets with the help of MNE-Python.
https://mne.tools/mne-bids/
BSD 3-Clause "New" or "Revised" License
127 stars 84 forks source link

trans from get_head_mri_trans on ds000117 different from openfmri one #854

Open kalenkovich opened 3 years ago

kalenkovich commented 3 years ago

[Apologies! I initially submitted by mistake by hitting Ctrl+Enter. The text is now updated]

Describe the bug

Transformation matrix in the openfmri dataset (sub002) is different from the one created by get_head_mri_trans using the openneuro dataset (sub-01).

Steps to reproduce

  1. Download the -trans.fif file from openfmri.
  2. Download data from openneuro:
    openneuro-py download --dataset=ds000117 --include "sub-01"
    openneuro-py download --dataset=ds000117 --include "derivatives/freesurfer/sub-01"
  3. Run the following code to load -trans.fif and calculate the transformation using get_head_mri_trans.
from pathlib import Path

import mne
import mne_bids

# load `-trans.fif`
openfmri_trans = mne.read_trans("sub002-trans.fif")

# `get_head_mri_trans`
bids_dir = Path('ds000117')

meg_bids_path_raw = mne_bids.BIDSPath(subject='01',
                                      session='meg',
                                      task='facerecognition',
                                      run='01',
                                      root=bids_dir)

t1_bids_path = mne_bids.BIDSPath(subject='01',
                                 session='mri',
                                 root=bids_dir)

# In the openneuro dataset, the freesurfer data are structured differently from the way freesurfer does it, so we need
# to add a few folders to `fs_subject` for `get_head_mri_trans` to find the files.
fs_subject = Path('sub-01') / 'ses-mri' / 'anat'
fs_subjects_dir = bids_dir / 'derivatives' / 'freesurfer'

openneuro_trans = mne_bids.get_head_mri_trans(
    bids_path=meg_bids_path_raw, t1_bids_path=t1_bids_path,
    fs_subject=fs_subject, fs_subjects_dir=fs_subjects_dir)

Expected results

The transformations are the same.

Actual results

They are not:

print('openfmri:', openfmri_trans,
      'openneuro:', openneuro_trans,
      sep='\n')
openfmri:
<Transform | head->MRI (surface RAS)>
[[ 0.9993276   0.02825975  0.02336468 -0.00644258]
 [-0.01752848  0.92785197 -0.37253678 -0.01513725]
 [-0.03220678  0.37187651  0.92772335 -0.05592113]
 [ 0.          0.          0.          1.        ]]
openneuro:
<Transform | head->MRI (surface RAS)>
[[ 0.99950435  0.03147787  0.00044172 -0.00494183]
 [-0.02883306  0.9209773  -0.3885479  -0.01160764]
 [-0.01263747  0.38834258  0.92142842 -0.05459117]
 [ 0.          0.          0.          1.        ]]

Additional information

I had to install the development version of mne for get_head_mri_trans to work (it calls mne.chpi.get_chpi_info).

mne.sys_info(): (well, almost, I had to skip 'mayavi', 'pyvista', 'vtk', and 'PyQt5' because importing them crashed Python)

Platform: Windows-2012ServerR2-6.3.9600-SP0 Python: 3.9.4 (default, Apr 9 2021, 11:43:21) [MSC v.1916 64 bit (AMD64)] Executable: E:\Evgenii_Kalenkovich\programs\miniminiconda3\envs\reproduction\python.exe CPU: Intel64 Family 6 Model 85 Stepping 7, GenuineIntel: 64 cores Memory: 639.7 GB

mne: 0.24.dev0 numpy: 1.20.3 {blas=mkl_rt, lapack=mkl_rt} scipy: 1.6.2 matplotlib: 3.4.2 {backend=module://backend_interagg}

sklearn: 0.23.2 numba: Not found nibabel: 3.2.1 nilearn: 0.7.1 dipy: 1.4.1 cupy: Not found pandas: 1.3.1

kalenkovich commented 3 years ago

I though it might be due to the head movement compensation so I tried again with maxfiltered data but the result was the same.

 openneuro-py download --dataset=ds000117 --include "derivatives/meg_derivatives/sub-01/ses-meg/meg/sub-01_ses-meg_task-facerecognition_run-01_proc-sss_meg.fif"
meg_bids_path_tss = mne_bids.BIDSPath(subject='01',
                                      session='meg',
                                      task='facerecognition',
                                      processing='sss',
                                      run='01',
                                      root=bids_dir / 'derivatives' / 'meg_derivatives')

openneuro_trans_sss = mne_bids.get_head_mri_trans(
    bids_path=meg_bids_path_tss, t1_bids_path=t1_bids_path,
    fs_subject=fs_subject, fs_subjects_dir=fs_subjects_dir)

assert openneuro_trans_sss == openneuro_trans
hoechenberger commented 3 years ago

Why would you assume the transformation matrices should be the same? As far as I can tell, the OpenNeuro dataset does not ship with a trans.fif file. What get_head_mri_trans() does is it looks for the cardinal / fiducial / landmark points in both the MEG and MRI JSON sidecar files, and then find a suitable tranformation matrix between the two coordinate systems.

It's not clear how the trnasformation you found on OpenfMRI was created; or more precisely, whether the cardinal points were were specified to be in the exact same locations as for the OpenNeuro dataset. I don't know how to download the OpenfMRI data (it will always take me to OpenNeuro) so I cannot really look into this.

Also I noticed that you're using a trans.fif for a sub002, while the OpenNeuro subject in your example is sub-01, which could also explain the differences.

kalenkovich commented 3 years ago

One other thing I tried was to compare the fressurfer data from openneuro with what we got by running it ourselves:

our_reconned_fs_subject = 'sub001'
our_reconned_fs_subjects_dir = Path(r'../reconned')
openneuro_trans_our_reconned = mne_bids.get_head_mri_trans(
    bids_path=meg_bids_path_raw, t1_bids_path=t1_bids_path,
    fs_subject=our_reconned_fs_subject, fs_subjects_dir=our_reconned_fs_subjects_dir)

trans_diff = openneuro_trans.copy()
trans_diff['trans'] -= openneuro_trans_our_reconned['trans']
print(trans_diff)
<Transform | head->MRI (surface RAS)>
[[ 0.         -0.00000002  0.00000003 -0.00097441]
 [ 0.00000003  0.00000002  0.00000003  0.00089278]
 [-0.00000002 -0.00000003  0.00000001 -0.02038182]
 [ 0.          0.          0.          0.        ]]

The results are almost identical up to a translation.

kalenkovich commented 3 years ago

Why would you assume the transformation matrices should be the same?

That is an excellent point! Well, because it is the same dataset but stored differently :smile: I assumed that re-formatting and moving the dataset shouln't have changed anything.

As far as I can tell, the OpenNeuro dataset does not ship with a trans.fif file. What get_head_mri_trans() does is it looks for the cardinal / fiducial / landmark points in both the MEG and MRI JSON sidecar files, and then find a suitable tranformation matrix between the two coordinate systems.

I couldn't fing -trans.fif files on OpenNeuro either.

It's not clear how the trnasformation you found on OpenfMRI was created; or more precisely, whether the cardinal points were were specified to be in the exact same locations as for the OpenNeuro dataset. I don't know how to download the OpenfMRI data (it will always take me to OpenNeuro) so I cannot really look into this.

Yeah, you need to prepend legacy. to stay on openfmri.

Also I noticed that you're using a trans.fif for a sub002, while the OpenNeuro subject in your example is sub-01, which could also explain the differences.

The numbering has changed in one of the versions. I am sorry I did not mention it in the issue text.

kalenkovich commented 3 years ago

I guess I shouldn't have assumed that the matrices should be the same. And so this is not an mne-bids issue. Sorry for the noise then. I'll ask the dataset maintainers.

hoechenberger commented 3 years ago

Yeah, you need to prepend legacy. to stay on openfmri.

Ah, good to know!

Can you maybe fire up the MNE Coregistration GUI and load the trans and see where the MRI fiducials end up then?

kalenkovich commented 3 years ago

Yeah, you need to prepend legacy. to stay on openfmri.

Ah, good to know!

Can you maybe fire up the MNE Coregistration GUI and load the trans and see where the MRI fiducials end up then?

Sure thing! I'll try tomorrow (I am not at the office anymore).

kalenkovich commented 2 years ago

Hi, @hoechenberger, sorry for taking longer than I promised.

I wasn't able to make coreg work with freesurefer data stored in the BIDS format, unfortunately. I plotted the coreg in 3d (using the code from #822) instead:

def plot_coreg(bids_path, trans, label):
    info = mne.io.read_info(bids_path.fpath)
    fig = mne.viz.plot_alignment(
        info=info,
        subject=fs_subject,
        subjects_dir=fs_subjects_dir,
        trans=trans,
        surfaces="white",
        coord_frame="meg",
        meg="helmet",
        eeg=True,
        dig=True,
    )
    fig.plotter.screenshot(f"{label}.png")

plot_coreg(bids_path=meg_bids_path_raw, trans=openneuro_trans, label='openneuro')
plot_coreg(bids_path=meg_bids_path_raw, trans=openfmri_trans, label='openfmri')

ezgif com-gif-maker

kalenkovich commented 2 years ago

BTW, would it be useful if I filed an issue about the stable version of mne-bids requiring the dev version of mne?

hoechenberger commented 2 years ago

Hello, it seems I had meanwhile forgotten about this issue, sorry about that! Have you been able to figure things out?

kalenkovich commented 2 years ago

Hello, it seems I had meanwhile forgotten about this issue, sorry about that! Have you been able to figure things out?

No, unfortunately. We got lost while trying to figure out whether this is an mne-bids, the dataset, or our code issue, so we dropped it and just used the mne-bids output as is. If you have any suggestions on how to figure it out, I'd be happy to try them out.