diff --git a/hippunfold/config/snakebids.yml b/hippunfold/config/snakebids.yml index 9d458635..515fb7b7 100644 --- a/hippunfold/config/snakebids.yml +++ b/hippunfold/config/snakebids.yml @@ -141,7 +141,40 @@ parse_args: - segT1w - segT2w - cropseg - + + + --template: + choices: + - 'CITI168' + - 'dHCP' + - 'MBMv2' + - 'MBMv3' + - 'CIVM' + default: 'CITI168' + help: 'Set the template to use for registration to coronal oblique (and optionally for template-based segmentation if --use-template-seg is enabled). CITI168 is for adult human data, dHCP is for neonatal human data, MBMv2 is for ex vivo marmoset data, MBMv3 is for in vivo marmoset data, and CIVM is for in vivo macaque data. (default: %(default)s)' + + + + + --inject_template: + choices: + - 'upenn' + - 'MBMv2' + - 'MBMv3' + - 'CIVM' + default: 'upenn' + help: 'Set the template to use for shape injection. (default: %(default)s)' + + --use_template_seg: + help: 'Use template-based segmentation for hippocampal tissue *instead of* nnUnet and shape injection. This is only to be used if nnUnet models are not trained for the data you are using, e.g. for non-human primate data with the MBMv2 (ex vivo marmoset), MBMv3 (in vivomarmoset), or CIVM (in vivo macaque) template. (default: %(default)s)' + default: False + action: 'store_true' + + --template_seg_smoothing_factor: + help: 'Scales the default smoothing sigma for gradient and warp in greedy registration for template-based segmentation. Using a value higher than 1 will use result in a smoother warp. (default: %(default)s)' + default: 2.0 + + --derivatives: help: 'Path to the derivatives folder (e.g. for finding manual segs) (default: %(default)s) ' default: False @@ -178,13 +211,7 @@ parse_args: default: False action: 'store_true' - --template: - choices: - - 'CITI168' - - 'dHCP' - default: 'CITI168' - help: 'Set the template to use for registration to coronal oblique. (default: %(default)s)' - + --t1_reg_template: help: 'Use T1w to register to template space, instead of the segmentation modality. Note: this was the default behavior prior to v1.0.0. (default: %(default)s)' default: false @@ -354,6 +381,33 @@ template_files: crop_ref: tpl-dHCP_cohort-1_res-1_space-corobl_hemi-{hemi}_T2w.nii.gz crop_refT1w: tpl-dHCP_cohort-1_res-1_space-corobl_hemi-{hemi}_T1w.nii.gz Mask_crop: tpl-dHCP_cohort-1_res-1_space-corobl_hemi-{hemi}_desc-hipp_mask.nii.gz + MBMv2: + T1w: MBMv2/Template_sym_MTR_80um.nii.gz + T2w: MBMv2/Template_sym_T2_80um.nii.gz + xfm_corobl: MBMv2/tpl-MBMv2_from-native_to-corobl_type-itk_affine.txt + crop_ref: MBMv2/tpl-MBMv2_hemi-{hemi}_space-corobl_{modality}.nii.gz + Mask_crop: MBMv2/tpl-MBMv2_hemi-{hemi}_space-corobl_desc-hipp_mask.nii.gz + dseg: MBMv2/tpl-MBMv2_hemi-R_space-corobl_desc-tissuemanual_dseg.nii.gz + coords: MBMv2/tpl-MBMv2_dir-{dir}_hemi-R_space-corobl_label-{autotop}_desc-laplace_coords.nii.gz + MBMv3: + T1w: MBMv3/tpl-MBMv3_T1w.nii.gz + T2w: MBMv3/tpl-MBMv3_T2w.nii.gz + xfm_corobl: MBMv3/tpl-MBMv3_from-native_to-corobl_type-itk_affine.txt + crop_ref: MBMv3/tpl-MBMv3_hemi-{hemi}_space-corobl_{modality}.nii.gz + Mask_crop: MBMv3/tpl-MBMv3_hemi-{hemi}_space-corobl_desc-hipp_mask.nii.gz + dseg: MBMv3/tpl-MBMv3_hemi-R_space-corobl_desc-tissue_dseg.nii.gz + coords: MBMv3/tpl-MBMv3_dir-{dir}_hemi-R_space-corobl_label-{autotop}_desc-laplace_coords.nii.gz + CIVM: + T1w: CIVM/tpl-CIVM_T1w.nii.gz + xfm_corobl: CIVM/tpl-CIVM_from-native_to-corobl_type-itk_affine.txt + crop_ref: CIVM/tpl-CIVM_hemi-{hemi}_space-corobl_{modality}.nii.gz + Mask_crop: CIVM/tpl-CIVM_hemi-{hemi}_space-corobl_desc-hipp_mask.nii.gz + dseg: CIVM/tpl-CIVM_hemi-R_space-corobl_desc-tissue_dseg.nii.gz + coords: CIVM/tpl-CIVM_dir-{dir}_hemi-R_space-corobl_label-{autotop}_desc-laplace_coords.nii.gz + upenn: + T1w: upenn/tpl-upenn_desc-hipptissue_dseg.nii.gz + dseg: upenn/tpl-upenn_desc-hipptissue_dseg.nii.gz + coords: upenn/tpl-upenn_dir-{dir}_label-{autotop}_coords.nii.gz atlas_files: multihist7: @@ -572,3 +626,5 @@ t1_reg_template: False generate_myelin_map: False no_unfolded_reg: False root: results +use_template_seg: False +template_seg_smoothing_factor: 2 diff --git a/hippunfold/workflow/Snakefile b/hippunfold/workflow/Snakefile index 84859a31..2b939bb8 100644 --- a/hippunfold/workflow/Snakefile +++ b/hippunfold/workflow/Snakefile @@ -59,7 +59,7 @@ elif "T1w" in config["modality"]: # only generate hipp surface if skipping template injection # i.e. drop dentate -if config["skip_inject_template_labels"]: +if config["skip_inject_template_labels"]: # TODO do we need this? config["autotop_labels"] = ["hipp"] @@ -144,9 +144,6 @@ include: "rules/autotop.smk" include: "rules/warps.smk" -include: "rules/shape_inject.smk" - - include: "rules/gifti.smk" @@ -162,6 +159,26 @@ include: "rules/qc.smk" include: "rules/myelin_map.smk" +if config["use_template_seg"]: + if ( + "dseg" in config["template_files"][config["template"]] + and "coords" in config["template_files"][config["template"]] + ): + + include: "rules/templateseg.smk" + + else: + print( + "use_template_seg is not possible, template dseg or coords do not exist for the chosen template" + ) + + include: "rules/shape_inject.smk" + +else: + + include: "rules/shape_inject.smk" + + rule all: input: get_final_output(), diff --git a/hippunfold/workflow/rules/common.smk b/hippunfold/workflow/rules/common.smk index f2acdaf2..297b9486 100644 --- a/hippunfold/workflow/rules/common.smk +++ b/hippunfold/workflow/rules/common.smk @@ -293,20 +293,21 @@ def get_final_qc(): ) ) if (config["modality"] == "T1w") or (config["modality"] == "T2w"): - qc.extend( - expand( - bids( - root=root, - datatype="qc", - desc="unetf3d", - suffix="dice.tsv", - hemi="{hemi}", - **config["subj_wildcards"], - ), - hemi=config["hemi"], - allow_missing=True, + if not config["use_template_seg"]: + qc.extend( + expand( + bids( + root=root, + datatype="qc", + desc="unetf3d", + suffix="dice.tsv", + hemi="{hemi}", + **config["subj_wildcards"], + ), + hemi=config["hemi"], + allow_missing=True, + ) ) - ) return qc diff --git a/hippunfold/workflow/rules/templateseg.smk b/hippunfold/workflow/rules/templateseg.smk new file mode 100644 index 00000000..db255df6 --- /dev/null +++ b/hippunfold/workflow/rules/templateseg.smk @@ -0,0 +1,277 @@ +def get_smoothing_opt(wildcards): + """sets the smoothness of the greedy template shape injection deformation""" + + gradient_sigma = 1.732 * float(config["template_seg_smoothing_factor"]) + warp_sigma = 0.7071 * float(config["template_seg_smoothing_factor"]) + + return f"-s {gradient_sigma}vox {warp_sigma}vox" + + +rule template_reg: + input: + fixed_img=bids( + root=work, + datatype="anat", + **config["subj_wildcards"], + suffix="{modality}.nii.gz".format( + modality=get_modality_suffix(config["modality"]) + ), + space="corobl", + desc="preproc", + hemi="{hemi}" + ), + template_dir=Path(download_dir) / "template" / config["template"], + params: + moving_img=lambda wildcards, input: Path(input.template_dir) + / config["template_files"][config["template"]][ + get_modality_suffix(config["modality"]) + ], + xfm_corobl=lambda wildcards, input: Path(input.template_dir) + / config["template_files"][config["template"]]["xfm_corobl"], + general_opts="-d 3 -m NCC 2x2x2", + smoothing_opts=get_smoothing_opt, + iteration_opts="-n 100x50x10", #default -n 100x100 + output: + warp=bids( + root=work, + **config["subj_wildcards"], + suffix="xfm.nii.gz", + datatype="warps", + desc="greedytemplatereg", + from_="template", + to="subject", + space="corobl", + hemi="{hemi,Lflip|R}" + ), + group: + "subj" + container: + config["singularity"]["autotop"] + threads: 8 + shell: + "greedy -threads {threads} {params.general_opts} " + " {params.smoothing_opts} {params.iteration_opts} " + " -i {input.fixed_img} {params.moving_img} -it {params.xfm_corobl} -o {output.warp}" + + +rule warp_template_dseg: + input: + ref=bids( + root=work, + datatype="anat", + **config["subj_wildcards"], + suffix=f"{config['modality']}.nii.gz", + space="corobl", + desc="preproc", + hemi="{hemi}", + ), + warp=bids( + root=work, + **config["subj_wildcards"], + suffix="xfm.nii.gz", + datatype="warps", + desc="greedytemplatereg", + from_="template", + to="subject", + space="corobl", + hemi="{hemi}" + ), + template_dir=Path(download_dir) / "template" / config["template"], + params: + template_dseg=lambda wildcards, input: Path(input.template_dir) + / config["template_files"][config["template"]]["dseg"], + interp_opt="-ri LABEL 0.2vox", + output: + inject_seg=bids( + root=work, + datatype="anat", + **config["subj_wildcards"], + suffix="dseg.nii.gz", + desc="postproc", + space="corobl", + hemi="{hemi,Lflip|R}" + ), + group: + "subj" + container: + config["singularity"]["autotop"] + threads: 8 + shell: + "greedy -d 3 -threads {threads} {params.interp_opt} -rf {input.ref} -rm {params.template_dseg} {output.inject_seg} -r {input.warp}" + + +rule warp_template_coords: + input: + template_dir=Path(download_dir) / "template" / config["template"], + ref=bids( + root=work, + datatype="anat", + **config["subj_wildcards"], + suffix=f"{config['modality']}.nii.gz", + space="corobl", + desc="preproc", + hemi="{hemi}", + ), + warp=bids( + root=work, + **config["subj_wildcards"], + suffix="xfm.nii.gz", + datatype="warps", + desc="greedytemplatereg", + from_="template", + to="subject", + space="corobl", + hemi="{hemi}" + ), + params: + interp_opt="-ri NN", + template_coords=lambda wildcards, input: Path(input.template_dir) + / config["template_files"][config["template"]]["coords"], + output: + init_coords=bids( + root=work, + datatype="coords", + **config["subj_wildcards"], + dir="{dir}", + label="{autotop}", + suffix="coords.nii.gz", + desc="init", + space="corobl", + hemi="{hemi,R|Lflip}" + ), + group: + "subj" + container: + config["singularity"]["autotop"] + threads: 8 + shell: + "greedy -d 3 -threads {threads} {params.interp_opt} -rf {input.ref} -rm {params.template_coords} {output.init_coords} -r {input.warp}" + + +rule warp_template_anat: + input: + ref=bids( + root=work, + datatype="anat", + **config["subj_wildcards"], + suffix=f"{config['modality']}.nii.gz", + space="corobl", + desc="preproc", + hemi="{hemi}", + ), + warp=bids( + root=work, + **config["subj_wildcards"], + suffix="xfm.nii.gz", + datatype="warps", + desc="greedytemplatereg", + from_="template", + to="subject", + space="corobl", + hemi="{hemi}" + ), + template_dir=Path(download_dir) / "template" / config["template"], + params: + template_anat=lambda wildcards, input: Path(input.template_dir) + / config["template_files"][config["template"]][config["modality"]], + xfm_corobl=lambda wildcards, input: Path(input.template_dir) + / config["template_files"][config["template"]]["xfm_corobl"], + output: + warped=bids( + root=work, + datatype="anat", + **config["subj_wildcards"], + suffix=f"{config['modality']}.nii.gz", + desc="warpedtemplate", + space="corobl", + hemi="{hemi,Lflip|R}", + ), + group: + "subj" + container: + config["singularity"]["autotop"] + threads: 8 + shell: + "greedy -d 3 -threads {threads} -rf {input.ref} -rm {params.template_anat} {output.warped} -r {input.warp} {params.xfm_corobl}" + + +rule unflip_template_dseg: + input: + nii=bids( + root=work, + datatype="anat", + suffix="dseg.nii.gz", + desc="postproc", + space="corobl", + hemi="{hemi}flip", + **config["subj_wildcards"] + ), + unflip_ref=bids( + root=work, + datatype="anat", + **config["subj_wildcards"], + suffix=f"{config['modality']}.nii.gz", + space="corobl", + desc="preproc", + hemi="{hemi}", + ), + output: + nii=bids( + root=work, + datatype="anat", + suffix="dseg.nii.gz", + desc="postproc", + space="corobl", + hemi="{hemi,L}", + **config["subj_wildcards"] + ), + container: + config["singularity"]["autotop"] + group: + "subj" + shell: + "c3d {input.nii} -flip x -popas FLIPPED " + " {input.unflip_ref} -push FLIPPED -copy-transform -o {output.nii} " + + +rule unflip_template_coords: + input: + nii=bids( + root=work, + datatype="coords", + **config["subj_wildcards"], + dir="{dir}", + label="{autotop}", + suffix="coords.nii.gz", + desc="init", + space="corobl", + hemi="{hemi}flip" + ), + unflip_ref=bids( + root=work, + datatype="anat", + **config["subj_wildcards"], + suffix=f"{config['modality']}.nii.gz", + space="corobl", + desc="preproc", + hemi="{hemi}", + ), + output: + nii=bids( + root=work, + datatype="coords", + **config["subj_wildcards"], + dir="{dir}", + label="{autotop}", + suffix="coords.nii.gz", + desc="init", + space="corobl", + hemi="{hemi,L}" + ), + container: + config["singularity"]["autotop"] + group: + "subj" + shell: + "c3d {input.nii} -flip x -popas FLIPPED " + " {input.unflip_ref} -push FLIPPED -copy-transform -o {output.nii} "