Esempio n. 1
0
 write_raw_bids(
     raw,
     bids_path,
     events_data=events_data,
     event_id=event_id,
     overwrite=True,
 )
 # MRI scan
 t1_fname = op.join(subjects_dir, f"sub-{subject}", "mri", "T1.mgz")
 # transformation matrix
 trans = mne.read_trans(op.join(bids_root, f"sub-{subject}-trans.fif"))
 t1w_bids_path = BIDSPath(subject=subject, root=bids_root, suffix="T1w")
 landmarks = get_anat_landmarks(
     t1_fname,
     info=raw.info,
     trans=trans,
     fs_subject=f"sub-{subject}",
     fs_subjects_dir=subjects_dir,
 )
 t1w_bids_path = write_anat(
     image=t1_fname,
     bids_path=t1w_bids_path,
     landmarks=landmarks,
     verbose=True,
 )
 anat_dir = t1w_bids_path.directory
 # ERM
 erm_fname = op.join(bids_root, "sub-%s_erm_raw.fif" % subject)
 erm = mne.io.read_raw_fif(erm_fname, allow_maxshield="yes")
 erm.info["line_freq"] = 60
 er_date = erm.info["meas_date"].strftime("%Y%m%d")
Esempio n. 2
0
def test_update_anat_landmarks(tmp_path):
    """Test updating the anatomical landmarks of an MRI scan."""
    data_path = Path(testing.data_path())
    raw_path = data_path / 'MEG' / 'sample' / 'sample_audvis_trunc_raw.fif'
    trans_path = Path(str(raw_path).replace('_raw.fif', '-trans.fif'))
    t1_path = data_path / 'subjects' / 'sample' / 'mri' / 'T1.mgz'
    fs_subject = 'sample'
    fs_subjects_dir = data_path / 'subjects'
    bids_root = tmp_path
    bids_path_mri = BIDSPath(subject=subject_id,
                             session=session_id,
                             acquisition=acq,
                             root=bids_root,
                             datatype='anat',
                             suffix='T1w')

    # First, write the MRI scan to BIDS, including the anatomical landmarks
    info = mne.io.read_info(raw_path)
    trans = mne.read_trans(trans_path)
    landmarks = get_anat_landmarks(image=t1_path,
                                   info=info,
                                   trans=trans,
                                   fs_subject=fs_subject,
                                   fs_subjects_dir=fs_subjects_dir)
    bids_path_mri = write_anat(image=t1_path,
                               bids_path=bids_path_mri,
                               landmarks=landmarks,
                               deface=False)
    bids_path_mri_json = bids_path_mri.copy().update(extension='.json')

    # Modify the landmarks
    # Move the nasion a bit
    landmarks_new = landmarks.copy()
    landmarks_new.dig[1]['r'] *= 0.9
    update_anat_landmarks(bids_path=bids_path_mri, landmarks=landmarks_new)

    with bids_path_mri_json.fpath.open(encoding='utf-8') as f:
        mri_json = json.load(f)

    assert np.allclose(landmarks_new.dig[1]['r'],
                       mri_json['AnatomicalLandmarkCoordinates']['NAS'])

    # Remove JSON sidecar; updating the anatomical landmarks should re-create
    # the file unless `on_missing` is `'raise'`
    bids_path_mri_json.fpath.unlink()
    with pytest.raises(KeyError,
                       match='No AnatomicalLandmarkCoordinates section found'):
        update_anat_landmarks(bids_path=bids_path_mri, landmarks=landmarks_new)

    update_anat_landmarks(bids_path=bids_path_mri,
                          landmarks=landmarks_new,
                          on_missing='ignore')

    with pytest.raises(KeyError, match='landmark not found'):
        update_anat_landmarks(bids_path=bids_path_mri,
                              landmarks=landmarks_new,
                              kind='ses-1')
    update_anat_landmarks(bids_path=bids_path_mri,
                          landmarks=landmarks_new,
                          kind='ses-1',
                          on_missing='ignore')

    mri_json = json.loads(bids_path_mri_json.fpath.read_text(encoding='utf-8'))
    assert 'NAS' in mri_json['AnatomicalLandmarkCoordinates']
    assert 'NAS_ses-1' in mri_json['AnatomicalLandmarkCoordinates']

    assert np.allclose(landmarks_new.dig[1]['r'],
                       mri_json['AnatomicalLandmarkCoordinates']['NAS'])

    # Check without extension provided
    bids_path_mri_no_ext = bids_path_mri.copy().update(extension=None)
    update_anat_landmarks(bids_path=bids_path_mri_no_ext,
                          landmarks=landmarks_new)

    # Check without datatytpe provided
    bids_path_mri_no_datatype = bids_path_mri.copy().update(datatype=None)
    update_anat_landmarks(bids_path=bids_path_mri_no_datatype,
                          landmarks=landmarks)

    # Check handling of invalid input
    bids_path_invalid = bids_path_mri.copy().update(datatype='meg')
    with pytest.raises(ValueError, match='Can only operate on "anat"'):
        update_anat_landmarks(bids_path=bids_path_invalid, landmarks=landmarks)

    bids_path_invalid = bids_path_mri.copy().update(suffix=None)
    with pytest.raises(ValueError, match='lease specify the "suffix"'):
        update_anat_landmarks(bids_path=bids_path_invalid, landmarks=landmarks)

    bids_path_invalid = bids_path_mri.copy().update(suffix='meg')
    with pytest.raises(ValueError,
                       match='Can only operate on "T1w" and "FLASH"'):
        update_anat_landmarks(bids_path=bids_path_invalid, landmarks=landmarks)

    bids_path_invalid = bids_path_mri.copy().update(subject='invalid')
    with pytest.raises(ValueError, match='Could not find an MRI scan'):
        update_anat_landmarks(bids_path=bids_path_invalid, landmarks=landmarks)

    # Unsupported coordinate frame
    landmarks_invalid = landmarks.copy()
    for digpoint in landmarks_invalid.dig:
        digpoint['coord_frame'] = FIFF.FIFFV_MNE_COORD_RAS

    with pytest.raises(ValueError, match='must be specified in MRI voxel'):
        update_anat_landmarks(bids_path=bids_path_mri,
                              landmarks=landmarks_invalid)

    # Missing cardinal point
    landmarks_invalid = landmarks.copy()
    del landmarks_invalid.dig[0]
    with pytest.raises(ValueError,
                       match='did not contain all required cardinal points'):
        update_anat_landmarks(bids_path=bids_path_mri,
                              landmarks=landmarks_invalid)

    # Test with path-like landmarks
    fiducials_path = (data_path / 'subjects' / 'sample' / 'bem' /
                      'sample-fiducials.fif')

    update_anat_landmarks(bids_path=bids_path_mri,
                          landmarks=fiducials_path,
                          fs_subject='sample',
                          fs_subjects_dir=data_path / 'subjects')
    expected_coords_in_voxels = np.array([
        [68.38202, 45.24057, 43.439808],  # noqa: E241
        [42.27006, 30.758774, 74.09837],  # noqa: E202, E241
        [17.044853, 46.586075, 42.618504]
    ])
    mri_json = json.loads(bids_path_mri_json.fpath.read_text(encoding='utf-8'))
    for landmark, expected_coords in zip(('LPA', 'NAS', 'RPA'),
                                         expected_coords_in_voxels):
        assert np.allclose(mri_json['AnatomicalLandmarkCoordinates'][landmark],
                           expected_coords)
Esempio n. 3
0
def test_update_anat_landmarks(tmpdir):
    """Test updating the anatomical landmarks of an MRI scan."""
    data_path = Path(testing.data_path())
    raw_path = data_path / 'MEG' / 'sample' / 'sample_audvis_trunc_raw.fif'
    trans_path = Path(str(raw_path).replace('_raw.fif', '-trans.fif'))
    t1_path = data_path / 'subjects' / 'sample' / 'mri' / 'T1.mgz'
    fs_subject = 'sample'
    fs_subjects_dir = data_path / 'subjects'
    bids_root = Path(tmpdir)
    bids_path_mri = BIDSPath(subject=subject_id, session=session_id,
                             acquisition=acq, root=bids_root, datatype='anat',
                             suffix='T1w')

    # First, write the MRI scan to BIDS, including the anatomical landmarks
    info = mne.io.read_info(raw_path)
    trans = mne.read_trans(trans_path)
    landmarks = get_anat_landmarks(
        image=t1_path, info=info, trans=trans, fs_subject=fs_subject,
        fs_subjects_dir=fs_subjects_dir
    )
    bids_path_mri = write_anat(image=t1_path, bids_path=bids_path_mri,
                               landmarks=landmarks, deface=False)
    bids_path_mri_json = bids_path_mri.copy().update(extension='.json')

    # Modify the landmarks
    # Move the nasion a bit
    landmarks_new = landmarks.copy()
    landmarks_new.dig[1]['r'] *= 0.9
    update_anat_landmarks(bids_path=bids_path_mri, landmarks=landmarks_new)

    with bids_path_mri_json.fpath.open(encoding='utf-8') as f:
        mri_json = json.load(f)

    assert np.allclose(
        landmarks_new.dig[1]['r'],
        mri_json['AnatomicalLandmarkCoordinates']['NAS']
    )

    # Remove JSON sidecar; updating the anatomical landmarks should re-create
    # the file
    bids_path_mri_json.fpath.unlink()
    update_anat_landmarks(bids_path=bids_path_mri, landmarks=landmarks_new)

    with bids_path_mri_json.fpath.open(encoding='utf-8') as f:
        mri_json = json.load(f)

    assert np.allclose(
        landmarks_new.dig[1]['r'],
        mri_json['AnatomicalLandmarkCoordinates']['NAS']
    )

    # Check without extension provided
    bids_path_mri_no_ext = bids_path_mri.copy().update(extension=None)
    update_anat_landmarks(bids_path=bids_path_mri_no_ext,
                          landmarks=landmarks_new)

    # Check without datatytpe provided
    bids_path_mri_no_datatype = bids_path_mri.copy().update(datatype=None)
    update_anat_landmarks(bids_path=bids_path_mri_no_datatype,
                          landmarks=landmarks)

    # Check handling of invalid input
    bids_path_invalid = bids_path_mri.copy().update(datatype='meg')
    with pytest.raises(ValueError, match='Can only operate on "anat"'):
        update_anat_landmarks(bids_path=bids_path_invalid, landmarks=landmarks)

    bids_path_invalid = bids_path_mri.copy().update(suffix=None)
    with pytest.raises(ValueError, match='lease specify the "suffix"'):
        update_anat_landmarks(bids_path=bids_path_invalid, landmarks=landmarks)

    bids_path_invalid = bids_path_mri.copy().update(suffix='meg')
    with pytest.raises(ValueError,
                       match='Can only operate on "T1w" and "FLASH"'):
        update_anat_landmarks(bids_path=bids_path_invalid, landmarks=landmarks)

    bids_path_invalid = bids_path_mri.copy().update(subject='invalid')
    with pytest.raises(ValueError, match='Could not find an MRI scan'):
        update_anat_landmarks(bids_path=bids_path_invalid, landmarks=landmarks)

    # Unsupported coordinate frame
    landmarks_invalid = landmarks.copy()
    for digpoint in landmarks_invalid.dig:
        digpoint['coord_frame'] = FIFF.FIFFV_MNE_COORD_RAS

    with pytest.raises(ValueError, match='must be specified in MRI voxel'):
        update_anat_landmarks(bids_path=bids_path_mri,
                              landmarks=landmarks_invalid)

    # Missing cardinal point
    landmarks_invalid = landmarks.copy()
    del landmarks_invalid.dig[0]
    with pytest.raises(ValueError,
                       match='did not contain all required cardinal points'):
        update_anat_landmarks(bids_path=bids_path_mri,
                              landmarks=landmarks_invalid)
Esempio n. 4
0
bids_path = BIDSPath(subject=subject_id, task=task, root=bids_root)

# plot T1 to show that it is ACPC-aligned
# note that the origin is centered on the anterior commissure (AC)
# with the y-axis passing through the posterior commissure (PC)
T1_fname = op.join(subjects_dir, 'sample_seeg', 'mri', 'T1.mgz')
fig = plot_anat(T1_fname, cut_coords=(0, 0, 0))
fig.axes['x'].ax.annotate('AC', (2., -2.), (30., -40.),
                          color='w',
                          arrowprops=dict(facecolor='w', alpha=0.5))
fig.axes['x'].ax.annotate('PC', (-31., -2.), (-80., -40.),
                          color='w',
                          arrowprops=dict(facecolor='w', alpha=0.5))

# write ACPC-aligned T1
landmarks = get_anat_landmarks(T1_fname, raw.info, trans, 'sample_seeg',
                               subjects_dir)
T1_bids_path = write_anat(T1_fname,
                          bids_path,
                          deface=True,
                          landmarks=landmarks)

# write `raw` to BIDS and anonymize it (converts to BrainVision format)
#
# we need to pass the `montage` argument for coordinate frames other than
# "head" which is what MNE uses internally in the `raw` object
#
# `acpc_aligned=True` affirms that our MRI is aligned to ACPC
# if this is not true, convert to `fsaverage` (see below)!
write_raw_bids(raw,
               bids_path,
               anonymize=dict(daysback=40000),
# consist of the coordinates of three anatomical landmarks (LPA, Nasion and
# RPA (=left and right preauricular points) expressed in voxel coordinates
# w.r.t. the T1 image.

# First create the BIDSPath object.
t1w_bids_path = BIDSPath(subject=sub,
                         session=ses,
                         root=output_path,
                         suffix='T1w')

# use ``trans`` to transform landmarks from the ``raw`` file to
# the voxel space of the image
landmarks = get_anat_landmarks(
    t1_fname,  # path to the MRI scan
    info=raw.info,  # the MEG data file info from the same subject as the MRI
    trans=trans,  # our transformation matrix
    fs_subject='sample',  # FreeSurfer subject
    fs_subjects_dir=fs_subjects_dir,  # FreeSurfer subjects directory
)

# We use the write_anat function
t1w_bids_path = write_anat(
    image=t1_fname,  # path to the MRI scan
    bids_path=t1w_bids_path,
    landmarks=landmarks,  # the landmarks in MRI voxel space
    verbose=True  # this will print out the sidecar file
)
anat_dir = t1w_bids_path.directory

# %%
# Let's have another look at our BIDS directory