-
Notifications
You must be signed in to change notification settings - Fork 1.4k
[MRG] Mne watershed bem #2194
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] Mne watershed bem #2194
Changes from all commits
a0eca10
172be88
381963d
a701938
620b1ab
e325fe5
833613a
cf0f567
b914ee2
70c4dfd
7b0166b
7570fa4
7499190
e37c789
d5665ae
c219d28
730c860
9ae0306
8ad37bc
9654b3e
8ad49cd
1a22ef0
da3dcb0
5745c25
4a81371
ef5a45e
55efd41
3132b41
c5a7cca
73e36ff
8171b03
a2a5e06
8c507ed
617b679
e53c67e
dfdfaea
9d0a20b
81cd080
c2d34b0
effb961
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,13 +4,18 @@ | |
# | ||
# License: BSD (3-clause) | ||
|
||
import sys | ||
import os | ||
import os.path as op | ||
import shutil | ||
import numpy as np | ||
from scipy import linalg | ||
|
||
from .fixes import partial | ||
from .utils import verbose, logger | ||
from .utils import (verbose, logger, run_subprocess, get_subjects_dir) | ||
from .io.constants import FIFF | ||
from .externals.six import string_types | ||
from .surface import read_surface, write_bem_surface | ||
|
||
|
||
# ############################################################################ | ||
|
@@ -332,3 +337,116 @@ def cost_fun(x, points): | |
origin = x_opt[:3] | ||
radius = x_opt[3] | ||
return radius, origin | ||
|
||
|
||
# ############################################################################ | ||
# Create BEM surfaces | ||
|
||
@verbose | ||
def make_watershed_bem(subject, subjects_dir=None, overwrite=False, | ||
volume='T1', atlas=False, gcaatlas=False, preflood=None, | ||
verbose=None): | ||
""" | ||
Create BEM surfaces using the watershed algorithm included with FreeSurfer | ||
|
||
Parameters | ||
---------- | ||
subject : str | ||
Subject name (required) | ||
subjects_dir : str | ||
Directory containing subjects data. If None use | ||
the Freesurfer SUBJECTS_DIR environment variable. | ||
overwrite : bool | ||
Write over existing files | ||
volume : str | ||
Defaults to T1 | ||
atlas : bool | ||
Specify the --atlas option for mri_watershed | ||
gcaatlas : bool | ||
Use the subcortical atlas | ||
preflood : int | ||
Change the preflood height | ||
verbose : bool, str or None | ||
If not None, override default verbose level | ||
|
||
.. versionadded:: 0.10 | ||
""" | ||
env = os.environ.copy() | ||
|
||
if not os.environ.get('FREESURFER_HOME'): | ||
raise RuntimeError('FREESURFER_HOME environment variable not set') | ||
|
||
env['SUBJECT'] = subject | ||
|
||
subjects_dir = get_subjects_dir(subjects_dir, raise_error=True) | ||
env['SUBJECTS_DIR'] = subjects_dir | ||
|
||
subject_dir = op.join(subjects_dir, subject) | ||
mri_dir = op.join(subject_dir, 'mri') | ||
T1_dir = op.join(mri_dir, volume) | ||
T1_mgz = op.join(mri_dir, volume + '.mgz') | ||
bem_dir = op.join(subject_dir, 'bem') | ||
ws_dir = op.join(subject_dir, 'bem', 'watershed') | ||
|
||
if not op.isdir(subject_dir): | ||
raise RuntimeError('Could not find the MRI data directory "%s"' | ||
% subject_dir) | ||
if not op.isdir(bem_dir): | ||
os.makedirs(bem_dir) | ||
if not op.isdir(T1_dir) and not op.isfile(T1_mgz): | ||
raise RuntimeError('Could not find the MRI data') | ||
if op.isdir(ws_dir): | ||
if not overwrite: | ||
raise RuntimeError('%s already exists. Use the --overwrite option' | ||
'to recreate it.' % ws_dir) | ||
else: | ||
shutil.rmtree(ws_dir) | ||
# put together the command | ||
cmd = ['mri_watershed'] | ||
if preflood: | ||
cmd += ["-h", "%s" % int(preflood)] | ||
|
||
if gcaatlas: | ||
cmd += ['-atlas', '-T1', '-brain_atlas', env['FREESURFER_HOME'] + | ||
'/average/RB_all_withskull_2007-08-08.gca', | ||
subject_dir + '/mri/transforms/talairach_with_skull.lta'] | ||
elif atlas: | ||
cmd += ['-atlas'] | ||
if op.exists(T1_mgz): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick :) is that it for you? does it work for you? |
||
cmd += ['-useSRAS', '-surf', op.join(ws_dir, subject), T1_mgz, | ||
op.join(ws_dir, 'ws')] | ||
else: | ||
cmd += ['-useSRAS', '-surf', op.join(ws_dir, subject), T1_dir, | ||
op.join(ws_dir, 'ws')] | ||
# report and run | ||
logger.info('\nRunning mri_watershed for BEM segmentation with the ' | ||
'following parameters:\n\n' | ||
'SUBJECTS_DIR = %s\n' | ||
'SUBJECT = %s\n' | ||
'Results dir = %s\n' % (subjects_dir, subject, ws_dir)) | ||
os.makedirs(op.join(ws_dir, 'ws')) | ||
run_subprocess(cmd, env=env, stdout=sys.stdout) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note. it would be nicer if run_subprocess printed the entire command, not a list of strings. It would make copying and pasting easier, e.g. for debugging in the command line. |
||
# | ||
os.chdir(ws_dir) | ||
if op.isfile(T1_mgz): | ||
# XXX : do this with python code | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Eric89GXL we'll take care of this later. ready from end now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks for adding the reminder note |
||
surfaces = [subject + '_brain_surface', subject + | ||
'_inner_skull_surface', subject + '_outer_skull_surface', | ||
subject + '_outer_skin_surface'] | ||
for s in surfaces: | ||
cmd = ['mne_convert_surface', '--surf', s, '--mghmri', T1_mgz, | ||
'--surfout', s, "--replacegeom"] | ||
run_subprocess(cmd, env=env, stdout=sys.stdout) | ||
os.chdir(bem_dir) | ||
if op.isfile(subject + '-head.fif'): | ||
os.remove(subject + '-head.fif') | ||
|
||
# run the equivalent of mne_surf2bem | ||
points, tris = read_surface(op.join(ws_dir, | ||
subject + '_outer_skin_surface')) | ||
points *= 1e-3 | ||
surf = dict(coord_frame=5, id=4, nn=None, np=len(points), | ||
ntri=len(tris), rr=points, sigma=1, tris=tris) | ||
write_bem_surface(subject + '-head.fif', surf) | ||
|
||
logger.info('Created %s/%s-head.fif\n\nComplete.' % (bem_dir, subject)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
#!/usr/bin/env python | ||
# Authors: Lorenzo De Santis | ||
""" | ||
|
||
Create BEM surfaces using the watershed algorithm included with | ||
FreeSurfer | ||
|
||
""" | ||
|
||
from __future__ import print_function | ||
import sys | ||
|
||
from mne.bem import make_watershed_bem | ||
|
||
|
||
def run(): | ||
from mne.commands.utils import get_optparser | ||
|
||
parser = get_optparser(__file__) | ||
|
||
parser.add_option("-s", "--subject", dest="subject", | ||
help="Subject name (required)", default=None) | ||
parser.add_option("-d", "--subjects-dir", dest="subjects_dir", | ||
help="Subjects directory", default=None) | ||
parser.add_option("-o", "--overwrite", dest="overwrite", | ||
help="Write over existing files", action="store_true") | ||
parser.add_option("-v", "--volume", dest="volume", | ||
help="Defaults to T1", default='T1') | ||
parser.add_option("-a", "--atlas", dest="atlas", | ||
help="Specify the --atlas option for mri_watershed", | ||
default=False, action="store_true") | ||
parser.add_option("-g", "--gcaatlas", dest="gcaatlas", | ||
help="Use the subcortical atlas", default=False, | ||
action="store_true") | ||
parser.add_option("-p", "--preflood", dest="preflood", | ||
help="Change the preflood height", default=None) | ||
parser.add_option("--verbose", dest="verbose", | ||
help="If not None, override default verbose level", | ||
default=None) | ||
|
||
options, args = parser.parse_args() | ||
|
||
if options.subject is None: | ||
parser.print_help() | ||
sys.exit(1) | ||
|
||
subject = options.subject | ||
subjects_dir = options.subjects_dir | ||
overwrite = options.overwrite | ||
volume = options.volume | ||
atlas = options.atlas | ||
gcaatlas = options.gcaatlas | ||
preflood = options.preflood | ||
verbose = options.verbose | ||
|
||
make_watershed_bem(subject=subject, subjects_dir=subjects_dir, | ||
overwrite=overwrite, volume=volume, atlas=atlas, | ||
gcaatlas=gcaatlas, preflood=preflood, verbose=verbose) | ||
|
||
is_main = (__name__ == '__main__') | ||
if is_main: | ||
run() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,9 +10,10 @@ | |
mne_compute_proj_ecg, mne_compute_proj_eog, | ||
mne_coreg, mne_flash_bem_model, mne_kit2fiff, | ||
mne_make_scalp_surfaces, mne_maxfilter, | ||
mne_report, mne_surf2bem) | ||
mne_report, mne_surf2bem, mne_watershed_bem) | ||
from mne.utils import (run_tests_if_main, _TempDir, requires_mne, requires_PIL, | ||
requires_mayavi, requires_tvtk, ArgvSetter, slow_test) | ||
requires_mayavi, requires_tvtk, requires_freesurfer, | ||
ArgvSetter, slow_test, ultra_slow_test) | ||
from mne.io import Raw | ||
from mne.datasets import testing | ||
|
||
|
@@ -177,4 +178,28 @@ def test_surf2bem(): | |
check_usage(mne_surf2bem) | ||
|
||
|
||
@ultra_slow_test | ||
@requires_freesurfer | ||
@testing.requires_testing_data | ||
def test_watershed_bem(): | ||
"""Test mne watershed bem""" | ||
check_usage(mne_watershed_bem) | ||
# Copy necessary files to tempdir | ||
tempdir = _TempDir() | ||
mridata_path = op.join(subjects_dir, 'sample', 'mri') | ||
mridata_path_new = op.join(tempdir, 'sample', 'mri') | ||
os.mkdir(op.join(tempdir, 'sample')) | ||
os.mkdir(mridata_path_new) | ||
if op.exists(op.join(mridata_path, 'T1')): | ||
shutil.copytree(op.join(mridata_path, 'T1'), op.join(mridata_path_new, | ||
'T1')) | ||
if op.exists(op.join(mridata_path, 'T1.mgz')): | ||
shutil.copyfile(op.join(mridata_path, 'T1.mgz'), | ||
op.join(mridata_path_new, 'T1.mgz')) | ||
|
||
with ArgvSetter(('-d', tempdir, '-s', 'sample', '-o'), | ||
disable_stdout=False, disable_stderr=False): | ||
mne_watershed_bem.run() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we check the result against the |
||
|
||
|
||
run_tests_if_main() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -547,6 +547,13 @@ def slow_test(f): | |
return f | ||
|
||
|
||
@nottest | ||
def ultra_slow_test(f): | ||
"""Decorator for ultra slow tests""" | ||
f.ultra_slow_test = True | ||
return f | ||
|
||
|
||
def has_nibabel(vox2ras_tkr=False): | ||
"""Determine if nibabel is installed | ||
|
||
|
@@ -777,7 +784,7 @@ def run_subprocess(command, verbose=None, *args, **kwargs): | |
"that you use '$HOME' instead of '~'.") | ||
warnings.warn(msg) | ||
|
||
logger.info("Running subprocess: %s" % str(command)) | ||
logger.info("Running subprocess: %s" % ' '.join(command)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @agramfort can you share a screenshot or print of output generated here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. here we go
[image: Inline image 1]
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. where? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. perfect! |
||
try: | ||
p = subprocess.Popen(command, *args, **kwargs) | ||
except Exception: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add
Notes
section with.. versionadded
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still need this bit (I assume you're waiting to make all changes in one more pass, but just wanted to remind you)