Esempio n. 1
0
def mkoutersurf(image, radius, outfile):
    #radius information is currently ignored
    #it is a little tougher to deal with the morphology in python

    fill = nib.load( image )
    filld = fill.get_data()
    filld[filld==1] = 255

    gaussian = np.ones((2,2))*.25

    image_f = np.zeros((256,256,256))

    for slice in xrange(256):
        temp = filld[:,:,slice]
        image_f[:,:,slice] = convolve(temp, gaussian, 'same')

    image2 = np.zeros((256,256,256))
    image2[np.where(image_f <= 25)] = 0
    image2[np.where(image_f > 25)] = 255

    strel15 = generate_binary_structure(3, 1)

    BW2 = grey_closing(image2, structure=strel15)
    thresh = np.max(BW2)/2
    BW2[np.where(BW2 <= thresh)] = 0
    BW2[np.where(BW2 > thresh)] = 255

    v, f = marching_cubes(BW2, 100)

    v2 = np.transpose(
             np.vstack( ( 128 - v[:,0],
                          v[:,2] - 128,
                          128 - v[:,1], )))
    
    write_surface(outfile, v2, f)
Esempio n. 2
0
def test_io_surface():
    """Test reading and writing of Freesurfer surface mesh files
    """
    fname = op.join(data_path, 'subjects', 'fsaverage', 'surf', 'lh.inflated')
    pts, tri = read_surface(fname)
    write_surface(op.join(tempdir, 'tmp'), pts, tri)
    c_pts, c_tri = read_surface(op.join(tempdir, 'tmp'))
    assert_array_equal(pts, c_pts)
    assert_array_equal(tri, c_tri)
Esempio n. 3
0
def test_io_surface():
    """Test reading and writing of Freesurfer surface mesh files
    """
    tempdir = _TempDir()
    fname_quad = op.join(data_path, 'subjects', 'bert', 'surf',
                         'lh.inflated.nofix')
    fname_tri = op.join(data_path, 'subjects', 'fsaverage', 'surf',
                        'lh.inflated')
    for fname in (fname_quad, fname_tri):
        pts, tri = read_surface(fname)
        write_surface(op.join(tempdir, 'tmp'), pts, tri)
        c_pts, c_tri = read_surface(op.join(tempdir, 'tmp'))
        assert_array_equal(pts, c_pts)
        assert_array_equal(tri, c_tri)
Esempio n. 4
0
def test_io_surface():
    """Test reading and writing of Freesurfer surface mesh files
    """
    tempdir = _TempDir()
    fname_quad = op.join(data_path, 'subjects', 'bert', 'surf',
                         'lh.inflated.nofix')
    fname_tri = op.join(data_path, 'subjects', 'fsaverage', 'surf',
                        'lh.inflated')
    for fname in (fname_quad, fname_tri):
        pts, tri, vol_info = read_surface(fname, read_metadata=True)
        write_surface(op.join(tempdir, 'tmp'), pts, tri, volume_info=vol_info)
        c_pts, c_tri, c_vol_info = read_surface(op.join(tempdir, 'tmp'),
                                                read_metadata=True)
        assert_array_equal(pts, c_pts)
        assert_array_equal(tri, c_tri)
        assert_true(_is_equal_dict([vol_info, c_vol_info]))
Esempio n. 5
0
def test_io_surface():
    """Test reading and writing of Freesurfer surface mesh files."""
    tempdir = _TempDir()
    fname_quad = op.join(data_path, 'subjects', 'bert', 'surf',
                         'lh.inflated.nofix')
    fname_tri = op.join(data_path, 'subjects', 'fsaverage', 'surf',
                        'lh.inflated')
    for fname in (fname_quad, fname_tri):
        with pytest.warns(None):  # no volume info
            pts, tri, vol_info = read_surface(fname, read_metadata=True)
        write_surface(op.join(tempdir, 'tmp'), pts, tri, volume_info=vol_info)
        with pytest.warns(None):  # no volume info
            c_pts, c_tri, c_vol_info = read_surface(op.join(tempdir, 'tmp'),
                                                    read_metadata=True)
        assert_array_equal(pts, c_pts)
        assert_array_equal(tri, c_tri)
        assert_equal(object_diff(vol_info, c_vol_info), '')
Esempio n. 6
0
def test_io_surface():
    """Test reading and writing of Freesurfer surface mesh files."""
    tempdir = _TempDir()
    fname_quad = op.join(data_path, 'subjects', 'bert', 'surf',
                         'lh.inflated.nofix')
    fname_tri = op.join(data_path, 'subjects', 'fsaverage', 'surf',
                        'lh.inflated')
    for fname in (fname_quad, fname_tri):
        with warnings.catch_warnings(record=True) as w:
            pts, tri, vol_info = read_surface(fname, read_metadata=True)
        assert_true(all('No volume info' in str(ww.message) for ww in w))
        write_surface(op.join(tempdir, 'tmp'), pts, tri, volume_info=vol_info)
        with warnings.catch_warnings(record=True) as w:  # No vol info
            c_pts, c_tri, c_vol_info = read_surface(op.join(tempdir, 'tmp'),
                                                    read_metadata=True)
        assert_array_equal(pts, c_pts)
        assert_array_equal(tri, c_tri)
        assert_equal(object_diff(vol_info, c_vol_info), '')
Esempio n. 7
0
def test_bem_model_topology(tmpdir):
    """Test BEM model topological checks."""
    # bad topology (not enough neighboring tris)
    tempdir = str(tmpdir)
    makedirs(op.join(tempdir, 'foo', 'bem'))
    for fname in ('inner_skull', 'outer_skull', 'outer_skin'):
        fname += '.surf'
        copy(op.join(subjects_dir, 'sample', 'bem', fname),
             op.join(tempdir, 'foo', 'bem', fname))
    outer_fname = op.join(tempdir, 'foo', 'bem', 'outer_skull.surf')
    rr, tris = read_surface(outer_fname)
    tris = tris[:-1]
    write_surface(outer_fname, rr, tris[:-1])
    with pytest.raises(RuntimeError, match='Surface outer skull is not compl'):
        make_bem_model('foo', None, subjects_dir=tempdir)
    # Now get past this error to reach gh-6127 (not enough neighbor tris)
    rr_bad = np.concatenate([rr, np.mean(rr, axis=0, keepdims=True)], axis=0)
    write_surface(outer_fname, rr_bad, tris)
    with pytest.raises(RuntimeError, match='Surface outer skull.*triangles'):
        make_bem_model('foo', None, subjects_dir=tempdir)
# folder called ``conv`` inside the FreeSurfer subject folder to keep them in.

# Put the converted surfaces in a separate 'conv' folder
conv_dir = op.join(subjects_dir, 'sample', 'conv')
os.makedirs(conv_dir, exist_ok=True)

# Load the inner skull surface and create a problem
# The metadata is empty in this example. In real study, we want to write the
# original metadata to the fixed surface file. Set read_metadata=True to do so.
coords, faces = mne.read_surface(op.join(bem_dir, 'inner_skull.surf'))
coords[0] *= 1.1  # Move the first vertex outside the skull

# Write the inner skull surface as an .obj file that can be imported by
# Blender.
mne.write_surface(op.join(conv_dir, 'inner_skull.obj'),
                  coords,
                  faces,
                  overwrite=True)

# Also convert the outer skull surface.
coords, faces = mne.read_surface(op.join(bem_dir, 'outer_skull.surf'))
mne.write_surface(op.join(conv_dir, 'outer_skull.obj'),
                  coords,
                  faces,
                  overwrite=True)

###############################################################################
# Editing in Blender
# ^^^^^^^^^^^^^^^^^^
#
# We can now open Blender and import the surfaces. Go to *File > Import >
# Wavefront (.obj)*. Navigate to the ``conv`` folder and select the file you
Esempio n. 9
0
    surf = check_seghead()
    if surf is None:
        print('mkheadsurf did not produce the standard output file.')
        sys.exit(1)

    fif = '{0}/{1}/bem/{1}-head-dense.fif'.format(subj_dir, subject)
    print('2. Creating %s ...' % fif)
    cmd = 'mne_surf2bem --surf %s --id 4 %s --fif %s' % (surf, force, fif)
    my_run_cmd(cmd, 'Failed to create %s, see above' % fif)
    levels = 'medium', 'sparse'
    for ii, (n_tri, level) in enumerate(zip([30000, 2500], levels), 3):
        my_surf = mne.read_bem_surfaces(fif)[0]
        print('%i. Creating medium grade tessellation...' % ii)
        print('%i.1 Decimating the dense tessellation...' % ii)
        points, tris = mne.decimate_surface(points=my_surf['rr'],
                                            triangles=my_surf['tris'],
                                            n_triangles=n_tri)
        out_fif = fif.replace('dense', level)
        print('%i.2 Creating %s' % (ii, out_fif))
        surf_fname = '/tmp/tmp-surf.surf'
        # convert points to meters, make mne_analyze happy
        mne.write_surface(surf_fname, points * 1e3, tris)
        # XXX for some reason --check does not work here.
        cmd = 'mne_surf2bem --surf %s --id 4 --force --fif %s'
        cmd %= (surf_fname, out_fif)
        my_run_cmd(cmd, 'Failed to create %s, see above' % out_fif)
        os.remove(surf_fname)

    sys.exit(0)
    surf = check_seghead()
    if surf is None:
        print 'mkheadsurf did not produce the standard output file.'
        sys.exit(1)

    fif = '{0}/{1}/bem/{1}-head-dense.fif'.format(subj_dir, subject)
    print '2. Creating %s ...' % fif
    cmd = 'mne_surf2bem --surf %s --id 4 %s --fif %s' % (surf, force, fif)
    my_run_cmd(cmd, 'Failed to create %s, see above' % fif)
    levels = 'medium', 'sparse'
    for ii, (n_tri, level) in enumerate(zip([30000, 2500], levels), 3):
        my_surf = mne.read_bem_surfaces(fif)[0]
        print '%i. Creating medium grade tessellation...' % ii
        print '%i.1 Decimating the dense tessellation...' % ii
        points, tris = mne.decimate_surface(points=my_surf['rr'],
                                            triangles=my_surf['tris'],
                                            n_triangles=n_tri)
        out_fif = fif.replace('dense', level)
        print '%i.2 Creating %s' % (ii, out_fif)
        surf_fname = '/tmp/tmp-surf.surf'
        # convert points to meters, make mne_analyze happy
        mne.write_surface(surf_fname, points * 1e3, tris)
        # XXX for some reason --check does not work here.
        cmd = 'mne_surf2bem --surf %s --id 4 --force --fif %s'
        cmd %= (surf_fname, out_fif)
        my_run_cmd(cmd, 'Failed to create %s, see above' % out_fif)
        os.remove(surf_fname)

    sys.exit(0)
def _run(subjects_dir, subject, force, overwrite, verbose=None):
    this_env = copy.copy(os.environ)
    this_env['SUBJECTS_DIR'] = subjects_dir
    this_env['SUBJECT'] = subject

    if 'SUBJECTS_DIR' not in this_env:
        raise RuntimeError('The environment variable SUBJECTS_DIR should '
                           'be set')

    if not op.isdir(subjects_dir):
        raise RuntimeError('subjects directory %s not found, specify using '
                           'the environment variable SUBJECTS_DIR or '
                           'the command line option --subjects-dir')

    if 'MNE_ROOT' not in this_env:
        raise RuntimeError('MNE_ROOT environment variable is not set')

    if 'FREESURFER_HOME' not in this_env:
        raise RuntimeError('The FreeSurfer environment needs to be set up '
                           'for this script')
    force = '--force' if force else '--check'
    subj_path = op.join(subjects_dir, subject)
    if not op.exists(subj_path):
        raise RuntimeError('%s does not exits. Please check your subject '
                           'directory path.' % subj_path)

    if op.exists(op.join(subj_path, 'mri', 'T1.mgz')):
        mri = 'T1.mgz'
    else:
        mri = 'T1'

    logger.info('1. Creating a dense scalp tessellation with mkheadsurf...')

    def check_seghead(surf_path=op.join(subj_path, 'surf')):
        for k in ['/lh.seghead', '/lh.smseghead']:
            surf = surf_path + k if op.exists(surf_path + k) else None
            if surf is not None:
                break
        return surf

    my_seghead = check_seghead()
    if my_seghead is None:
        run_subprocess(['mkheadsurf', '-subjid', subject, '-srcvol', mri],
                       env=this_env)

    surf = check_seghead()
    if surf is None:
        raise RuntimeError('mkheadsurf did not produce the standard output '
                           'file.')

    dense_fname = '{0}/{1}/bem/{1}-head-dense.fif'.format(subjects_dir,
                                                          subject)
    logger.info('2. Creating %s ...' % dense_fname)
    _check_file(dense_fname, overwrite)
    run_subprocess(['mne_surf2bem', '--surf', surf, '--id', '4', force,
                    '--fif', dense_fname], env=this_env)
    levels = 'medium', 'sparse'
    my_surf = mne.read_bem_surfaces(dense_fname)[0]
    tris = [30000, 2500]
    if os.getenv('_MNE_TESTING_SCALP', 'false') == 'true':
        tris = [len(my_surf['tris'])]  # don't actually decimate
    for ii, (n_tri, level) in enumerate(zip(tris, levels), 3):
        logger.info('%i. Creating %s tessellation...' % (ii, level))
        logger.info('%i.1 Decimating the dense tessellation...' % ii)
        points, tris = mne.decimate_surface(points=my_surf['rr'],
                                            triangles=my_surf['tris'],
                                            n_triangles=n_tri)
        other_fname = dense_fname.replace('dense', level)
        logger.info('%i.2 Creating %s' % (ii, other_fname))
        _check_file(other_fname, overwrite)
        tempdir = _TempDir()
        surf_fname = tempdir + '/tmp-surf.surf'
        # convert points to meters, make mne_analyze happy
        mne.write_surface(surf_fname, points * 1e3, tris)
        # XXX for some reason --check does not work here.
        try:
            run_subprocess(['mne_surf2bem', '--surf', surf_fname, '--id', '4',
                            '--force', '--fif', other_fname], env=this_env)
        finally:
            del tempdir
Esempio n. 12
0
    def save_surface(self, filename):
        """ save the surface """

        mne.write_surface(filename, self.pos, self.triangles, create_stamp=self.subject)
Esempio n. 13
0
def make_mne_anatomy(subject,
                     subjects_dir,
                     recordings_path=None,
                     hcp_path=op.curdir,
                     outputs=('label', 'mri', 'surf')):
    """Extract relevant anatomy and create MNE friendly directory layout

    The function will create the following outputs by default:

    $subjects_dir/$subject/bem/inner_skull.surf
    $subjects_dir/$subject/label/*
    $subjects_dir/$subject/mri/*
    $subjects_dir/$subject/surf/*
    $recordings_path/$subject/$subject-head_mri-trans.fif

    These can then be set as $SUBJECTS_DIR and as MEG directory, consistent
    with MNE examples.

    Parameters
    ----------
    subject : str
        The subject name.
    subjects_dir : str
        The path corresponding to MNE/freesurfer SUBJECTS_DIR (to be created)
    hcp_path : str
        The path where the HCP files can be found.
    outputs : {'label', 'mri', 'stats', 'surf', 'touch'}
        The outputs of the freesrufer pipeline shipped by HCP. Defaults to
        ('mri', 'surf'), the minimum needed to extract MNE-friendly anatomy
        files and data.
    """
    if hcp_path == op.curdir:
        hcp_path = op.realpath(hcp_path)
    if not op.isabs(subjects_dir):
        subjects_dir = op.realpath(subjects_dir)

    this_subjects_dir = op.join(subjects_dir, subject)
    if not op.isabs(recordings_path):
        recordings_path = op.realpath(recordings_path)

    this_recordings_path = op.join(recordings_path, subject)

    if not op.exists(this_recordings_path):
        os.makedirs(this_recordings_path)

    for output in outputs:
        if not op.exists(op.join(this_subjects_dir, output)):
            os.makedirs(op.join(this_subjects_dir, output))
        if output == 'mri':
            for suboutput in ['orig', 'transforms']:
                if not op.exists(op.join(this_subjects_dir, output,
                                         suboutput)):
                    os.makedirs(op.join(this_subjects_dir, output, suboutput))

        files = get_file_paths(subject=subject,
                               data_type='freesurfer',
                               output=output,
                               hcp_path=hcp_path)
        for source in files:
            match = [match for match in re.finditer(subject, source)][-1]
            split_path = source[:match.span()[1] + 1]
            target = op.join(this_subjects_dir, source.split(split_path)[-1])
            if (not op.isfile(target) and not op.islink(target)
                    and op.exists(source)):  # don't link if it's not there.
                if sys.platform != 'win32':
                    os.symlink(source, target)
                else:
                    shutil.copyfile(source, target)

    logger.info('reading extended structural processing ...')

    # Step 1 #################################################################
    # transform head models to expected coordinate system

    # make hcp trans
    transforms_fname = get_file_paths(subject=subject,
                                      data_type='meg_anatomy',
                                      output='transforms',
                                      hcp_path=hcp_path)
    transforms_fname = [
        k for k in transforms_fname if k.endswith('transform.txt')
    ][0]
    hcp_trans = _read_trans_hcp(fname=transforms_fname, convert_to_meter=False)

    # get RAS freesurfer trans
    c_ras_trans_fname = get_file_paths(subject=subject,
                                       data_type='freesurfer',
                                       output='mri',
                                       hcp_path=hcp_path)
    c_ras_trans_fname = [
        k for k in c_ras_trans_fname if k.endswith('c_ras.mat')
    ][0]
    logger.info('reading RAS freesurfer transform')
    # ceci n'est pas un .mat file ...

    with open(op.join(subjects_dir, c_ras_trans_fname)) as fid:
        ras_trans = np.array([r.split() for r in fid.read().split('\n') if r],
                             dtype=np.float64)

    logger.info('Combining RAS transform and coregistration')
    ras_trans_m = linalg.inv(ras_trans)  # and the inversion

    logger.info('extracting head model')
    head_model_fname = get_file_paths(subject=subject,
                                      data_type='meg_anatomy',
                                      output='head_model',
                                      hcp_path=hcp_path)[0]
    pnts, faces = _get_head_model(head_model_fname=head_model_fname)

    logger.info('coregistring head model to MNE-HCP coordinates')
    pnts = apply_trans(ras_trans_m.dot(hcp_trans['bti2spm']), pnts)

    tri_fname = op.join(this_subjects_dir, 'bem', 'inner_skull.surf')
    if not op.exists(op.dirname(tri_fname)):
        os.makedirs(op.dirname(tri_fname))
    write_surface(tri_fname, pnts, faces)

    # Step 2 #################################################################
    # write corresponding device to MRI transform

    logger.info('extracting coregistration')
    # now convert to everything meter too here
    ras_trans_m[:3, 3] *= 1e-3
    bti2spm = hcp_trans['bti2spm']
    bti2spm[:3, 3] *= 1e-3
    head_mri_t = Transform(  # we're lying here for a good purpose
        'head', 'mri', np.dot(ras_trans_m, bti2spm))  # it should be 'ctf_head'
    write_trans(
        op.join(this_recordings_path, '%s-head_mri-trans.fif' % subject),
        head_mri_t)
Esempio n. 14
0
def make_mne_anatomy(subject, subjects_dir, recordings_path=None,
                     hcp_path=op.curdir, outputs=('label', 'mri', 'surf')):
    """Extract relevant anatomy and create MNE friendly directory layout

    The function will create the following outputs by default:

    $subjects_dir/$subject/bem/inner_skull.surf
    $subjects_dir/$subject/label/*
    $subjects_dir/$subject/mri/*
    $subjects_dir/$subject/surf/*
    $recordings_path/$subject/$subject-head_mri-trans.fif

    These can then be set as $SUBJECTS_DIR and as MEG directory, consistent
    with MNE examples.

    Parameters
    ----------
    subject : str
        The subject name.
    subjects_dir : str
        The path corresponding to MNE/freesurfer SUBJECTS_DIR (to be created)
    hcp_path : str
        The path where the HCP files can be found.
    outputs : {'label', 'mri', 'stats', 'surf', 'touch'}
        The outputs of the freesrufer pipeline shipped by HCP. Defaults to
        ('mri', 'surf'), the minimum needed to extract MNE-friendly anatomy
        files and data.
    """
    if hcp_path == op.curdir:
        hcp_path = op.realpath(hcp_path)
    if not op.isabs(subjects_dir):
        subjects_dir = op.realpath(subjects_dir)

    this_subjects_dir = op.join(subjects_dir, subject)
    if not op.isabs(recordings_path):
        recordings_path = op.realpath(recordings_path)

    this_recordings_path = op.join(recordings_path, subject)

    if not op.exists(this_recordings_path):
        os.makedirs(this_recordings_path)

    for output in outputs:
        if not op.exists(op.join(this_subjects_dir, output)):
            os.makedirs(op.join(this_subjects_dir, output))
        if output == 'mri':
            for suboutput in ['orig', 'transforms']:
                if not op.exists(
                        op.join(this_subjects_dir, output, suboutput)):
                    os.makedirs(op.join(this_subjects_dir, output, suboutput))

        files = get_file_paths(
            subject=subject, data_type='freesurfer', output=output,
            hcp_path=hcp_path)
        for source in files:
            match = [match for match in re.finditer(subject, source)][-1]
            split_path = source[:match.span()[1] + 1]
            target = op.join(this_subjects_dir, source.split(split_path)[-1])
            if (not op.isfile(target) and not op.islink(target) and
                    op.exists(source)):  # don't link if it's not there.
                if sys.platform != 'win32':
                    os.symlink(source, target)
                else:
                    shutil.copyfile(source, target)

    logger.info('reading extended structural processing ...')

    # Step 1 #################################################################
    # transform head models to expected coordinate system

    # make hcp trans
    transforms_fname = get_file_paths(
        subject=subject, data_type='meg_anatomy', output='transforms',
        hcp_path=hcp_path)
    transforms_fname = [k for k in transforms_fname if
                        k.endswith('transform.txt')][0]
    hcp_trans = _read_trans_hcp(fname=transforms_fname, convert_to_meter=False)

    # get RAS freesurfer trans
    c_ras_trans_fname = get_file_paths(
        subject=subject, data_type='freesurfer', output='mri',
        hcp_path=hcp_path)
    c_ras_trans_fname = [k for k in c_ras_trans_fname if
                         k.endswith('c_ras.mat')][0]
    logger.info('reading RAS freesurfer transform')
    # ceci n'est pas un .mat file ...

    with open(op.join(subjects_dir, c_ras_trans_fname)) as fid:
        ras_trans = np.array([
            r.split() for r in fid.read().split('\n') if r],
            dtype=np.float64)

    logger.info('Combining RAS transform and coregistration')
    ras_trans_m = linalg.inv(ras_trans)  # and the inversion

    logger.info('extracting head model')
    head_model_fname = get_file_paths(
        subject=subject, data_type='meg_anatomy', output='head_model',
        hcp_path=hcp_path)[0]
    pnts, faces = _get_head_model(head_model_fname=head_model_fname)

    logger.info('coregistring head model to MNE-HCP coordinates')
    pnts = apply_trans(ras_trans_m.dot(hcp_trans['bti2spm']), pnts)

    tri_fname = op.join(this_subjects_dir, 'bem', 'inner_skull.surf')
    if not op.exists(op.dirname(tri_fname)):
        os.makedirs(op.dirname(tri_fname))
    write_surface(tri_fname, pnts, faces)

    # Step 2 #################################################################
    # write corresponding device to MRI transform

    logger.info('extracting coregistration')
    # now convert to everything meter too here
    ras_trans_m[:3, 3] *= 1e-3
    bti2spm = hcp_trans['bti2spm']
    bti2spm[:3, 3] *= 1e-3
    head_mri_t = Transform(  # we're lying here for a good purpose
        'head', 'mri', np.dot(ras_trans_m, bti2spm))  # it should be 'ctf_head'
    write_trans(op.join(this_recordings_path,
                        '%s-head_mri-trans.fif' % subject), head_mri_t)
Esempio n. 15
0
def make_outer_surf(
    orig_pial: Union[str, Path],
    image: Union[str, Path],
    output_fpath: Union[str, Path],
    outer_surface_sphere: float = 15,
):
    """Create outer surface of a pial volume.

    Make outer surface based on a pial volume and radius,
    write to surface in outfile.

    Parameters
    ----------
    orig_pial : str | pathlib.Path
        Pial surface (e.g. lh.pial)
    image : str | pathlib.Path
        Filled lh or rh pial image (e.g. lh.pial.filled.mgz)
    output_fpath : str | pathlib.Path
        surface file to write data to
    outer_surface_sphere : float | None
        radius for smoothing in mm (default=15). diameter of the sphere used
        by make_outer_surface to close the sulci using morphological operations.
        Ignored currently. Corresponds to ``se=strel('sphere',se_diameter);``
        in Matlab. See [1].

    References
    ----------
    .. [1] See FieldTrip Toolbox ``make_outer_surface`` function inside
    ``prepare_mesh_cortexhull.m`` file.

    .. [2] https://github.com/aestrivex/ielu
    """
    from scipy.signal import convolve
    from scipy.ndimage.morphology import grey_closing, generate_binary_structure
    from mne import write_surface
    from mcubes import marching_cubes

    # radius information is currently ignored
    # it is a little tougher to deal with the morphology in python

    # load original pial surface to get the volume information
    pial_surf = nb.freesurfer.read_geometry(orig_pial, read_metadata=True)
    volume_info = pial_surf[2]

    # load filled pial image
    fill = nb.load(image)
    filld = fill.get_data()
    filld[filld == 1] = 255

    # apply a very soft Gaussian filter with sigma = 1mm to
    # facilitate the closing
    gaussian = np.ones((2, 2)) * 0.25

    # initialize image cube array
    image_f = np.zeros((256, 256, 256))

    # initialize a thresholded image
    image2 = np.zeros((256, 256, 256))

    # for each slice, convolve the Gaussian filter on the
    # filled image
    for slice in range(256):
        temp = filld[:, :, slice]
        image_f[:, :, slice] = convolve(temp, gaussian, "same")

    # thresholded image based on value of 25
    image2[np.where(image_f <= 25)] = 0
    image2[np.where(image_f > 25)] = 255

    strel15 = generate_binary_structure(3, 1)

    # run multi-dimensional grayscale closing of the image
    BW2 = grey_closing(image2, structure=strel15)
    thresh = np.max(BW2) / 2
    BW2[np.where(BW2 <= thresh)] = 0
    BW2[np.where(BW2 > thresh)] = 255

    # apply marching cubes algorithm to get
    # vertices and faces
    v, f = marching_cubes(BW2, 100)

    # in order to cope with the different orientation
    v2 = np.transpose(
        np.vstack((
            128 - v[:, 0],
            v[:, 2] - 128,
            128 - v[:, 1],
        )))

    write_surface(output_fpath, v2, f, volume_info=volume_info)
Esempio n. 16
0
# <https://en.wikipedia.org/wiki/Wavefront_.obj_file>`_ files and create a new
# folder called ``conv`` inside the FreeSurfer subject folder to keep them in.

# Put the converted surfaces in a separate 'conv' folder
conv_dir = subjects_dir / 'sample' / 'conv'
os.makedirs(conv_dir, exist_ok=True)

# Load the inner skull surface and create a problem
# The metadata is empty in this example. In real study, we want to write the
# original metadata to the fixed surface file. Set read_metadata=True to do so.
coords, faces = mne.read_surface(bem_dir / 'inner_skull.surf')
coords[0] *= 1.1  # Move the first vertex outside the skull

# Write the inner skull surface as an .obj file that can be imported by
# Blender.
mne.write_surface(conv_dir / 'inner_skull.obj', coords, faces, overwrite=True)

# Also convert the outer skull surface.
coords, faces = mne.read_surface(bem_dir / 'outer_skull.surf')
mne.write_surface(conv_dir / 'outer_skull.obj', coords, faces, overwrite=True)

# %%
# Editing in Blender
# ^^^^^^^^^^^^^^^^^^
#
# See the following video tutorial for how to import, edit and export
# surfaces in Blender (step-by-step instructions are also below):
#
# ..  youtube:: JBIaX7VaTZk
#
# We can now open Blender and import the surfaces. Go to *File > Import >