Skip to content
Draft
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
6 changes: 3 additions & 3 deletions HypVINN/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Hypothalamic subfields segmentation pipeline

### Requirements
* Same as FastSurfer.
* If the T1w and T2w images are available and not co-registered, FreeSurfer should be sourced to run the registration code, and the mri_coreg and mri_vol2vol binaries should also be available.
* If the T1w and T2w images are available and not co-registered, HypVINN can register the T2w image to the T1w reference internally.

### Model weights
* EUDAT (FZ Jülich) data repository: https://b2share.fz-juelich.de/records/2af6da63d5c1414b832c1f606bbd068a
Expand All @@ -30,7 +30,7 @@ Note: These weights (version 1.1) are retrained compared to paper ([version 1.0]
* `--t2 </dir/T2**.nii.gz>` : T2 image path
* `--seg_log` : Path to file in which run logs will be saved. If not set logs will be stored in `/sd/sid/scripts/hypvinn_seg.log`
### Image processing options
* `--reg_mode` : Ignored, if no T2 image is passed. Specifies the registration method used to register T1 and T2 images. Options are 'coreg' (default) for mri_coreg, 'robust' for mri_robust_register, and 'none' to skip registration (this requires T1 and T2 are externally co-registered).
* `--reg_mode` : Ignored, if no T2 image is passed. Specifies the registration method used to register T1 and T2 images. Options are 'coreg' (default) for `neuroreg.coreg` and 'none' to skip registration (this requires T1 and T2 are externally co-registered).
* `--qc_snap`: Activate the creation of QC snapshots of the predicted HypVINN segmentation in `/sd/sid/qc_snapshots`. The created QC snapshots are created to simplify the visual quality control process.
### FastSurfer Technical parameters (see FastSurfer documentation)
* `--device`
Expand Down Expand Up @@ -104,7 +104,7 @@ Note: These weights (version 1.1) are retrained compared to paper ([version 1.0]
|--hypothalamus.HypVINN.nii.gz(Hypothalamus Segmentation)
|-- hypothalamus_mask.HypVINN.nii.gz (Hypothalamus Segmentation Mask)
|-- transforms
|-- t2tot1.lta (FreeSurfer registration file, only available if registration is performed)
|-- t2tot1.lta (T2-to-T1 registration transform, only available if registration is performed)
|-- qc_snapshots : QC outputs (optional)
|-- hypothalamus.HypVINN_qc_screenshoot.png (Coronal quality control image)
|-- stats : Statistics outputs
Expand Down
14 changes: 7 additions & 7 deletions HypVINN/run_prediction.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,11 @@ def option_parse() -> argparse.ArgumentParser:
"--reg_mode",
type=str,
default="coreg",
choices=["none", "coreg", "robust"],
help="Freesurfer Registration type to run. coreg: mri_coreg, "
"robust : mri_robust_register, none: entirely deactivates "
"registration of T2 to T1, if both images are passed, "
"images need to be register properly externally.",
choices=["none", "coreg"],
help="Registration type to run for T2-to-T1 alignment when both images "
"are passed. coreg: neuroreg.coreg, none: entirely deactivates "
"registration of T2 to T1, so images need to be registered "
"properly externally.",
)

parser.add_argument(
Expand Down Expand Up @@ -156,7 +156,7 @@ def main(
hypo_maskfile: str = HYPVINN_MASK_NAME,
qc_snapshots: bool = False,
threads: int | None = None,
reg_mode: Literal["coreg", "robust", "none"] = "coreg",
reg_mode: Literal["coreg", "none"] = "coreg",
batch_size: int = 1,
async_io: bool = False,
device: str = "auto",
Expand Down Expand Up @@ -195,7 +195,7 @@ def main(
Whether to create QC snapshots.
threads : int, optional
If not None, updates the FastSurfer global setting in `FastSurfer.utils.parallel`.
reg_mode : "coreg", "robust", "none", default="coreg"
reg_mode : "coreg", "none", default="coreg"
The registration mode to use.
batch_size : int, default=1
The batch size to use.
Expand Down
2 changes: 1 addition & 1 deletion HypVINN/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ class ViewOperationDefinition(TypedDict):
ViewOperations = dict[Plane, ViewOperationDefinition | None]
ModalityMode = Literal["t1", "t2", "t1t2"]
ModalityDict = dict[Literal["t1", "t2"], ndarray]
RegistrationMode = Literal["robust", "coreg", "none"]
RegistrationMode = Literal["coreg", "none"]
57 changes: 15 additions & 42 deletions HypVINN/utils/preproc.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def t1_to_t2_registration(
threads: int = -1,
) -> Path:
"""
Register T1 to T2 images using either mri_coreg or mri_robust_register.
Register the T2 image to the T1 reference using neuroreg.

Parameters
----------
Expand All @@ -49,7 +49,7 @@ def t1_to_t2_registration(
lta_path : Path
The path to the lta transform.
registration_type : RegistrationMode, default="coreg"
The type of registration to be used. It can be either "coreg" or "robust".
The type of registration to be used. It can be either "coreg" or "none".
threads : int, default=-1
The number of threads to be used. If it is less than or equal to 0, the number
of threads will be automatically determined.
Expand All @@ -62,49 +62,21 @@ def t1_to_t2_registration(
Raises
------
RuntimeError
If mri_coreg, mri_vol2vol, or mri_robust_register fails to run or if they cannot
be found.
If the requested neuroreg registration backend fails.
"""
import shutil

from FastSurferCNN.utils.parallel import get_num_threads
from FastSurferCNN.utils.run_tools import Popen

if threads <= 0:
threads = get_num_threads()

def from_freesurfer_home(fs_binary: str) -> str:
if not os.environ.get("FREESURFER_HOME", ""):
raise RuntimeError(
f"Could not find {fs_binary}, source FreeSurfer or set the FREESURFER_HOME environment variable"
)
return os.environ["FREESURFER_HOME"] + "/bin/" + fs_binary

def run_fs_binary(fs_binary: str, args: list[str]) -> int:
fs_binary = shutil.which(fs_binary) or from_freesurfer_home(fs_binary)
args = [fs_binary] + list(map(str, args))
LOGGER.info("Running " + " ".join(args))
retval = Popen(args).finish()
if retval.retcode != 0:
LOGGER.error(f"{fs_binary} failed with error code {retval.retcode}.")
raise RuntimeError(f"{fs_binary} failed")

LOGGER.info(f"{fs_binary} finished in {retval.runtime}!")
from neuroreg import coreg

if registration_type == "coreg":
run_fs_binary(
"mri_coreg",
["--mov", t2_path, "--targ", t1_path, "--reg", lta_path, "--threads", str(threads)],
)
run_fs_binary(
"mri_vol2vol",
["--mov", t2_path, "--targ", t1_path, "--reg", lta_path, "--o", output_path, "--cubic", "--keep-precision"],
LOGGER.info("Running neuroreg.coreg for T2-to-T1 registration.")
coreg(
str(t2_path),
str(t1_path),
lta_name=str(lta_path),
mapped_name=str(output_path),
keep_dtype=True,
)
else:
run_fs_binary(
"mri_robust_register",
["--mov", t2_path, "--dst", t1_path, "--lta", lta_path, "--mapmov", output_path, "--cost", "NMI"],
)
raise ValueError(f"Unknown registration type: {registration_type}")

return output_path

Expand All @@ -125,7 +97,8 @@ def hypvinn_preproc(
mode : ModalityMode
The mode for HypVINN. It should be "t1t2".
reg_mode : RegistrationMode
The registration mode. If it is not "none", the function will register T1 to T2 images.
The registration mode. If it is not "none", the function will register the
T2 image to the T1 reference.
t1_path : Path
The path to the T1 image.
t2_path : Path
Expand Down Expand Up @@ -162,7 +135,7 @@ def hypvinn_preproc(
f"T2 image will be interpolated to the resolution of the T1 image."
)

LOGGER.info("Registering T1 to T2 ...")
LOGGER.info("Registering T2 to T1 ...")
t1_to_t2_registration(
t1_path=t1_path,
t2_path=t2_path,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ dependencies = [
'matplotlib>=3.7.1',
'meshpy>=2025.1.1', # needed for FastSurfer-CC
'monai>=1.4.0', # needed for FastSurfer-CC
'neuroreg>=0.6.2', # needed for registration / etiv
'neuroreg>=0.6.3', # needed for registration / etiv
'nibabel>=5.4.0', # needed to fix a bug in nibabel
'numpy>=1.25',
'packaging',
Expand Down
3 changes: 2 additions & 1 deletion recon_surf/long_prepare_template.sh
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ fi
# check that SUBJECTS_DIR exists
check_create_subjects_dir_properties "$SUBJECTS_DIR"

auto_detect_fs_license "the longitudinal template preparation" || exit $?

################################## SETUP and LOGFILE ##############################


Expand Down Expand Up @@ -456,4 +458,3 @@ do
RunIt "$cmd" "$LF"
done


2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ multipledispatch==1.0.0
narwhals==2.21.0
networkx==3.6.1
neurolit==0.6.1
neuroreg==0.6.2
neuroreg==0.6.3
nibabel==5.4.2
numpy==2.4.4
packaging==26.2
Expand Down
21 changes: 9 additions & 12 deletions run_fastsurfer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -239,13 +239,13 @@ SEGMENTATION PIPELINE:
--t2 <T2_input> *Optional* T2 full head input (must be externally biasfield
corrected when called with --no_biasfield). Requires an
ABSOLUTE Path!
--reg_mode <none|coreg|robust>
--reg_mode <none|coreg>
Ignored, if no T2 image is passed.
Specifies the registration method used to register T1
and T2 images. Options are 'coreg' (default) for
mri_coreg, 'robust' for mri_robust_register, and 'none'
to skip registration (this requires T1 and T2 are
externally co-registered).
Specifies the registration method used to register T1
and T2 images. Options are 'coreg' (default) for
neuroreg.coreg and 'none' to skip registration
(this requires T1 and T2 are externally
co-registered).
--qc_snap Create QC snapshots in \$SUBJECTS_DIR/\$sid/qc_snapshots
to simplify the QC process.

Expand Down Expand Up @@ -515,8 +515,8 @@ case $key in
--hypo_statsfile) hypo_statsfile="$1" ; shift ;;
--reg_mode)
mode=$(echo "$1" | tr "[:upper:]" "[:lower:]")
if [[ "$mode" =~ ^(none|coreg|robust)$ ]] ; then hypvinn_regmode="$mode"
else echo "Invalid --reg_mode option, must be 'none', 'coreg' or 'robust'." ; exit 1
if [[ "$mode" =~ ^(none|coreg)$ ]] ; then hypvinn_regmode="$mode"
else echo "Invalid --reg_mode option, must be 'none' or 'coreg'." ; exit 1
fi
shift # past value
;;
Expand Down Expand Up @@ -844,9 +844,6 @@ if [[ "$run_seg_pipeline" == "true" ]] ; then
if [[ "$run_biasfield" == "true" ]] && [[ "$run_talairach_registration" == "true" ]] ; then
what_needs_license+=" and the talairach-registration in the segmentation pipeline"
fi
if [[ -n "$t2" ]] && [[ "$hypvinn_regmode" != "none" ]] ; then
what_needs_license+=" and the T1-T2 registration in the segmentation pipeline"
fi
fi
if [[ -n "$what_needs_license" ]]
then
Expand Down Expand Up @@ -1402,7 +1399,7 @@ then
if [[ "$run_hypvinn_module" == "true" ]]
then
echo "MODULE: HypVINN hypothalamus segmentation" >> "$exec_time_log"
# currently, the order of the T2 preprocessing only is registration to T1w
# currently, the T2 preprocessing step in HypVINN is registration to T1w
cmd=($python "$hypvinndir/run_prediction.py" --sd "${sd}" --sid "${subject}" --reg_mode "$hypvinn_regmode"
"${hypvinn_flags[@]}" --threads "$threads_seg" --async_io --batch_size "$batch_size" --seg_log "$seg_log"
--device "$device" --viewagg_device "$viewagg" --t1)
Expand Down
Loading