Beispiel #1
0
def test_warp_montage_volume():
    """Test warping an montage based on intracranial electrode positions."""
    import nibabel as nib
    subject_T1 = nib.load(op.join(subjects_dir, 'sample', 'mri', 'T1.mgz'))
    subject_brain = nib.load(
        op.join(subjects_dir, 'sample', 'mri', 'brain.mgz'))
    template_brain = nib.load(
        op.join(subjects_dir, 'fsaverage', 'mri', 'brain.mgz'))
    reg_affine, sdr_morph = compute_volume_registration(
        subject_brain,
        template_brain,
        zooms=5,
        niter=dict(translation=[5, 5, 5], rigid=[5, 5, 5], sdr=[3, 3, 3]),
        pipeline=('translation', 'rigid', 'sdr'))
    # make fake image with three coordinates
    CT_data = np.zeros(subject_brain.shape)
    # make electrode contact hyperintensities
    CT_data[45:47, 39:41, 49:50] = 500  # surround high intensity
    CT_data[46, 40, 49] = 1000  # center even higher intensity
    CT_data[47:49, 39:40, 49:50] = 500
    CT_data[48, 39, 50] = 1000
    CT_data[50:52, 38:40, 50:51] = 500
    CT_data[50, 39, 50] = 1000
    CT = nib.Nifti1Image(CT_data, subject_T1.affine)
    ch_coords = np.array([[-8.7040273, 17.99938754, 10.29604017],
                          [-14.03007764, 19.69978401, 12.07236939],
                          [-21.1130506, 21.98310911, 13.25658887]])
    ch_pos = dict(zip(['1', '2', '3'], ch_coords / 1000))  # mm -> m
    montage = make_dig_montage(ch_pos, coord_frame='mri')
    montage_warped, image_from, image_to = warp_montage_volume(
        montage,
        CT,
        reg_affine,
        sdr_morph,
        'sample',
        subjects_dir=subjects_dir,
        thresh=0.99)
    # checked with nilearn plot from `tut-ieeg-localize`
    # check montage in surface RAS
    ground_truth_warped = np.array([[-0.27778788, 0.24251515, -0.35693939],
                                    [-0.30033333, 0.24785714, -0.35014286],
                                    [-0.32261947, 0.25295575, -0.34614159]])
    for i in range(len(montage.ch_names)):
        assert np.linalg.norm(  # off by less than 1.5 cm
            montage_warped.dig[i]['r'] - ground_truth_warped[i]) < 0.015
    # check image_from
    assert_array_equal(np.array(np.where(_get_img_fdata(image_from) == 1)),
                       np.array([[45, 46, 46], [40, 39, 40], [49, 49, 49]]))
    assert_array_equal(np.array(np.where(_get_img_fdata(image_from) == 2)),
                       np.array([[48, 48], [39, 39], [49, 50]]))
    assert_array_equal(np.array(np.where(_get_img_fdata(image_from) == 3)),
                       np.array([[50, 50, 51], [38, 39, 39], [50, 50, 50]]))
    # check image_to, too many, just check center
    ground_truth_warped_voxels = np.array(
        [[135.5959596, 161.97979798, 123.83838384],
         [143.11111111, 159.71428571, 125.61904762],
         [150.53982301, 158.38053097, 127.31858407]])
    for i in range(len(montage.ch_names)):
        assert np.linalg.norm(
            np.array(np.where(_get_img_fdata(image_to) == i + 1)).mean(
                axis=1) - ground_truth_warped_voxels[i]) < 5

    # test inputs
    with pytest.raises(ValueError, match='`thresh` must be between 0 and 1'):
        warp_montage_volume(montage,
                            CT,
                            reg_affine,
                            sdr_morph,
                            'sample',
                            thresh=11.)
    with pytest.raises(ValueError, match='subject folder is incorrect'):
        warp_montage_volume(montage,
                            CT,
                            reg_affine,
                            sdr_morph,
                            subject_from='foo')
    CT_unaligned = nib.Nifti1Image(CT_data, subject_brain.affine)
    with pytest.raises(RuntimeError, match='not aligned to Freesurfer'):
        warp_montage_volume(montage,
                            CT_unaligned,
                            reg_affine,
                            sdr_morph,
                            'sample',
                            subjects_dir=subjects_dir)
    bad_montage = make_dig_montage(ch_pos, coord_frame='mri')
    bad_montage.dig[0]['coord_frame'] = 99
    with pytest.raises(RuntimeError,
                       match='Only single coordinate frame in '
                       'dig is supported'):
        warp_montage_volume(bad_montage,
                            CT,
                            reg_affine,
                            sdr_morph,
                            'sample',
                            subjects_dir=subjects_dir)
    wrong_montage = make_dig_montage(ch_pos, coord_frame='head')
    with pytest.raises(RuntimeError, match='Coordinate frame not supported'):
        warp_montage_volume(wrong_montage,
                            CT,
                            reg_affine,
                            sdr_morph,
                            'sample',
                            subjects_dir=subjects_dir)

    # check channel not warped
    ch_pos_doubled = ch_pos.copy()
    ch_pos_doubled.update(zip(['4', '5', '6'], ch_coords / 1000))
    doubled_montage = make_dig_montage(ch_pos_doubled, coord_frame='mri')
    with pytest.warns(RuntimeWarning, match='not assigned'):
        warp_montage_volume(doubled_montage,
                            CT,
                            reg_affine,
                            sdr_morph,
                            'sample',
                            subjects_dir=subjects_dir)
Beispiel #2
0
def test_warp_montage_volume():
    """Test warping an montage based on intracranial electrode positions."""
    import nibabel as nib
    subject_brain = nib.load(
        op.join(subjects_dir, 'sample', 'mri', 'brain.mgz'))
    template_brain = nib.load(
        op.join(subjects_dir, 'fsaverage', 'mri', 'brain.mgz'))
    zooms = dict(translation=10, rigid=10, sdr=10)
    reg_affine, sdr_morph = compute_volume_registration(
        subject_brain, template_brain, zooms=zooms,
        niter=[3, 3, 3],
        pipeline=('translation', 'rigid', 'sdr'))
    # make an info object with three channels with positions
    ch_coords = np.array([[-8.7040273, 17.99938754, 10.29604017],
                          [-14.03007764, 19.69978401, 12.07236939],
                          [-21.1130506, 21.98310911, 13.25658887]])
    ch_pos = dict(zip(['1', '2', '3'], ch_coords / 1000))  # mm -> m
    lpa, nasion, rpa = get_mni_fiducials('sample', subjects_dir)
    montage = make_dig_montage(ch_pos, lpa=lpa['r'], nasion=nasion['r'],
                               rpa=rpa['r'], coord_frame='mri')
    # make fake image based on the info
    CT_data = np.zeros(subject_brain.shape)
    # convert to voxels
    ch_coords_vox = apply_trans(
        np.linalg.inv(subject_brain.header.get_vox2ras_tkr()), ch_coords)
    for (x, y, z) in ch_coords_vox.round().astype(int):
        # make electrode contact hyperintensities
        # first, make the surrounding voxels high intensity
        CT_data[x - 1:x + 2, y - 1:y + 2, z - 1:z + 2] = 500
        # then, make the center even higher intensity
        CT_data[x, y, z] = 1000
    CT = nib.Nifti1Image(CT_data, subject_brain.affine)
    ch_coords = np.array([[-8.7040273, 17.99938754, 10.29604017],
                          [-14.03007764, 19.69978401, 12.07236939],
                          [-21.1130506, 21.98310911, 13.25658887]])
    ch_pos = dict(zip(['1', '2', '3'], ch_coords / 1000))  # mm -> m
    lpa, nasion, rpa = get_mni_fiducials('sample', subjects_dir)
    montage = make_dig_montage(ch_pos, lpa=lpa['r'], nasion=nasion['r'],
                               rpa=rpa['r'], coord_frame='mri')
    montage_warped, image_from, image_to = warp_montage_volume(
        montage, CT, reg_affine, sdr_morph, 'sample',
        subjects_dir_from=subjects_dir, thresh=0.99)
    # checked with nilearn plot from `tut-ieeg-localize`
    # check montage in surface RAS
    ground_truth_warped = np.array([[-0.009, -0.00133333, -0.033],
                                    [-0.01445455, 0.00127273, -0.03163636],
                                    [-0.022, 0.00285714, -0.031]])
    for i, d in enumerate(montage_warped.dig):
        assert np.linalg.norm(  # off by less than 1.5 cm
            d['r'] - ground_truth_warped[i]) < 0.015
    # check image_from
    for idx, contact in enumerate(range(1, len(ch_pos) + 1)):
        voxels = np.array(np.where(np.array(image_from.dataobj) == contact)).T
        assert ch_coords_vox.round()[idx] in voxels
        assert ch_coords_vox.round()[idx] + 5 not in voxels
    # check image_to, too many, just check center
    ground_truth_warped_voxels = np.array(
        [[135.5959596, 161.97979798, 123.83838384],
         [143.11111111, 159.71428571, 125.61904762],
         [150.53982301, 158.38053097, 127.31858407]])
    for i in range(len(montage.ch_names)):
        assert np.linalg.norm(
            np.array(np.where(np.array(image_to.dataobj) == i + 1)
                     ).mean(axis=1) - ground_truth_warped_voxels[i]) < 8
    # test inputs
    with pytest.raises(ValueError, match='`thresh` must be between 0 and 1'):
        warp_montage_volume(
            montage, CT, reg_affine, sdr_morph, 'sample', thresh=11.)
    with pytest.raises(ValueError, match='subject folder is incorrect'):
        warp_montage_volume(
            montage, CT, reg_affine, sdr_morph, subject_from='foo')
    CT_unaligned = nib.Nifti1Image(CT_data, template_brain.affine)
    with pytest.raises(RuntimeError, match='not aligned to Freesurfer'):
        warp_montage_volume(montage, CT_unaligned, reg_affine,
                            sdr_morph, 'sample',
                            subjects_dir_from=subjects_dir)
    bad_montage = montage.copy()
    for d in bad_montage.dig:
        d['coord_frame'] = 99
    with pytest.raises(RuntimeError, match='Coordinate frame not supported'):
        warp_montage_volume(bad_montage, CT, reg_affine,
                            sdr_morph, 'sample',
                            subjects_dir_from=subjects_dir)

    # check channel not warped
    ch_pos_doubled = ch_pos.copy()
    ch_pos_doubled.update(zip(['4', '5', '6'], ch_coords / 1000))
    doubled_montage = make_dig_montage(
        ch_pos_doubled, lpa=lpa['r'], nasion=nasion['r'],
        rpa=rpa['r'], coord_frame='mri')
    with pytest.warns(RuntimeWarning, match='not assigned'):
        warp_montage_volume(doubled_montage, CT, reg_affine,
                            None, 'sample', subjects_dir_from=subjects_dir)