Contusions bias cortical thickness estimates after traumatic brain injury: A TRACK-TBI study.
The 1 match
- [1] § Methods › Cortical thickness estimation ↔ antsnetct_postproc_thickness.py, lines 1–59 · score 0.53 · post processing, ANTsNetCT, maps, segmentation, Cortical thickness, ROI
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Python · 628 lines · 21 KB · no license · 1 match
- #!/usr/bin/env python3
- """Post-process ANTsNetCT cortical thickness inputs.
- This script recomputes ANTs KellyKapowski thickness from the ANTsNetCT
- segmentation and posterior probability maps. User provides the derivatives
- root, subject, and session, and the script discovers matching ANTsNetCT
- outputs beneath that location. If contusion-mask subtraction is requested,
- the user must also provide either ``--contusion-mask`` or ``--bids-dir`` so
- the mask can be found.
- Assumptions
- -----------
- The script assumes the ANTsNetCT derivative layout and filenames used by the
- official package and by this repository's submit wrappers:
- <derivatives-dir>/<antsnetct-dataset>/<sub>/<ses>/anat/
- <prefix>_dseg.nii.gz
- <prefix>_label-WM_probseg.nii.gz
- <prefix>_label-SGM_probseg.nii.gz
- <prefix>_label-CGM_probseg.nii.gz
- where ``<prefix>`` ends in ``_seg-antsnetct``. By default
- ``<antsnetct-dataset>`` is ``output_longi``.
- The ANTsNetCT labels are assumed to be:
- WM = 2, CGM = 8, SGM = 9
- Post-processing follows the legacy TRACK workflow: SGM is relabeled as WM in
- the discrete segmentation, and the WM posterior supplied to KellyKapowski is
- WM + SGM. If a contusion mask is enabled, it is binarized, resampled to the
- ANTsNetCT segmentation grid, optionally dilated there, then removed from the
- segmentation and GM/WM posteriors before KellyKapowski is run.
- """
- from __future__ import annotations
- import argparse
- import glob
- import os
- import sys
- from dataclasses import dataclass
- from textwrap import dedent
- from typing import Any, Iterable, List, Optional, Sequence, Tuple
- DEFAULT_ANTSNETCT_DATASET = "output_longi"
- DEFAULT_OUTPUT_DESC = "thicknessPostproc"
- DEFAULT_CONTUSION_OUTPUT_DESC = "thicknessPostprocNoContusion"
- DEFAULT_PREPARED_MASK_DESC = "contusionMaskPostproc"
- GM_LABEL = 8
- WM_LABEL = 2
- SGM_LABEL = 9
- DEFAULT_CONTUSION_PATTERNS = (
- "*_label-contusion*.nii.gz",
- "*_label-lesion_roi.nii.gz",
- "*_label-lesion*.nii.gz",
- )
- @dataclass(frozen=True)
- class AntsNetCtTarget:
- """File group needed to run KellyKapowski for one ANTsNetCT prefix."""
- prefix: str
- anat_dir: str
- dseg_path: str
- wm_probseg_path: str
- sgm_probseg_path: str
- cgm_probseg_path: str
- output_path: str
- contusion_output_path: str
- prepared_contusion_mask_path: str
- @property
- def required_paths(self) -> Tuple[str, str, str, str]:
- return (
- self.dseg_path,
- self.wm_probseg_path,
- self.sgm_probseg_path,
- self.cgm_probseg_path,
- )
- def normalize_bids_label(value: str, prefix: str) -> str:
- """Return a BIDS-like label with the requested prefix."""
- return value if value.startswith(prefix) else f"{prefix}{value}"
- def bool_from_int(value: int) -> bool:
- """Convert legacy 0/1 argparse values to bool."""
- return value == 1
- def positive_or_zero_int(value: str) -> int:
- """Argparse type for non-negative integer options."""
- parsed = int(value)
- if parsed < 0:
- raise argparse.ArgumentTypeError("value must be >= 0")
- return parsed
- def antsnetct_anat_dir(derivatives_dir: str, dataset: str, sub: str, ses: str) -> str:
- """Return the expected subject/session anat directory."""
- return os.path.join(derivatives_dir, dataset, sub, ses, "anat")
- def strip_nii_gz_suffix(path: str) -> str:
- """Return a filename stem while preserving ordinary dots in the prefix."""
- filename = os.path.basename(path)
- suffix = ".nii.gz"
- return filename[: -len(suffix)] if filename.endswith(suffix) else os.path.splitext(filename)[0]
- def discover_prefixes(anat_dir: str, requested_prefix: Optional[str]) -> List[str]:
- """Find ANTsNetCT filename prefixes in an anat directory.
- ``requested_prefix`` may be either a basename prefix or a full path to a
- ``*_dseg.nii.gz`` file. Discovery is otherwise based on the ANTsNetCT
- ``*_seg-antsnetct_dseg.nii.gz`` suffix rather than a project-specific
- acquisition label.
- """
- if requested_prefix is not None:
- prefix = strip_nii_gz_suffix(requested_prefix)
- if prefix.endswith("_dseg"):
- prefix = prefix[: -len("_dseg")]
- return [prefix]
- pattern = os.path.join(anat_dir, "*_seg-antsnetct_dseg.nii.gz")
- prefixes: List[str] = []
- for dseg_path in sorted(glob.glob(pattern)):
- filename = os.path.basename(dseg_path)
- prefixes.append(filename[: -len("_dseg.nii.gz")])
- return deduplicate(prefixes)
- def deduplicate(values: Iterable[str]) -> List[str]:
- """Return values in their first-seen order with duplicates removed."""
- seen = set()
- unique: List[str] = []
- for value in values:
- if value not in seen:
- seen.add(value)
- unique.append(value)
- return unique
- def target_for_prefix(
- anat_dir: str,
- prefix: str,
- output_desc: str,
- contusion_output_desc: str,
- prepared_mask_desc: str,
- ) -> AntsNetCtTarget:
- """Build all file paths associated with one ANTsNetCT prefix."""
- return AntsNetCtTarget(
- prefix=prefix,
- anat_dir=anat_dir,
- dseg_path=os.path.join(anat_dir, f"{prefix}_dseg.nii.gz"),
- wm_probseg_path=os.path.join(anat_dir, f"{prefix}_label-WM_probseg.nii.gz"),
- sgm_probseg_path=os.path.join(anat_dir, f"{prefix}_label-SGM_probseg.nii.gz"),
- cgm_probseg_path=os.path.join(anat_dir, f"{prefix}_label-CGM_probseg.nii.gz"),
- output_path=os.path.join(anat_dir, f"{prefix}_desc-{output_desc}.nii.gz"),
- contusion_output_path=os.path.join(anat_dir, f"{prefix}_desc-{contusion_output_desc}.nii.gz"),
- prepared_contusion_mask_path=os.path.join(anat_dir, f"{prefix}_desc-{prepared_mask_desc}_mask.nii.gz"),
- )
- def missing_required_paths(target: AntsNetCtTarget) -> List[str]:
- """Return required ANTsNetCT inputs that are absent on disk."""
- return [path for path in target.required_paths if not os.path.exists(path)]
- def discover_contusion_masks(
- bids_dir: str,
- sub: str,
- ses: str,
- patterns: Sequence[str],
- ) -> List[str]:
- """Find candidate BIDS-space contusion masks for a subject/session."""
- anat_dir = os.path.join(bids_dir, sub, ses, "anat")
- matches: List[str] = []
- for pattern in patterns:
- matches.extend(sorted(glob.glob(os.path.join(anat_dir, pattern))))
- return deduplicate(matches)
- def choose_contusion_mask(
- explicit_mask: Optional[str],
- bids_dir: Optional[str],
- sub: str,
- ses: str,
- patterns: Sequence[str],
- ) -> Tuple[Optional[str], List[str]]:
- """Resolve the contusion mask path and return all discovered candidates."""
- if explicit_mask is not None:
- return explicit_mask, [explicit_mask]
- if bids_dir is None:
- return None, []
- candidates = discover_contusion_masks(bids_dir, sub, ses, patterns)
- return (candidates[0] if candidates else None), candidates
- def prepare_contusion_mask(
- ants: Any,
- mask_path: str,
- reference_image: Any,
- dilation_radius: int,
- dilation_shape: str,
- ) -> Any:
- """Load, binarize, resample, and optionally dilate a contusion mask.
- Dilation is performed after resampling so the radius is in voxels of the
- ANTsNetCT output grid. The returned mask is binary-valued on that grid.
- """
- mask = ants.threshold_image(ants.image_read(mask_path), low_thresh=0.1, inval=1, outval=0)
- mask = ants.resample_image_to_target(mask, reference_image, interp_type="nearestNeighbor")
- mask = ants.threshold_image(mask, low_thresh=0.5, inval=1, outval=0)
- if dilation_radius > 0:
- mask = ants.morphology(
- mask,
- operation="dilate",
- radius=dilation_radius,
- mtype="binary",
- value=1,
- shape=dilation_shape,
- )
- mask = ants.threshold_image(mask, low_thresh=0.5, inval=1, outval=0)
- return mask
- def subtract_mask(image: Any, mask: Optional[Any]) -> Any:
- """Remove masked voxels from an ANTs image while preserving image metadata."""
- if mask is None:
- return image
- return image - (image * mask)
- def run_kelly_kapowski(
- ants: Any,
- target: AntsNetCtTarget,
- contusion_mask: Optional[Any],
- kk_iterations: int,
- kk_r: float,
- kk_m: float,
- ) -> Any:
- """Run KellyKapowski thickness after ANTsNetCT-specific label handling."""
- kk_seg = ants.image_read(target.dseg_path)
- # KellyKapowski expects a GM label and WM label. ANTsNetCT keeps SGM as a
- # separate class, so this post-processing treats SGM as WM for thickness.
- kk_seg[kk_seg == SGM_LABEL] = WM_LABEL
- kk_seg = subtract_mask(kk_seg, contusion_mask)
- wm_posterior = ants.image_read(target.wm_probseg_path)
- sgm_posterior = ants.image_read(target.sgm_probseg_path)
- cgm_posterior = ants.image_read(target.cgm_probseg_path)
- kk_wm_posterior = subtract_mask(wm_posterior + sgm_posterior, contusion_mask)
- kk_gm_posterior = subtract_mask(cgm_posterior, contusion_mask)
- return ants.kelly_kapowski(
- s=kk_seg,
- g=kk_gm_posterior,
- w=kk_wm_posterior,
- its=kk_iterations,
- r=kk_r,
- m=kk_m,
- gm_label=GM_LABEL,
- wm_label=WM_LABEL,
- )
- def build_arg_parser() -> argparse.ArgumentParser:
- """Build the command-line interface used by ``main`` and ``--help``."""
- parser = argparse.ArgumentParser(
- description="Recompute KellyKapowski thickness from ANTsNetCT outputs.",
- formatter_class=argparse.RawDescriptionHelpFormatter,
- epilog=dedent(
- f"""\
- Examples:
- python antsnetct_postproc_thickness.py \\
- --derivatives-dir /path/to/derivatives --sub sub-001 --ses ses-2WK
- python antsnetct_postproc_thickness.py \\
- --derivatives-dir /path/to/derivatives --sub 001 --ses 2WK \\
- --bids-dir /path/to/bids --use-contusion-mask 1 \\
- --contusion-dilation-radius 2
- python antsnetct_postproc_thickness.py \\
- --derivatives-dir /path/to/derivatives --sub sub-001 --ses ses-2WK \\
- --contusion-mask /path/to/sub-001_ses-2WK_label-contusion_roi.nii.gz
- Notes:
- * Required inputs are --derivatives-dir, --sub, and --ses.
- * For contusion-mask discovery, also provide --bids-dir unless
- supplying --contusion-mask directly.
- * Default ANTsNetCT dataset: {DEFAULT_ANTSNETCT_DATASET}
- * Default primary output desc: {DEFAULT_OUTPUT_DESC}
- * --use-lesion-mask is retained as a deprecated alias for
- --use-contusion-mask to keep older submit wrappers working.
- """
- ),
- )
- parser.add_argument(
- "--derivatives-dir",
- required=True,
- help="Derivatives root that contains the ANTsNetCT dataset directory.",
- )
- parser.add_argument("--sub", required=True, help="Subject ID, e.g. sub-141048 or 141048.")
- parser.add_argument("--ses", required=True, help="Session ID, e.g. ses-2WK or 2WK.")
- parser.add_argument(
- "--antsnetct-dataset",
- default=DEFAULT_ANTSNETCT_DATASET,
- help="Dataset directory inside --derivatives-dir, usually output_longi or output_cross.",
- )
- parser.add_argument(
- "--prefix",
- help=(
- "Optional ANTsNetCT filename prefix to process. By default all "
- "*_seg-antsnetct_dseg.nii.gz prefixes in the subject/session anat "
- "directory are processed."
- ),
- )
- parser.add_argument(
- "--output-desc",
- default=DEFAULT_OUTPUT_DESC,
- help="BIDS desc value for the primary thickness output.",
- )
- parser.add_argument(
- "--contusion-output-desc",
- default=DEFAULT_CONTUSION_OUTPUT_DESC,
- help="Additional BIDS desc value written when a contusion mask is applied.",
- )
- parser.add_argument(
- "--bids-dir",
- help=(
- "BIDS root used to discover contusion masks when --contusion-mask "
- "is not provided. Required when --use-contusion-mask 1 is set "
- "without --contusion-mask."
- ),
- )
- parser.add_argument(
- "--contusion-mask",
- help="Explicit contusion/lesion mask path. Providing this enables contusion masking.",
- )
- parser.add_argument(
- "--contusion-mask-pattern",
- action="append",
- help=(
- "Glob pattern searched under <bids-dir>/<sub>/<ses>/anat. May be "
- "specified more than once. Defaults cover common contusion/lesion "
- "BIDS names."
- ),
- )
- parser.add_argument(
- "--use-contusion-mask",
- "--use-lesion-mask",
- dest="use_contusion_mask",
- type=int,
- choices=[0, 1],
- default=0,
- help="If 1, subtract a contusion mask before KellyKapowski. Legacy alias: --use-lesion-mask.",
- )
- parser.add_argument(
- "--require-contusion-mask",
- type=int,
- choices=[0, 1],
- default=0,
- help="If 1, fail when contusion masking is requested but no mask is found.",
- )
- parser.add_argument(
- "--contusion-dilation-radius",
- type=positive_or_zero_int,
- default=0,
- help=(
- "Binary morphology dilation radius in ANTsNetCT target-grid voxels. "
- "Use 0 to disable dilation."
- ),
- )
- parser.add_argument(
- "--contusion-dilation-shape",
- choices=["ball", "box", "cross", "annulus", "polygon"],
- default="ball",
- help="Structuring-element shape for contusion-mask dilation.",
- )
- parser.add_argument(
- "--write-prepared-contusion-mask",
- type=int,
- choices=[0, 1],
- default=0,
- help="If 1, save the resampled/dilated contusion mask beside the thickness output.",
- )
- parser.add_argument(
- "--overwrite",
- type=int,
- choices=[0, 1],
- default=0,
- help="If 1, overwrite existing primary post-processing outputs.",
- )
- parser.add_argument(
- "--dry-run",
- type=int,
- choices=[0, 1],
- default=0,
- help="If 1, print discovered inputs and planned outputs without loading ANTs.",
- )
- parser.add_argument(
- "--kk-iterations",
- type=positive_or_zero_int,
- default=45,
- help="KellyKapowski iterations passed as ants.kelly_kapowski(..., its=...).",
- )
- parser.add_argument(
- "--kk-r",
- type=float,
- default=0.025,
- help="KellyKapowski gradient-step parameter passed as r.",
- )
- parser.add_argument(
- "--kk-m",
- type=float,
- default=1.5,
- help="KellyKapowski smoothing/regularization parameter passed as m.",
- )
- return parser
- def parse_args(argv: Optional[Sequence[str]] = None) -> argparse.Namespace:
- """Parse CLI arguments."""
- return build_arg_parser().parse_args(argv)
- def print_target_plan(targets: Sequence[AntsNetCtTarget], contusion_mask_path: Optional[str]) -> None:
- """Print the dry-run processing plan."""
- print("Discovered ANTsNetCT targets:")
- for target in targets:
- print(f" prefix: {target.prefix}")
- print(f" dseg: {target.dseg_path}")
- print(f" WM: {target.wm_probseg_path}")
- print(f" SGM: {target.sgm_probseg_path}")
- print(f" CGM: {target.cgm_probseg_path}")
- print(f" out: {target.output_path}")
- if contusion_mask_path is not None:
- print(f" contusion out: {target.contusion_output_path}")
- print(f" prepared mask: {target.prepared_contusion_mask_path}")
- def main(argv: Optional[Sequence[str]] = None) -> int:
- """Run the ANTsNetCT post-processing workflow."""
- args = parse_args(argv)
- sub = normalize_bids_label(args.sub, "sub-")
- ses = normalize_bids_label(args.ses, "ses-")
- anat_dir = antsnetct_anat_dir(args.derivatives_dir, args.antsnetct_dataset, sub, ses)
- prefixes = discover_prefixes(anat_dir, args.prefix)
- if not prefixes:
- print(
- f"ERROR: no ANTsNetCT dseg files found in {anat_dir} "
- "(expected '*_seg-antsnetct_dseg.nii.gz').",
- file=sys.stderr,
- )
- return 1
- targets = [
- target_for_prefix(
- anat_dir=anat_dir,
- prefix=prefix,
- output_desc=args.output_desc,
- contusion_output_desc=args.contusion_output_desc,
- prepared_mask_desc=DEFAULT_PREPARED_MASK_DESC,
- )
- for prefix in prefixes
- ]
- use_contusion_mask = bool_from_int(args.use_contusion_mask) or args.contusion_mask is not None
- contusion_patterns = tuple(args.contusion_mask_pattern or DEFAULT_CONTUSION_PATTERNS)
- contusion_mask_path: Optional[str] = None
- contusion_candidates: List[str] = []
- if use_contusion_mask:
- if args.contusion_mask is None and args.bids_dir is None:
- print(
- "ERROR: --bids-dir is required to discover a contusion mask "
- "when --use-contusion-mask 1 is set without --contusion-mask.",
- file=sys.stderr,
- )
- return 1
- contusion_mask_path, contusion_candidates = choose_contusion_mask(
- explicit_mask=args.contusion_mask,
- bids_dir=args.bids_dir,
- sub=sub,
- ses=ses,
- patterns=contusion_patterns,
- )
- if args.contusion_mask is not None and not os.path.exists(args.contusion_mask):
- print(f"ERROR: explicit contusion mask does not exist: {args.contusion_mask}", file=sys.stderr)
- return 1
- if contusion_mask_path is None:
- message = (
- f"No contusion mask found for {sub} {ses}. "
- "Provide --contusion-mask or --bids-dir with matching --contusion-mask-pattern."
- )
- if bool_from_int(args.require_contusion_mask):
- print(f"ERROR: {message}", file=sys.stderr)
- return 1
- print(f"WARNING: {message} Continuing without contusion subtraction.", file=sys.stderr)
- use_contusion_mask = False
- elif len(contusion_candidates) > 1:
- print(f"WARNING: found {len(contusion_candidates)} contusion-mask candidates; using first:")
- print(f" {contusion_mask_path}")
- if bool_from_int(args.dry_run):
- print(f"Subject/session: {sub} {ses}")
- print(f"ANTsNetCT anat dir: {anat_dir}")
- if use_contusion_mask:
- print(f"Contusion mask: {contusion_mask_path}")
- print(f"Contusion dilation radius: {args.contusion_dilation_radius}")
- print(f"Contusion dilation shape: {args.contusion_dilation_shape}")
- else:
- print("Contusion mask: disabled")
- print_target_plan(targets, contusion_mask_path if use_contusion_mask else None)
- return 0
- try:
- import ants
- except ImportError as exc:
- print(
- "ERROR: could not import ants. Run this script in an ANTsPy/ANTsNetCT environment.",
- file=sys.stderr,
- )
- print(f"Import error: {exc}", file=sys.stderr)
- return 1
- processed = 0
- skipped = 0
- failures = 0
- for target in targets:
- print(f"\n[{sub} {ses}] {target.prefix}")
- if not bool_from_int(args.overwrite) and os.path.exists(target.output_path):
- print(f"Skipping existing output: {target.output_path}")
- skipped += 1
- continue
- missing = missing_required_paths(target)
- if missing:
- print(f"ERROR: missing required files for prefix {target.prefix}:", file=sys.stderr)
- for path in missing:
- print(f" {path}", file=sys.stderr)
- failures += 1
- continue
- contusion_mask = None
- if use_contusion_mask and contusion_mask_path is not None:
- print(f"Using contusion mask: {contusion_mask_path}")
- print(
- "Preparing contusion mask "
- f"(dilation radius={args.contusion_dilation_radius}, shape={args.contusion_dilation_shape})"
- )
- reference = ants.image_read(target.dseg_path)
- contusion_mask = prepare_contusion_mask(
- ants=ants,
- mask_path=contusion_mask_path,
- reference_image=reference,
- dilation_radius=args.contusion_dilation_radius,
- dilation_shape=args.contusion_dilation_shape,
- )
- if bool_from_int(args.write_prepared_contusion_mask):
- ants.image_write(contusion_mask, filename=target.prepared_contusion_mask_path)
- print(f"Wrote prepared contusion mask: {target.prepared_contusion_mask_path}")
- try:
- kk = run_kelly_kapowski(
- ants=ants,
- target=target,
- contusion_mask=contusion_mask,
- kk_iterations=args.kk_iterations,
- kk_r=args.kk_r,
- kk_m=args.kk_m,
- )
- ants.image_write(kk, filename=target.output_path)
- print(f"Wrote primary thickness output: {target.output_path}")
- if contusion_mask is not None:
- ants.image_write(kk, filename=target.contusion_output_path)
- print(f"Wrote contusion-specific thickness output: {target.contusion_output_path}")
- processed += 1
- except Exception as exc: # noqa: BLE001 - report target-level failures in batch runs.
- failures += 1
- print(f"ERROR: failed while processing {target.prefix}: {exc}", file=sys.stderr)
- print(f"\nSummary: processed={processed}, skipped={skipped}, failures={failures}")
- return 1 if failures else 0
- if __name__ == "__main__":
- raise SystemExit(main())
antsnetct_postproc_thickness.py at commit 464b866, no license · at the source
Overview
- University of Pennsylvania, Department of Neurology, Philadelphia, PA, United States
- University of Pennsylvania, Department of Biostatistics, Epidemiology, and Informatics, Philadelphia, PA, United States
- Penn Statistics in Imaging and Visualization Center, Department of Biostatistics, Epidemiology, and Informatics, University of Pennsylvania, Philadelphia, PA, United States
- Center For AI And Data Science For Integrated Diagnostics, United States
- University of Pennsylvania, Department of Radiology, Philadelphia, PA, United States
- University of Rochester, Department of Neurology, Rochester, NY, United States
Abstract
The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.
Repository
Its files are read in the Code ↔ Paper reader above, with 1 match between paragraphs and lines of code.
dbrennan44/ANTsNetCT-Cortical-Thickness-with-Contusion-Post-Processing
464b866d6252abcd2562825594b60f7dae48b1ce, 10 July 2026Availability: 1 check, the latest on 28 September 2026: the link answers
- 28 September 2026: the link answers
2 files
- antsnetct_postproc_thick
ness.py , Python, 628 lines, 1 match - README.md, Text, 11 lines
The paper's code and data availability statement is in the Data section.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 1 script, each with its path and the digest of its content;
- 1 match between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
No dataset and no data link were found in the paper.
Code and data availability statement
The paper has a code and data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:
- it points to the authors' code: dbrennan44/
ANTsNetCT-Cortical-Thick ness-with-Contusion-Post -Processing
Read it in the paper: doi.org/10.1016/j.nicl.2026.104003.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 28 September 2026: the first record
Recorded: type, language, journal, volume, pages, dates, 7 authors, 5 keywords, 13 MeSH terms, 3 funders, 39 references.
Cite
This paper
Brennan, D., Schneider, A. L., Shinohara, R. T., Diaz-Arrastia, R., Cook, P. A., Gee, J. C., & Gugger, J. J. (2026). Contusions bias cortical thickness estimates after traumatic brain injury: A TRACK-TBI study. NeuroImage. Clinical, 50, 104003. https://
BibTeX
@article{brennan2026cont
author = {Brennan, Daniel and Schneider, Andrea L.C. and Shinohara, Russell Taki and Diaz-Arrastia, Ramon and Cook, Philip A. and Gee, James C. and Gugger, James J.},
title = {{Contusions bias cortical thickness estimates after traumatic brain injury: A TRACK-TBI study}},
journal = {NeuroImage. Clinical},
year = {2026},
month = may,
volume = {50},
pages = {104003},
publisher = {Elsevier},
issn = {2213-1582},
doi = {10.1016/
url = {https://
pmid = {42114207},
pmcid = {PMC13191617}
}
RIS
TY - JOUR
AU - Brennan, Daniel
AU - Schneider, Andrea L.C.
AU - Shinohara, Russell Taki
AU - Diaz-Arrastia, Ramon
AU - Cook, Philip A.
AU - Gee, James C.
AU - Gugger, James J.
TI - Contusions bias cortical thickness estimates after traumatic brain injury: A TRACK-TBI study
T2 - NeuroImage. Clinical
J2 - Neuroimage Clin
PY - 2026
DA - 2026/
VL - 50
SP - 104003
SN - 2213-1582
PB - Elsevier
DO - 10.1016/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1016/
"type": "article-journal",
"title": "Contusions bias cortical thickness estimates after traumatic brain injury: A TRACK-TBI study",
"container-title": "NeuroImage. Clinical",
"author": [
{
"family": "Brennan",
"given": "Daniel"
},
{
"family": "Schneider",
"given": "Andrea L.C."
},
{
"family": "Shinohara",
"given": "Russell Taki"
},
{
"family": "Diaz-Arrastia",
"given": "Ramon"
},
{
"family": "Cook",
"given": "Philip A."
},
{
"family": "Gee",
"given": "James C."
},
{
"family": "Gugger",
"given": "James J."
}
],
"container-title-short":
"volume": "50",
"page": "104003",
"DOI": "10.1016/
"PMID": "42114207",
"PMCID": "PMC13191617",
"ISSN": "2213-1582",
"publisher": "Elsevier",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
5,
6
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1038/s41598-026-55397-w [code]
- Fast surface reconstruction of human brain MRI: benchmarking deep-learning based morphometry tools.Journal: Scientific reportsIn common: ANTs, structural MRI / diffusion, 2 references
- [2] doi:10.3389/fonc.2026.1886395 [code]
- Resources are associated with functional outcome and brain morphometry in childhood cancer survivors.Journal: Frontiers in oncologyIn common: ANTs, structural MRI / diffusion, 2 references
- [3] doi:10.1038/s41398-026-04143-x [code]
- Neighborhood opportunity, white matter, and cognition in a large pediatric neuroimaging study.Journal: Translational psychiatryIn common: ANTs, structural MRI / diffusion, 2 references
- [4] doi:10.1162/imag.a.1366 [code]
- MICAFlow: Fast and robust MRI preprocessing bridging research neuroimaging and clinical practice.Journal: Imaging neuroscience (Cambridge, Mass.)In common: ANTs, structural MRI / diffusion, 1 reference
- [5] doi:10.1038/s41598-026-56778-x [code]
- Chiari malformation type 1 is associated with a smaller fourth ventricle volume - a multi-cohort replication study.Journal: Scientific reportsIn common: ANTs, structural MRI / diffusion, 1 reference
- [6] doi:10.1038/s41586-026-10631-3 [code]
- A prognostic human brain network for diffuse midline glioma.Journal: NatureIn common: ANTs, 1 reference
- [7] doi:10.1002/epi.70296 [code]
- Fully automated three-dimensional deep learning-based magnetic resonance imaging segmentation of brain cavities in epilepsy surgery.Journal: EpilepsiaIn common: ANTs, structural MRI / diffusion, 1 reference
- [8] doi:10.1162/imag.a.1352 [code]
- Brain-age in ultra-low-field MRI: How well does it work?Journal: Imaging neuroscience (Cambridge, Mass.)In common: ANTs, structural MRI / diffusion, 1 reference
- [9] doi:10.3389/fnins.2026.1843319 [code]
- Humanized APOE mouse brain volume increases over age irrespective of sex and APOE genotype: implications for translational validity to the human.Journal: Frontiers in neuroscienceIn common: ANTs, structural MRI / diffusion, 1 reference
- [10] doi:10.1073/pnas.2604111123 [code]
- Multiscale characterization of the human claustrum from histology to MRI.Journal: Proceedings of the National Academy of Sciences of the United States of AmericaIn common: ANTs, structural MRI / diffusion, 1 reference
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 1 script, and 1 match between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:8d905422a58464e2…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
