Skip to content
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

ENH: improved brain extraction parameters #44

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ ENV PATH=/usr/local/miniconda/bin:$PATH \
RUN conda install -y python=3.7.1 \
mkl=2018.0.3 \
mkl-service \
numpy=1.15.4 \
numpy>=1.16.5 \
scipy=1.1.0 \
scikit-learn=0.19.1 \
scikit-learn>=0.20 \
matplotlib=2.2.2 \
pandas=0.23.4 \
libxml2=2.9.8 \
Expand Down
11 changes: 0 additions & 11 deletions nirodents/cli/brainextraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,6 @@ def get_parser():
default=(0, 4, 4),
help="Specify ants-ai Search Grid parameter",
)

parser.add_argument(
"--slice-direction",
dest="slice_direction",
action="store",
type=int,
default=1,
choices=[0, 1, 2],
help="Specify slice direction: 0 = Sagittal (R-L), 1 = Coronal (A-P), 2 = Axial (S-I)",
)
return parser


Expand All @@ -148,7 +138,6 @@ def main():
arc=opts.antsai_arcfrac,
step=opts.antsai_step,
grid=tuple(opts.antsai_grid),
slice_direction=opts.slice_direction,
debug=opts.debug,
mri_scheme=opts.mri_scheme,
omp_nthreads=opts.omp_nthreads,
Expand Down
2 changes: 1 addition & 1 deletion nirodents/data/artsBrainExtraction_precise_T2w.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"metric_weight": [
1,
1,
[0.5, 0.5]
[0.4, 0.6]
],
"number_of_iterations": [
[1000, 500, 250, 100],
Expand Down
33 changes: 16 additions & 17 deletions nirodents/workflows/brainextraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ def init_rodent_brain_extraction_wf(
arc=0.12,
step=4,
grid=(0, 4, 4),
slice_direction=1,
debug=False,
interim_checkpoints=True,
mem_gb=3.0,
Expand Down Expand Up @@ -128,7 +127,7 @@ def init_rodent_brain_extraction_wf(
norm_lap_tmpl = pe.Node(niu.Function(function=_trunc), name="norm_lap_tmpl")
norm_lap_tmpl.inputs.out_max = 1.0
norm_lap_tmpl.inputs.percentiles = (1, 99.99)
norm_lap_tmpl.inputs.clip_max = None
norm_lap_tmpl.inputs.clip_max = 99.9
target_sigma = pe.Node(niu.Function(function=_lap_sigma),
name="target_sigma", run_without_submitting=True)
lap_target = pe.Node(
Expand All @@ -137,7 +136,7 @@ def init_rodent_brain_extraction_wf(
norm_lap_target = pe.Node(niu.Function(function=_trunc), name="norm_lap_target")
norm_lap_target.inputs.out_max = 1.0
norm_lap_target.inputs.percentiles = (1, 99.99)
norm_lap_target.inputs.clip_max = None
norm_lap_target.inputs.clip_max = 99.9

# Set up initial spatial normalization
ants_params = "testing" if debug else "precise"
Expand Down Expand Up @@ -167,8 +166,7 @@ def init_rodent_brain_extraction_wf(
clip_tmpl.inputs.percentiles = (35.0, 90.0)

# set INU bspline grid based on voxel size
init_bspline_grid = pe.Node(niu.Function(function=_bspline_distance), name="init_bspline_grid")
init_bspline_grid.inputs.slice_dir = slice_direction
bspline_grid = pe.Node(niu.Function(function=_bspline_grid), name="bspline_grid")

# INU correction of the target image
init_n4 = pe.Node(
Expand Down Expand Up @@ -200,8 +198,8 @@ def init_rodent_brain_extraction_wf(
wf.connect([
# Target image massaging
(inputnode, clip_target, [(("in_files", _pop), "in_file")]),
(inputnode, init_bspline_grid, [(("in_files", _pop), "in_file")]),
(init_bspline_grid, init_n4, [("out", "args")]),
(inputnode, bspline_grid, [(("in_files", _pop), "in_file")]),
(bspline_grid, init_n4, [("out", "args")]),
(clip_target, denoise, [("out", "input_image")]),
(denoise, init_n4, [("output_image", "input_image")]),
(init_n4, clip_inu, [("output_image", "in_file")]),
Expand Down Expand Up @@ -274,6 +272,7 @@ def init_rodent_brain_extraction_wf(
# fmt: off
wf.connect([
(inputnode, map_brainmask, [(("in_files", _pop), "reference_image")]),
(bspline_grid, final_n4, [("out", "args")]),
(denoise, final_n4, [("output_image", "input_image")]),
# Project template's brainmask into subject space
(norm, map_brainmask, [("reverse_transforms", "transforms"),
Expand Down Expand Up @@ -453,18 +452,18 @@ def _pop(in_files):
return in_files


def _bspline_distance(in_file, spacings=(8, 10, 8), slice_dir=1):
import numpy as np
def _bspline_grid(in_file):
import nibabel as nb
import numpy as np

img = nb.load(in_file)
zooms = img.header.get_zooms()[:3]
zooms_round = [round(x, 3) for x in zooms]
extent = (np.array(img.shape[:3]) - 1) * zooms
if zooms_round.count(zooms_round[0]) != 3 and np.argmax(zooms) != slice_dir:
extent[np.argmax(zooms)], extent[slice_dir] = extent[slice_dir], extent[np.argmax(zooms)]
retval = [f"{v}" for v in np.ceil(extent / np.array(spacings)).astype(int)]
return f"-b [{'x'.join(retval)}]"
slices = img.header.get_data_shape()
# get slice ratio
ratio = [s / slices[np.argmax(slices)] for s in slices]
ratio_factor = ratio[np.argmax(ratio)] / ratio[np.argmin(ratio)]
# turn into integer resolution
mesh_res = [f"{round(i * ratio_factor)}" for i in ratio]
return f"-b [{'x'.join(mesh_res)}]"


def _lap_sigma(in_file):
Expand All @@ -474,4 +473,4 @@ def _lap_sigma(in_file):

img = nb.load(in_file)
min_vox = np.amin(img.header.get_zooms())
return str(0.3508 * math.exp(1.4652 * min_vox))
return str(1.5 * min_vox ** 0.75)
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ install_requires =
nipype ~= 1.5.1
niworkflows >= 1.3.2
templateflow ~= 0.7.1
svgutils == 0.3.1

test_requires =
coverage < 5
pytest >= 4.4
Expand Down