Skip to content

Commit

Permalink
[DOC] Add citations for anatomical workflow and dsi studio (#584)
Browse files Browse the repository at this point in the history
* Add citations for anatomical and dsi studio
  • Loading branch information
mattcieslak authored Jun 10, 2023
1 parent 5b8c4f7 commit 467cd0f
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 47 deletions.
46 changes: 46 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,49 @@
0.18.0 (June 9, 2023)
=====================

No technical changes to the pipeline here, but citations and methods boilerplate have been updated to
reflect the changes in 0.18.0alpha0.



0.18.0alpha0 (May 26, 2023)
===========================

First release moving towards 1.0! Please open bug reports if anything suspicious comes up. This release
changes the anatomical workflow significantly, synthstrip and synthseg are used. The recon workflow
"dsi_studio_autotrack" has also been added.

## What's Changed
* Bump sentry-sdk from 0.13.1 to 1.14.0 by @dependabot in https://github.com/PennLINC/qsiprep/pull/539
* [ENH] Update FreeSurfer to 7.3.1, dmri-amico to 1.5.4 by @mattcieslak in https://github.com/PennLINC/qsiprep/pull/537
* WIP: ENH: Make pyAFQ tests faster, add export all by @36000 in https://github.com/PennLINC/qsiprep/pull/534
* [ENH] move biascorrect so it runs on resampled data by default by @mattcieslak in https://github.com/PennLINC/qsiprep/pull/527
* [Fix] Fix threading on DRBUDDI interface by @mattcieslak in https://github.com/PennLINC/qsiprep/pull/540
* [ENH] add CNR to the imageqc.csv by @mattcieslak in https://github.com/PennLINC/qsiprep/pull/541
* [FIX] pin pandas version to < 2.0.0 by @mattcieslak in https://github.com/PennLINC/qsiprep/pull/543
* ENH: Replace avscale with non-fsl tools by @jbh1091 in https://github.com/PennLINC/qsiprep/pull/542
* ENH: Replace fsl applymask by @jbh1091 in https://github.com/PennLINC/qsiprep/pull/544
* Replace fsl split by @jbh1091 in https://github.com/PennLINC/qsiprep/pull/548
* [FIX] Update distortion_group_merge.py by @smeisler in https://github.com/PennLINC/qsiprep/pull/555
* [ENH] Redo anatomical workflow by @mattcieslak in https://github.com/PennLINC/qsiprep/pull/553
* [FIX] remove pre bids-filter acq type argument by @octomike in https://github.com/PennLINC/qsiprep/pull/557
* FIX: Replace deprecated `np.int` instances by @smeisler in https://github.com/PennLINC/qsiprep/pull/558
* [WIP] ENH: 482 remove fsl dependency by @jbh1091 in https://github.com/PennLINC/qsiprep/pull/498
* [ENH] Update TORTOISE for improved T2w registration by @mattcieslak in https://github.com/PennLINC/qsiprep/pull/564
* [FIX] T2w anat-modality issues by @mattcieslak in https://github.com/PennLINC/qsiprep/pull/565
* [FIX] update boost in tortoise by @mattcieslak in https://github.com/PennLINC/qsiprep/pull/569
* [FIX] connections on multi-anat workflow by @mattcieslak in https://github.com/PennLINC/qsiprep/pull/572
* [ENH] Update DSI Studio to the latest commit by @mattcieslak in https://github.com/PennLINC/qsiprep/pull/573
* [ENH] Add DSI Studio AutoTrack recon workflow by @mattcieslak in https://github.com/PennLINC/qsiprep/pull/576

## New Contributors
* @dependabot made their first contribution in https://github.com/PennLINC/qsiprep/pull/539
* @jbh1091 made their first contribution in https://github.com/PennLINC/qsiprep/pull/542
* @smeisler made their first contribution in https://github.com/PennLINC/qsiprep/pull/555

**Full Changelog**: https://github.com/PennLINC/qsiprep/compare/0.17.0...0.18.0alpha0


0.16.1 (October 10, 2022)
=========================

Expand Down
54 changes: 53 additions & 1 deletion qsiprep/data/boilerplate.bib
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ @article{ants
year = 2008
}

@article{fsl_fast,
@article{fsl_fast,
author = {Zhang, Y. and Brady, M. and Smith, S.},
doi = {10.1109/42.906424},
issn = {0278-0062},
Expand Down Expand Up @@ -594,4 +594,56 @@ @article{pfgibbs
pages={2733--2750},
year={2021},
publisher={Wiley Online Library}
}

@article{synthstrip,
title={SynthStrip: skull-stripping for any brain image},
author={Hoopes, Andrew and Mora, Jocelyn S and Dalca, Adrian V and Fischl, Bruce and Hoffmann, Malte},
journal={NeuroImage},
volume={260},
pages={119474},
year={2022},
publisher={Elsevier}
}

@article{synthseg1,
title={SynthSeg: Segmentation of brain MRI scans of any contrast and resolution without retraining},
author={Billot, Benjamin and Greve, Douglas N and Puonti, Oula and Thielscher, Axel and Van Leemput, Koen and Fischl, Bruce and Dalca, Adrian V and Iglesias, Juan Eugenio and others},
journal={Medical image analysis},
volume={86},
pages={102789},
year={2023},
publisher={Elsevier}
}

@article{synthseg2,
title={Robust machine learning segmentation for large-scale analysis of heterogeneous clinical brain MRI datasets},
author={Billot, Benjamin and Magdamo, Colin and Cheng, You and Arnold, Steven E and Das, Sudeshna and Iglesias, Juan Eugenio},
journal={Proceedings of the National Academy of Sciences},
volume={120},
number={9},
pages={e2216399120},
year={2023},
publisher={National Acad Sciences}
}

@article{yeh2013deterministic,
title={Deterministic diffusion fiber tracking improved by quantitative anisotropy},
author={Yeh, Fang-Cheng and Verstynen, Timothy D and Wang, Yibao and Fern{\'a}ndez-Miranda, Juan C and Tseng, Wen-Yih Isaac},
journal={PloS one},
volume={8},
number={11},
pages={e80713},
year={2013},
publisher={Public Library of Science San Francisco, USA}
}

@article{autotrack,
title={Shape analysis of the human association pathways},
author={Yeh, Fang-Cheng},
journal={Neuroimage},
volume={223},
pages={117329},
year={2020},
publisher={Elsevier}
}
2 changes: 2 additions & 0 deletions qsiprep/interfaces/dsi_studio.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import pandas as pd
from .bids import get_bids_params
LOGGER = logging.getLogger('nipype.interface')
DSI_STUDIO_VERSION = "94b9c79"


class DSIStudioCommandLineInputSpec(CommandLineInputSpec):
Expand Down Expand Up @@ -807,6 +808,7 @@ class _AutoTrackInputSpec(DSIStudioCommandLineInputSpec):
argstr="%s",
usedefault=True,
desc="Forces DSI Studio to write results in cwd")
_boilerplate_traits = ["track_id", "track_voxel_ratio", "tolerance", "yield_rate"]


class _AutoTrackOutputSpec(DSIStudioCommandLineInputSpec):
Expand Down
21 changes: 19 additions & 2 deletions qsiprep/interfaces/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,12 @@
traits, isdefined, File, InputMultiPath,
TraitedSpec, DynamicTraitedSpec, BaseInterfaceInputSpec, SimpleInterface
)
from nipype.interfaces.io import add_traits
from nipype.interfaces.io import add_traits, isdefined
from nipype.interfaces import ants
from ..utils.atlases import get_atlases

IFLOGGER = logging.getLogger('nipype.interfaces')


class GetConnectivityAtlasesInputSpec(BaseInterfaceInputSpec):
atlas_names = traits.List(mandatory=True, desc='atlas names to be used')
forward_transform = File(exists=True, desc='transform to get atlas into T1w space if desired')
Expand Down Expand Up @@ -514,3 +513,21 @@ def _concat_xfms(in_list, invert):
out_xfm = np.linalg.inv(out_xfm)

return out_xfm


def interface_to_boilerplate(interface, ignore=["args", "environ", "output_dir"]):
"""Create a string from an interface."""

if not hasattr(interface.inputs, "_boilerplate_traits"):
return ""
boilerplate_traits = interface.inputs._boilerplate_traits
display_items = []
for trait_name, trait_value in interface.inputs.traits():
if not trait_name in boilerplate_traits:
continue
if not isdefined(trait_value):
continue



return ""
66 changes: 31 additions & 35 deletions qsiprep/workflows/anatomical/volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class DerivativesDataSink(FDerivativesDataSink):
'MNI152NLin2009cAsym': 'mni_icbm152_nlin_asym_09c',
}

ANTS_VERSION=BrainExtraction().version or '<ver>'
FS_VERSION="7.3.1"

# pylint: disable=R0914
def init_anat_preproc_wf(template, debug, dwi_only,
Expand Down Expand Up @@ -162,9 +164,6 @@ def init_anat_preproc_wf(template, debug, dwi_only,
name='outputnode')

# Make sure we have usable anatomical reference images/masks
desc = """\
A template {contrast}w image in {template} space was selected as a standard
reference image. """
get_template_image = pe.Node(
GetTemplate(template_name=template,
infant_mode=infant_mode,
Expand All @@ -180,7 +179,7 @@ def init_anat_preproc_wf(template, debug, dwi_only,
(reference_grid_wf, outputnode, [('outputnode.grid_image', 'dwi_sampling_grid')])])

if dwi_only:
LOGGER.info("No anatomical scans available! Visual reports will show template masks.")
LOGGER.info("No anatomical scans will be processed! Visual reports will show template masks.")
workflow.connect([
(get_template_image, outputnode, [
('template_file', 't1_preproc'),
Expand All @@ -190,16 +189,6 @@ def init_anat_preproc_wf(template, debug, dwi_only,
workflow.add_nodes([inputnode])
return workflow

workflow.__postdesc__ = """\
Brain tissue segmentation of cerebrospinal fluid (CSF),
white-matter (WM) and gray-matter (GM) was performed on
the {contrast} using `SynthSeg` [FreeSurfer, @synthseg].
Brain extraction was performed on the {contrast} image
using `SynthStrip` [FreeSurfer, @synthstrip]
""".format(
ants_ver=BrainExtraction().version or '<ver>',
contrast=anatomical_contrast
)
desc = """Anatomical data preprocessing
: """
Expand All @@ -215,7 +204,7 @@ def init_anat_preproc_wf(template, debug, dwi_only,
"""
workflow.__desc__ = desc.format(
num_anats=num_anat_images,
ants_ver=BrainExtraction().version or '<ver>',
ants_ver=ANTS_VERSION,
contrast=anatomical_contrast[:-1], # remove the "w"
template=template
)
Expand All @@ -242,6 +231,16 @@ def init_anat_preproc_wf(template, debug, dwi_only,
sloppy=debug,
name="synthseg_anat_wf")

# Synthstrip is used a lot elsewhere, so make boilerplate for the anatomy-specific
# version here. TODO: get version number automatically
workflow.__postdesc__ = """\
Brain extraction was performed on the {contrast} image using
SynthStrip [@synthstrip] and automated segmentation was
performed using SynthSeg [@synthseg1, @synthseg2] from
FreeSurfer version {fs_version}. """.format(
fs_version=FS_VERSION,
contrast=anatomical_contrast)

# Perform registrations
anat_normalization_wf = init_anat_normalization_wf(
sloppy=debug,
Expand Down Expand Up @@ -442,28 +441,17 @@ def init_t2w_preproc_wf(omp_nthreads, num_t2ws, longitudinal, sloppy,
fields=['t2_preproc', 't2w_unfatsat']),
name='outputnode')

# desc = """\
# Additionally, a total of {num_t2ws} T2-weighted (T2w) images were found within the input
# BIDS dataset.
# All of them were corrected for intensity non-uniformity (INU)
# using `N4BiasFieldCorrection` [@n4, ANTs {ants_ver}].
# """ if num_t2ws > 1 else """\
# The T2-weighted (T2w) image was corrected for intensity non-uniformity (INU)
# using `N4BiasFieldCorrection` [@n4, ANTs {ants_ver}],
# and used as an anatomical reference throughout the workflow.
# """
# workflow.__desc__ = desc.format(
# num_anats=num_t2ws,
# ants_ver=BrainExtraction().version or '<ver>'
# )

# Ensure there is 1 and only 1 anatomical reference
# Ensure there is 1 and only 1 T2w reference
anat_reference_wf = init_anat_template_wf(longitudinal=longitudinal,
omp_nthreads=omp_nthreads,
num_images=num_t2ws,
sloppy=sloppy,
anatomical_contrast="T2w")

# ^ this also provides some boilerplate.
workflow.__postdesc__ = """\
The additional T2w reference image was registered to the T1w-ACPC reference
image using an affine transformation in antsRegistration.
"""
# Skull strip the anatomical reference
synthstrip_anat_wf = init_synthstrip_wf(
do_padding=True,
Expand All @@ -474,7 +462,7 @@ def init_t2w_preproc_wf(omp_nthreads, num_t2ws, longitudinal, sloppy,
# Perform registrations
settings = pkgr("qsiprep", "data/affine.json")
t2_brain_to_t1_brain = pe.Node(
ants.Registration(),
ants.Registration(from_file=settings),
name="t2_brain_to_t1_brain",
n_procs=omp_nthreads)

Expand Down Expand Up @@ -728,6 +716,10 @@ def init_anat_normalization_wf(sloppy, template_name, omp_nthreads,


# get a good ACPC transform
desc = """\
The anatomical reference image was reoriented into AC-PC alignment via
a 6-DOF transform extracted from a full Affine registration to the
{} template. """.format(template_name)
acpc_settings = pkgr(
"qsiprep",
"data/intramodal_ACPC.json" if not sloppy else "data/intramodal_ACPC_sloppy.json")
Expand Down Expand Up @@ -762,8 +754,11 @@ def init_anat_normalization_wf(sloppy, template_name, omp_nthreads,
])

if not do_nonlinear:
workflow.__desc__ = desc
return workflow

desc += """\
A full nonlinear registration to the template from AC-PC space was
estimated via symmetric nonlinear registration (SyN) using antsRegistration. """
rigid_acpc_resample_anat = pe.Node(
ants.ApplyTransforms(input_image_type=0,
interpolation='LanczosWindowedSinc'),
Expand Down Expand Up @@ -820,6 +815,7 @@ def init_anat_normalization_wf(sloppy, template_name, omp_nthreads,
])

if has_rois:
desc += "ROI masks of abnormal tissue were incorporated into the registration. "
rigid_acpc_resample_roi = pe.Node(
ants.ApplyTransforms(input_image_type=0,
interpolation='MultiLabel'),
Expand All @@ -834,7 +830,7 @@ def init_anat_normalization_wf(sloppy, template_name, omp_nthreads,
('roi', 'input_image')]),
])


workflow.__desc__ = desc
return workflow


Expand Down
Loading

0 comments on commit 467cd0f

Please sign in to comment.