From 1af42f77c14cdfc3b38c484e46428aded9aa20cc Mon Sep 17 00:00:00 2001 From: Ali Khan Date: Thu, 15 Feb 2024 15:42:17 -0500 Subject: [PATCH 01/15] add template-based segmentation and marm templates note: this is just a copy of the marmunfold branch --- hippunfold/config/snakebids.yml | 72 +++++- hippunfold/workflow/Snakefile | 25 +- hippunfold/workflow/rules/common.smk | 27 ++- hippunfold/workflow/rules/templateseg.smk | 277 ++++++++++++++++++++++ 4 files changed, 376 insertions(+), 25 deletions(-) create mode 100644 hippunfold/workflow/rules/templateseg.smk 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} " From 79ebe6d573e4f61888cf674030560fd78e6a0d7e Mon Sep 17 00:00:00 2001 From: Ali Khan Date: Thu, 15 Feb 2024 16:23:11 -0500 Subject: [PATCH 02/15] use downloaded template for shape-inject --- hippunfold/config/snakebids.yml | 48 +++++++++++----------- hippunfold/workflow/rules/preproc_t1.smk | 2 +- hippunfold/workflow/rules/shape_inject.smk | 23 ++++------- 3 files changed, 34 insertions(+), 39 deletions(-) diff --git a/hippunfold/config/snakebids.yml b/hippunfold/config/snakebids.yml index 515fb7b7..99366158 100644 --- a/hippunfold/config/snakebids.yml +++ b/hippunfold/config/snakebids.yml @@ -382,32 +382,32 @@ template_files: 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 + T1w: Template_sym_MTR_80um.nii.gz + T2w: Template_sym_T2_80um.nii.gz + xfm_corobl: tpl-MBMv2_from-native_to-corobl_type-itk_affine.txt + crop_ref: tpl-MBMv2_hemi-{hemi}_space-corobl_{modality}.nii.gz + Mask_crop: tpl-MBMv2_hemi-{hemi}_space-corobl_desc-hipp_mask.nii.gz + dseg: tpl-MBMv2_hemi-R_space-corobl_desc-tissuemanual_dseg.nii.gz + coords: 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 + T1w: tpl-MBMv3_T1w.nii.gz + T2w: tpl-MBMv3_T2w.nii.gz + xfm_corobl: tpl-MBMv3_from-native_to-corobl_type-itk_affine.txt + crop_ref: tpl-MBMv3_hemi-{hemi}_space-corobl_{modality}.nii.gz + Mask_crop: tpl-MBMv3_hemi-{hemi}_space-corobl_desc-hipp_mask.nii.gz + dseg: tpl-MBMv3_hemi-R_space-corobl_desc-tissue_dseg.nii.gz + coords: 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 + T1w: tpl-CIVM_T1w.nii.gz + xfm_corobl: tpl-CIVM_from-native_to-corobl_type-itk_affine.txt + crop_ref: tpl-CIVM_hemi-{hemi}_space-corobl_{modality}.nii.gz + Mask_crop: tpl-CIVM_hemi-{hemi}_space-corobl_desc-hipp_mask.nii.gz + dseg: tpl-CIVM_hemi-R_space-corobl_desc-tissue_dseg.nii.gz + coords: 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 + T1w: tpl-upenn_desc-hipptissue_dseg.nii.gz + dseg: tpl-upenn_desc-hipptissue_dseg.nii.gz + coords: tpl-upenn_dir-{dir}_label-{autotop}_coords.nii.gz atlas_files: multihist7: @@ -458,6 +458,8 @@ no_reg_template: False modality: T2w +inject_template: upenn + template: CITI168 atlas: diff --git a/hippunfold/workflow/rules/preproc_t1.smk b/hippunfold/workflow/rules/preproc_t1.smk index 96bf100f..65ffeb35 100644 --- a/hippunfold/workflow/rules/preproc_t1.smk +++ b/hippunfold/workflow/rules/preproc_t1.smk @@ -245,7 +245,7 @@ rule template_xfm_itk2ras: datatype="warps", **config["subj_wildcards"], suffix="xfm.txt", - from_="{native_modality,T1w|T2w}", + from_="{native_modality}", to="corobl", desc="affine", type_="itk" diff --git a/hippunfold/workflow/rules/shape_inject.smk b/hippunfold/workflow/rules/shape_inject.smk index 60aedbd6..d724d99d 100644 --- a/hippunfold/workflow/rules/shape_inject.smk +++ b/hippunfold/workflow/rules/shape_inject.smk @@ -88,13 +88,10 @@ rule prep_segs_for_greedy: rule import_template_shape: input: - template_seg=os.path.join( - workflow.basedir, - "..", - "resources", - "tpl-upenn", - "tpl-upenn_desc-hipptissue_dseg.nii.gz", - ), + template_dir=Path(download_dir) / "template" / config["inject_template"], + params: + template_seg=lambda wildcards, input: Path(input.template_dir) + / config["template_files"][config["inject_template"]]["dseg"], output: template_seg=bids( root=work, @@ -279,13 +276,6 @@ rule template_shape_inject: rule inject_init_laplace_coords: input: - coords=os.path.join( - workflow.basedir, - "..", - "resources", - "tpl-upenn", - "tpl-upenn_dir-{dir}_label-{autotop}_coords.nii.gz", - ), subject_seg=get_input_for_shape_inject, matrix=bids( root=work, @@ -310,7 +300,10 @@ rule inject_init_laplace_coords: space="corobl", hemi="{hemi}" ), + template_dir=Path(download_dir) / "template" / config["inject_template"], params: + coords=lambda wildcards, input: Path(input.template_dir) + / config["template_files"][config["inject_template"]]["coords"], interp_opt="-ri NN", output: init_coords=bids( @@ -340,7 +333,7 @@ rule inject_init_laplace_coords: config["singularity"]["autotop"] threads: 8 shell: - "greedy -d 3 -threads {threads} {params.interp_opt} -rf {input.subject_seg} -rm {input.coords} {output.init_coords} -r {input.warp} {input.matrix} &> {log}" + "greedy -d 3 -threads {threads} {params.interp_opt} -rf {input.subject_seg} -rm {params.coords} {output.init_coords} -r {input.warp} {input.matrix} &> {log}" rule unflip_init_coords: From e2e1aafeaaffad48935e3f37e45acbeffb7d7ace Mon Sep 17 00:00:00 2001 From: Ali Khan Date: Fri, 16 Feb 2024 11:20:30 -0500 Subject: [PATCH 03/15] fix use params instead of input --- hippunfold/workflow/rules/shape_inject.smk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hippunfold/workflow/rules/shape_inject.smk b/hippunfold/workflow/rules/shape_inject.smk index d724d99d..95a02065 100644 --- a/hippunfold/workflow/rules/shape_inject.smk +++ b/hippunfold/workflow/rules/shape_inject.smk @@ -106,7 +106,7 @@ rule import_template_shape: container: config["singularity"]["autotop"] shell: - "cp {input} {output}" + "cp {params.template_seg} {output.template_seg}" def get_image_pairs(wildcards, input): From 0ea9dd478913e93961f181a99e1edd1ae2e79a68 Mon Sep 17 00:00:00 2001 From: Ali Khan Date: Fri, 16 Feb 2024 11:37:10 -0500 Subject: [PATCH 04/15] add missing wildcard formats --- hippunfold/workflow/rules/shape_inject.smk | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hippunfold/workflow/rules/shape_inject.smk b/hippunfold/workflow/rules/shape_inject.smk index 95a02065..f895d00f 100644 --- a/hippunfold/workflow/rules/shape_inject.smk +++ b/hippunfold/workflow/rules/shape_inject.smk @@ -91,7 +91,9 @@ rule import_template_shape: template_dir=Path(download_dir) / "template" / config["inject_template"], params: template_seg=lambda wildcards, input: Path(input.template_dir) - / config["template_files"][config["inject_template"]]["dseg"], + / config["template_files"][config["inject_template"]]["dseg"].format( + **wildcards + ), output: template_seg=bids( root=work, @@ -303,7 +305,9 @@ rule inject_init_laplace_coords: template_dir=Path(download_dir) / "template" / config["inject_template"], params: coords=lambda wildcards, input: Path(input.template_dir) - / config["template_files"][config["inject_template"]]["coords"], + / config["template_files"][config["inject_template"]]["coords"].format( + **wildcards + ), interp_opt="-ri NN", output: init_coords=bids( From e21ce85d24b49fc675a0dc1a944cddc90578d13f Mon Sep 17 00:00:00 2001 From: Ali Khan Date: Fri, 16 Feb 2024 15:46:52 -0500 Subject: [PATCH 05/15] added CITI168 templateseg files (already in osf folder now) --- hippunfold/config/snakebids.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hippunfold/config/snakebids.yml b/hippunfold/config/snakebids.yml index 99366158..e98dd96d 100644 --- a/hippunfold/config/snakebids.yml +++ b/hippunfold/config/snakebids.yml @@ -374,6 +374,8 @@ template_files: crop_ref: T2w_300umCoronalOblique_hemi-{hemi}.nii.gz crop_refT1w: T1w_300umCoronalOblique_hemi-{hemi}.nii.gz Mask_crop: Mask_300umCoronalOblique_hemi-{hemi}.nii.gz + dseg: sub-CITI168_hemi-{hemi}_space-cropT1w_desc-postproc_dseg.nii.gz + coords: sub-CITI168_dir-{dir}_hemi-{hemi}_space-cropT1w_label-{autotop}_desc-laplace_coords.nii.gz dHCP: T1w: tpl-dHCP_cohort-1_res-1_T1w.nii.gz T2w: tpl-dHCP_cohort-1_res-1_T2w.nii.gz From e2990a758659ddb30ee0bea36744f622f9233240 Mon Sep 17 00:00:00 2001 From: Ali Khan Date: Fri, 16 Feb 2024 17:02:08 -0500 Subject: [PATCH 06/15] adjustments to get working with CITI168 templateseg - in CITI168 we have L and R masks.. - but will need to adjust this to get it working for data (ie Marm ex vivo) where only a single hemi exists -- will need to include some logic to decide when to register L hemi, vs when to register Lflip.. --- hippunfold/workflow/rules/templateseg.smk | 26 ++++++++++++++--------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/hippunfold/workflow/rules/templateseg.smk b/hippunfold/workflow/rules/templateseg.smk index db255df6..8074dd19 100644 --- a/hippunfold/workflow/rules/templateseg.smk +++ b/hippunfold/workflow/rules/templateseg.smk @@ -25,9 +25,11 @@ rule template_reg: moving_img=lambda wildcards, input: Path(input.template_dir) / config["template_files"][config["template"]][ get_modality_suffix(config["modality"]) - ], + ].format(**wildcards), xfm_corobl=lambda wildcards, input: Path(input.template_dir) - / config["template_files"][config["template"]]["xfm_corobl"], + / config["template_files"][config["template"]]["xfm_corobl"].format( + **wildcards + ), general_opts="-d 3 -m NCC 2x2x2", smoothing_opts=get_smoothing_opt, iteration_opts="-n 100x50x10", #default -n 100x100 @@ -41,7 +43,7 @@ rule template_reg: from_="template", to="subject", space="corobl", - hemi="{hemi,Lflip|R}" + hemi="{hemi,R|L}" ), group: "subj" @@ -79,7 +81,7 @@ rule warp_template_dseg: template_dir=Path(download_dir) / "template" / config["template"], params: template_dseg=lambda wildcards, input: Path(input.template_dir) - / config["template_files"][config["template"]]["dseg"], + / config["template_files"][config["template"]]["dseg"].format(**wildcards), interp_opt="-ri LABEL 0.2vox", output: inject_seg=bids( @@ -89,7 +91,7 @@ rule warp_template_dseg: suffix="dseg.nii.gz", desc="postproc", space="corobl", - hemi="{hemi,Lflip|R}" + hemi="{hemi,R|L}" ), group: "subj" @@ -126,7 +128,7 @@ rule warp_template_coords: params: interp_opt="-ri NN", template_coords=lambda wildcards, input: Path(input.template_dir) - / config["template_files"][config["template"]]["coords"], + / config["template_files"][config["template"]]["coords"].format(**wildcards), output: init_coords=bids( root=work, @@ -137,7 +139,7 @@ rule warp_template_coords: suffix="coords.nii.gz", desc="init", space="corobl", - hemi="{hemi,R|Lflip}" + hemi="{hemi,R|L|Lflip}" ), group: "subj" @@ -173,9 +175,13 @@ rule warp_template_anat: 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"]], + / config["template_files"][config["template"]][config["modality"]].format( + **wildcards + ), xfm_corobl=lambda wildcards, input: Path(input.template_dir) - / config["template_files"][config["template"]]["xfm_corobl"], + / config["template_files"][config["template"]]["xfm_corobl"].format( + **wildcards + ), output: warped=bids( root=work, @@ -184,7 +190,7 @@ rule warp_template_anat: suffix=f"{config['modality']}.nii.gz", desc="warpedtemplate", space="corobl", - hemi="{hemi,Lflip|R}", + hemi="{hemi,L|R}", ), group: "subj" From b89ca81e80b181dcc8e293a58c9c7f776a48127d Mon Sep 17 00:00:00 2001 From: Ali Khan Date: Mon, 19 Feb 2024 16:23:41 -0500 Subject: [PATCH 07/15] fixes to to allow flip and noflip template seg - checks config to see what template hemis are enabled, uses flipping for other hemis --- hippunfold/config/snakebids.yml | 17 +++++-- hippunfold/workflow/rules/templateseg.smk | 57 +++++++++++++++++++---- 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/hippunfold/config/snakebids.yml b/hippunfold/config/snakebids.yml index e98dd96d..5a024aed 100644 --- a/hippunfold/config/snakebids.yml +++ b/hippunfold/config/snakebids.yml @@ -366,6 +366,17 @@ singularity: xfm_identity: resources/etc/identity_xfm.txt +#templates enabled for template-based segmentation are here +template_based_segmentation: + CITI168: + hemi: + - R + - L + MBMv3: + hemi: + - R + + template_files: CITI168: T1w: T1w_head_700um.nii.gz @@ -395,10 +406,10 @@ template_files: T1w: tpl-MBMv3_T1w.nii.gz T2w: tpl-MBMv3_T2w.nii.gz xfm_corobl: tpl-MBMv3_from-native_to-corobl_type-itk_affine.txt - crop_ref: tpl-MBMv3_hemi-{hemi}_space-corobl_{modality}.nii.gz + crop_ref: tpl-MBMv3_hemi-{hemi}_space-corobl_T1w.nii.gz Mask_crop: tpl-MBMv3_hemi-{hemi}_space-corobl_desc-hipp_mask.nii.gz - dseg: tpl-MBMv3_hemi-R_space-corobl_desc-tissue_dseg.nii.gz - coords: tpl-MBMv3_dir-{dir}_hemi-R_space-corobl_label-{autotop}_desc-laplace_coords.nii.gz + dseg: tpl-MBMv3_hemi-{hemi}_space-corobl_desc-tissue_dseg.nii.gz + coords: tpl-MBMv3_dir-{dir}_hemi-{hemi}_space-corobl_label-{autotop}_desc-laplace_coords.nii.gz CIVM: T1w: tpl-CIVM_T1w.nii.gz xfm_corobl: tpl-CIVM_from-native_to-corobl_type-itk_affine.txt diff --git a/hippunfold/workflow/rules/templateseg.smk b/hippunfold/workflow/rules/templateseg.smk index 8074dd19..8620f2a7 100644 --- a/hippunfold/workflow/rules/templateseg.smk +++ b/hippunfold/workflow/rules/templateseg.smk @@ -7,6 +7,39 @@ def get_smoothing_opt(wildcards): return f"-s {gradient_sigma}vox {warp_sigma}vox" +# Template-based segmentation supports templates that have only a single hemisphere +# by mapping it to the flipped version of the other hemisphere. +# If a template has both L and R files, then we set hemi_constrained_wildcard to L|R. +# If a hemisphere is missing data, then we set it to flip that, e.g. if L missing, then use Lflip|R + +hemi_constraints = [] +if config["template"] in config["template_based_segmentation"]: + for hemi in config["hemi"]: + if hemi in config["template_based_segmentation"][config["template"]]["hemi"]: + hemi_constraints.append(hemi) + else: + hemi_constraints.append(f"{hemi}flip") + +hemi_constrained_wildcard = "{{hemi,{constraints}}}".format( + constraints="|".join(hemi_constraints) +) + + +def flipped(wildcards): + """function to map hemi in wildcards from Lflip to R, or Rflip to L, + for use in rules where e.g. the output wildcard is Lflip, but for the input, R is desired, such as + when mapping a R hemi dseg to the Lflip hemisphere of a subject.""" + + if wildcards.hemi == "L" or wildcards.hemi == "R": + return wildcards + elif wildcards.hemi == "Lflip": + wildcards.hemi = "R" + return wildcards + elif wildcards.hemi == "Rflip": + wildcards.hemi = "L" + return wildcards + + rule template_reg: input: fixed_img=bids( @@ -25,7 +58,7 @@ rule template_reg: moving_img=lambda wildcards, input: Path(input.template_dir) / config["template_files"][config["template"]][ get_modality_suffix(config["modality"]) - ].format(**wildcards), + ].format(**flipped(wildcards)), xfm_corobl=lambda wildcards, input: Path(input.template_dir) / config["template_files"][config["template"]]["xfm_corobl"].format( **wildcards @@ -43,7 +76,7 @@ rule template_reg: from_="template", to="subject", space="corobl", - hemi="{hemi,R|L}" + hemi=hemi_constrained_wildcard, ), group: "subj" @@ -81,7 +114,9 @@ rule warp_template_dseg: template_dir=Path(download_dir) / "template" / config["template"], params: template_dseg=lambda wildcards, input: Path(input.template_dir) - / config["template_files"][config["template"]]["dseg"].format(**wildcards), + / config["template_files"][config["template"]]["dseg"].format( + **flipped(wildcards) + ), interp_opt="-ri LABEL 0.2vox", output: inject_seg=bids( @@ -91,7 +126,7 @@ rule warp_template_dseg: suffix="dseg.nii.gz", desc="postproc", space="corobl", - hemi="{hemi,R|L}" + hemi=hemi_constrained_wildcard, ), group: "subj" @@ -128,7 +163,9 @@ rule warp_template_coords: params: interp_opt="-ri NN", template_coords=lambda wildcards, input: Path(input.template_dir) - / config["template_files"][config["template"]]["coords"].format(**wildcards), + / config["template_files"][config["template"]]["coords"].format( + **flipped(wildcards) + ), output: init_coords=bids( root=work, @@ -139,7 +176,7 @@ rule warp_template_coords: suffix="coords.nii.gz", desc="init", space="corobl", - hemi="{hemi,R|L|Lflip}" + hemi=hemi_constrained_wildcard, ), group: "subj" @@ -176,7 +213,7 @@ rule warp_template_anat: params: template_anat=lambda wildcards, input: Path(input.template_dir) / config["template_files"][config["template"]][config["modality"]].format( - **wildcards + **flipped(wildcards) ), xfm_corobl=lambda wildcards, input: Path(input.template_dir) / config["template_files"][config["template"]]["xfm_corobl"].format( @@ -190,7 +227,7 @@ rule warp_template_anat: suffix=f"{config['modality']}.nii.gz", desc="warpedtemplate", space="corobl", - hemi="{hemi,L|R}", + hemi=hemi_constrained_wildcard, ), group: "subj" @@ -228,7 +265,7 @@ rule unflip_template_dseg: suffix="dseg.nii.gz", desc="postproc", space="corobl", - hemi="{hemi,L}", + hemi="{hemi,L|R}", **config["subj_wildcards"] ), container: @@ -272,7 +309,7 @@ rule unflip_template_coords: suffix="coords.nii.gz", desc="init", space="corobl", - hemi="{hemi,L}" + hemi="{hemi,L|R}", ), container: config["singularity"]["autotop"] From 0950a9424bee39cb1112f9c46b1b96d266ac4773 Mon Sep 17 00:00:00 2001 From: "Jordan DeKraker - B. Bernhardt Lab" Date: Wed, 21 Feb 2024 15:38:39 -0500 Subject: [PATCH 08/15] changes work macaque local test --- .dryrun_test_all.sh | 1 + hippunfold/config/snakebids.yml | 32 ++++++++++-- hippunfold/workflow/rules/download.smk | 24 +++++++-- hippunfold/workflow/rules/preproc_t1.smk | 2 +- hippunfold/workflow/rules/templateseg.smk | 57 +++++++++++++++++---- hippunfold/workflow/scripts/create_warps.py | 4 +- 6 files changed, 99 insertions(+), 21 deletions(-) diff --git a/.dryrun_test_all.sh b/.dryrun_test_all.sh index 9a93cd68..74a3c865 100755 --- a/.dryrun_test_all.sh +++ b/.dryrun_test_all.sh @@ -14,3 +14,4 @@ hippunfold - test_out participant -np --modality cropseg --path_cropseg test_dat hippunfold - test_out participant -np --modality cropseg --path_cropseg test_data/data_cropseg_1hemi/sub-{subject}_hemi-{hemi}_dseg.nii.gz --hemi L hippunfold test_data/bids_singleT2w test_out participant -np --modality T2w --t1_reg_template hippunfold test_data/bids_singleT2w test_out participant -np --modality T2w --output_space T1w +hippunfold test_data/bids_T1w test_out participant -np --modality T1w --use-template-seg diff --git a/hippunfold/config/snakebids.yml b/hippunfold/config/snakebids.yml index e98dd96d..c246ff54 100644 --- a/hippunfold/config/snakebids.yml +++ b/hippunfold/config/snakebids.yml @@ -366,6 +366,29 @@ singularity: xfm_identity: resources/etc/identity_xfm.txt +#templates enabled for template-based segmentation are here +template_based_segmentation: + CITI168: + hemi: + - R + - L + dHCP: + hemi: + - R + - L + CIVM: + hemi: + - R + - L + MBMv2: + hemi: + - R + - L + MBMv3: + hemi: + - R + + template_files: CITI168: T1w: T1w_head_700um.nii.gz @@ -395,16 +418,16 @@ template_files: T1w: tpl-MBMv3_T1w.nii.gz T2w: tpl-MBMv3_T2w.nii.gz xfm_corobl: tpl-MBMv3_from-native_to-corobl_type-itk_affine.txt - crop_ref: tpl-MBMv3_hemi-{hemi}_space-corobl_{modality}.nii.gz + crop_ref: tpl-MBMv3_hemi-{hemi}_space-corobl_T1w.nii.gz Mask_crop: tpl-MBMv3_hemi-{hemi}_space-corobl_desc-hipp_mask.nii.gz - dseg: tpl-MBMv3_hemi-R_space-corobl_desc-tissue_dseg.nii.gz - coords: tpl-MBMv3_dir-{dir}_hemi-R_space-corobl_label-{autotop}_desc-laplace_coords.nii.gz + dseg: tpl-MBMv3_hemi-{hemi}_space-corobl_desc-tissuemanual_dseg.nii.gz + coords: tpl-MBMv3_dir-{dir}_hemi-{hemi}_space-corobl_label-{autotop}_desc-laplace_coords.nii.gz CIVM: T1w: tpl-CIVM_T1w.nii.gz xfm_corobl: tpl-CIVM_from-native_to-corobl_type-itk_affine.txt crop_ref: tpl-CIVM_hemi-{hemi}_space-corobl_{modality}.nii.gz Mask_crop: tpl-CIVM_hemi-{hemi}_space-corobl_desc-hipp_mask.nii.gz - dseg: tpl-CIVM_hemi-R_space-corobl_desc-tissue_dseg.nii.gz + dseg: tpl-CIVM_hemi-R_space-corobl_desc-tissuemanual_dseg.nii.gz coords: tpl-CIVM_dir-{dir}_hemi-R_space-corobl_label-{autotop}_desc-laplace_coords.nii.gz upenn: T1w: tpl-upenn_desc-hipptissue_dseg.nii.gz @@ -491,6 +514,7 @@ resource_urls: MBMv2: 'files.ca-1.osf.io/v1/resources/v8acf/providers/osfstorage/65395c0887852d133ca597dd/?zip=' MBMv3: 'files.ca-1.osf.io/v1/resources/v8acf/providers/osfstorage/65395c0e8a28b11240ffc6e9/?zip=' upenn: 'files.ca-1.osf.io/v1/resources/v8acf/providers/osfstorage/65395c1613d27b122a94ca09/?zip=' + CIVM: 'files.ca-1.osf.io/v1/resources/v8acf/providers/osfstorage/65395bf62827451220b86e24/?zip=' #to get hash, see https://github.com/CenterForOpenScience/osf.io/issues/8256#issuecomment-379833911 diff --git a/hippunfold/workflow/rules/download.smk b/hippunfold/workflow/rules/download.smk index 07c1bcdd..91c8661e 100644 --- a/hippunfold/workflow/rules/download.smk +++ b/hippunfold/workflow/rules/download.smk @@ -3,14 +3,32 @@ download_dir = get_download_dir() -rule download_extract_atlas_or_template: +rule download_extract_atlas: params: - url=lambda wildcards: config["resource_urls"][wildcards.resource_type][ + url=lambda wildcards: config["resource_urls"]["atlas"][ wildcards.atlas ], output: unzip_dir=directory( - Path(download_dir) / "{resource_type,atlas|template}" / "{atlas}" + Path(download_dir) / "atlas" / "{atlas}" + ), + container: + config["singularity"]["autotop"] + shadow: + "minimal" + shell: + "wget https://{params.url} -O temp.zip && " + " unzip -d {output.unzip_dir} temp.zip" + + +rule download_extract_template: + params: + url=lambda wildcards: config["resource_urls"]["template"][ + wildcards.template + ], + output: + unzip_dir=directory( + Path(download_dir) / "template" / "{template}" ), container: config["singularity"]["autotop"] diff --git a/hippunfold/workflow/rules/preproc_t1.smk b/hippunfold/workflow/rules/preproc_t1.smk index 65ffeb35..a2b44b54 100644 --- a/hippunfold/workflow/rules/preproc_t1.smk +++ b/hippunfold/workflow/rules/preproc_t1.smk @@ -298,7 +298,7 @@ rule warp_t1_to_corobl_crop: root=work, datatype="anat", **config["subj_wildcards"], - suffix="T1w.nii.gz", + suffix="{modality}.nii.gz", space="corobl", desc="preproc", hemi="{hemi,L|R}" diff --git a/hippunfold/workflow/rules/templateseg.smk b/hippunfold/workflow/rules/templateseg.smk index 8074dd19..8620f2a7 100644 --- a/hippunfold/workflow/rules/templateseg.smk +++ b/hippunfold/workflow/rules/templateseg.smk @@ -7,6 +7,39 @@ def get_smoothing_opt(wildcards): return f"-s {gradient_sigma}vox {warp_sigma}vox" +# Template-based segmentation supports templates that have only a single hemisphere +# by mapping it to the flipped version of the other hemisphere. +# If a template has both L and R files, then we set hemi_constrained_wildcard to L|R. +# If a hemisphere is missing data, then we set it to flip that, e.g. if L missing, then use Lflip|R + +hemi_constraints = [] +if config["template"] in config["template_based_segmentation"]: + for hemi in config["hemi"]: + if hemi in config["template_based_segmentation"][config["template"]]["hemi"]: + hemi_constraints.append(hemi) + else: + hemi_constraints.append(f"{hemi}flip") + +hemi_constrained_wildcard = "{{hemi,{constraints}}}".format( + constraints="|".join(hemi_constraints) +) + + +def flipped(wildcards): + """function to map hemi in wildcards from Lflip to R, or Rflip to L, + for use in rules where e.g. the output wildcard is Lflip, but for the input, R is desired, such as + when mapping a R hemi dseg to the Lflip hemisphere of a subject.""" + + if wildcards.hemi == "L" or wildcards.hemi == "R": + return wildcards + elif wildcards.hemi == "Lflip": + wildcards.hemi = "R" + return wildcards + elif wildcards.hemi == "Rflip": + wildcards.hemi = "L" + return wildcards + + rule template_reg: input: fixed_img=bids( @@ -25,7 +58,7 @@ rule template_reg: moving_img=lambda wildcards, input: Path(input.template_dir) / config["template_files"][config["template"]][ get_modality_suffix(config["modality"]) - ].format(**wildcards), + ].format(**flipped(wildcards)), xfm_corobl=lambda wildcards, input: Path(input.template_dir) / config["template_files"][config["template"]]["xfm_corobl"].format( **wildcards @@ -43,7 +76,7 @@ rule template_reg: from_="template", to="subject", space="corobl", - hemi="{hemi,R|L}" + hemi=hemi_constrained_wildcard, ), group: "subj" @@ -81,7 +114,9 @@ rule warp_template_dseg: template_dir=Path(download_dir) / "template" / config["template"], params: template_dseg=lambda wildcards, input: Path(input.template_dir) - / config["template_files"][config["template"]]["dseg"].format(**wildcards), + / config["template_files"][config["template"]]["dseg"].format( + **flipped(wildcards) + ), interp_opt="-ri LABEL 0.2vox", output: inject_seg=bids( @@ -91,7 +126,7 @@ rule warp_template_dseg: suffix="dseg.nii.gz", desc="postproc", space="corobl", - hemi="{hemi,R|L}" + hemi=hemi_constrained_wildcard, ), group: "subj" @@ -128,7 +163,9 @@ rule warp_template_coords: params: interp_opt="-ri NN", template_coords=lambda wildcards, input: Path(input.template_dir) - / config["template_files"][config["template"]]["coords"].format(**wildcards), + / config["template_files"][config["template"]]["coords"].format( + **flipped(wildcards) + ), output: init_coords=bids( root=work, @@ -139,7 +176,7 @@ rule warp_template_coords: suffix="coords.nii.gz", desc="init", space="corobl", - hemi="{hemi,R|L|Lflip}" + hemi=hemi_constrained_wildcard, ), group: "subj" @@ -176,7 +213,7 @@ rule warp_template_anat: params: template_anat=lambda wildcards, input: Path(input.template_dir) / config["template_files"][config["template"]][config["modality"]].format( - **wildcards + **flipped(wildcards) ), xfm_corobl=lambda wildcards, input: Path(input.template_dir) / config["template_files"][config["template"]]["xfm_corobl"].format( @@ -190,7 +227,7 @@ rule warp_template_anat: suffix=f"{config['modality']}.nii.gz", desc="warpedtemplate", space="corobl", - hemi="{hemi,L|R}", + hemi=hemi_constrained_wildcard, ), group: "subj" @@ -228,7 +265,7 @@ rule unflip_template_dseg: suffix="dseg.nii.gz", desc="postproc", space="corobl", - hemi="{hemi,L}", + hemi="{hemi,L|R}", **config["subj_wildcards"] ), container: @@ -272,7 +309,7 @@ rule unflip_template_coords: suffix="coords.nii.gz", desc="init", space="corobl", - hemi="{hemi,L}" + hemi="{hemi,L|R}", ), container: config["singularity"]["autotop"] diff --git a/hippunfold/workflow/scripts/create_warps.py b/hippunfold/workflow/scripts/create_warps.py index cc923fb1..f79414ab 100644 --- a/hippunfold/workflow/scripts/create_warps.py +++ b/hippunfold/workflow/scripts/create_warps.py @@ -259,9 +259,7 @@ def summary(name, array): summary("displace_to_unfold_vec", displace_to_unfold_vec) # create new shape as 5d vector image in native space -native_map_shape = np.ones( - 5, -) +native_map_shape = np.ones(5,) native_map_shape[:3] = mask.shape native_map_shape[-1] = 3 From 149d0a1c08b61c22ec58a268c5bbfb35d8476151 Mon Sep 17 00:00:00 2001 From: "Jordan DeKraker - B. Bernhardt Lab" Date: Wed, 21 Feb 2024 15:45:51 -0500 Subject: [PATCH 09/15] linting --- hippunfold/dags/proc_subgraph.py | 1 - hippunfold/workflow/Snakefile | 12 ------------ hippunfold/workflow/rules/common.smk | 2 -- hippunfold/workflow/rules/download.smk | 16 ++++------------ hippunfold/workflow/rules/nnunet.smk | 2 -- hippunfold/workflow/rules/preproc_t1.smk | 1 - hippunfold/workflow/rules/preproc_t2.smk | 2 -- hippunfold/workflow/rules/qc.smk | 1 - hippunfold/workflow/rules/subfields.smk | 1 - .../workflow/scripts/constrain_surf_to_bbox.py | 1 - hippunfold/workflow/scripts/create_warps.py | 4 +++- hippunfold/workflow/scripts/gen_volume_tsv.py | 1 - hippunfold/workflow/scripts/laplace_coords.py | 1 - .../workflow/scripts/laplace_coords_withinit.py | 1 - 14 files changed, 7 insertions(+), 39 deletions(-) diff --git a/hippunfold/dags/proc_subgraph.py b/hippunfold/dags/proc_subgraph.py index 566408ba..c5cd7fcc 100755 --- a/hippunfold/dags/proc_subgraph.py +++ b/hippunfold/dags/proc_subgraph.py @@ -19,7 +19,6 @@ subgraphs = dict() for smk in glob("../workflow/rules/*.smk"): - smk_name = re.findall(re.compile(r"/(\w+).smk"), smk)[0] with open(smk, "r") as f: diff --git a/hippunfold/workflow/Snakefile b/hippunfold/workflow/Snakefile index 2b939bb8..919b6536 100644 --- a/hippunfold/workflow/Snakefile +++ b/hippunfold/workflow/Snakefile @@ -139,23 +139,11 @@ if config["modality"] == "hippb500": include: "rules/autotop.smk" - - include: "rules/warps.smk" - - include: "rules/gifti.smk" - - include: "rules/subfields.smk" - - include: "rules/resample_final_to_crop_native.smk" - - include: "rules/qc.smk" - - include: "rules/myelin_map.smk" diff --git a/hippunfold/workflow/rules/common.smk b/hippunfold/workflow/rules/common.smk index 297b9486..b0e5db03 100644 --- a/hippunfold/workflow/rules/common.smk +++ b/hippunfold/workflow/rules/common.smk @@ -24,7 +24,6 @@ def get_modality_suffix(modality): def get_final_spec(): - if len(config["hemi"]) == 2: specs = expand( bids( @@ -323,7 +322,6 @@ def get_final_subj_output(): def get_final_output(): - if config["keep_work"]: subj_output = get_final_subj_output() else: diff --git a/hippunfold/workflow/rules/download.smk b/hippunfold/workflow/rules/download.smk index 91c8661e..2a60b38b 100644 --- a/hippunfold/workflow/rules/download.smk +++ b/hippunfold/workflow/rules/download.smk @@ -5,13 +5,9 @@ download_dir = get_download_dir() rule download_extract_atlas: params: - url=lambda wildcards: config["resource_urls"]["atlas"][ - wildcards.atlas - ], + url=lambda wildcards: config["resource_urls"]["atlas"][wildcards.atlas], output: - unzip_dir=directory( - Path(download_dir) / "atlas" / "{atlas}" - ), + unzip_dir=directory(Path(download_dir) / "atlas" / "{atlas}"), container: config["singularity"]["autotop"] shadow: @@ -23,13 +19,9 @@ rule download_extract_atlas: rule download_extract_template: params: - url=lambda wildcards: config["resource_urls"]["template"][ - wildcards.template - ], + url=lambda wildcards: config["resource_urls"]["template"][wildcards.template], output: - unzip_dir=directory( - Path(download_dir) / "template" / "{template}" - ), + unzip_dir=directory(Path(download_dir) / "template" / "{template}"), container: config["singularity"]["autotop"] shadow: diff --git a/hippunfold/workflow/rules/nnunet.smk b/hippunfold/workflow/rules/nnunet.smk index 054f0ecf..b9f20b69 100644 --- a/hippunfold/workflow/rules/nnunet.smk +++ b/hippunfold/workflow/rules/nnunet.smk @@ -42,7 +42,6 @@ def get_nnunet_input(wildcards): def get_model_tar(): - if config["force_nnunet_model"]: model_name = config["force_nnunet_model"] else: @@ -201,7 +200,6 @@ rule unflip_nnunet_nii: def get_f3d_ref(wildcards, input): - if config["modality"] == "T2w": nii = Path(input.template_dir) / config["template_files"][config["template"]][ "crop_ref" diff --git a/hippunfold/workflow/rules/preproc_t1.smk b/hippunfold/workflow/rules/preproc_t1.smk index a2b44b54..c9140272 100644 --- a/hippunfold/workflow/rules/preproc_t1.smk +++ b/hippunfold/workflow/rules/preproc_t1.smk @@ -71,7 +71,6 @@ else: def reg_to_template_cmd(wildcards, input, output): - ref = str( Path(input.template_dir) / config["template_files"][config["template"]][wildcards.modality].format( diff --git a/hippunfold/workflow/rules/preproc_t2.smk b/hippunfold/workflow/rules/preproc_t2.smk index 4dc43e60..e410355c 100644 --- a/hippunfold/workflow/rules/preproc_t2.smk +++ b/hippunfold/workflow/rules/preproc_t2.smk @@ -114,7 +114,6 @@ rule reg_t2_to_ref: def get_aligned_n4_t2(wildcards): - # first get the number of floating t2s filtered = snakebids.filter_list(config["input_zip_lists"]["T2w"], wildcards) num_scans = len(filtered["subject"]) @@ -278,7 +277,6 @@ def get_inputs_compose_t2_xfm_corobl(wildcards): return {"t2_to_t1": t2_to_t1, "t1_to_cor": t1_to_cor} else: - # xfm0: t2 to template t2_to_std = ( bids( diff --git a/hippunfold/workflow/rules/qc.smk b/hippunfold/workflow/rules/qc.smk index b2b9d028..0e97e6c6 100644 --- a/hippunfold/workflow/rules/qc.smk +++ b/hippunfold/workflow/rules/qc.smk @@ -110,7 +110,6 @@ rule plot_subj_subfields: def get_bg_img_for_subfield_qc(wildcards): - if config["modality"] == "hippb500": return bids( root=work, diff --git a/hippunfold/workflow/rules/subfields.smk b/hippunfold/workflow/rules/subfields.smk index 18ba6dcc..7a3397b6 100644 --- a/hippunfold/workflow/rules/subfields.smk +++ b/hippunfold/workflow/rules/subfields.smk @@ -123,7 +123,6 @@ rule label_subfields_from_vol_coords_corobl: def get_tissue_atlas_remapping(wildcards): - mapping = config["tissue_atlas_mapping"] remap = [] diff --git a/hippunfold/workflow/scripts/constrain_surf_to_bbox.py b/hippunfold/workflow/scripts/constrain_surf_to_bbox.py index fd82d8d1..df28f803 100644 --- a/hippunfold/workflow/scripts/constrain_surf_to_bbox.py +++ b/hippunfold/workflow/scripts/constrain_surf_to_bbox.py @@ -2,7 +2,6 @@ import numpy as np with open(snakemake.log[0], "w") as sys.stdout: - epsilon = 0.01 # load gifti surf diff --git a/hippunfold/workflow/scripts/create_warps.py b/hippunfold/workflow/scripts/create_warps.py index f79414ab..cc923fb1 100644 --- a/hippunfold/workflow/scripts/create_warps.py +++ b/hippunfold/workflow/scripts/create_warps.py @@ -259,7 +259,9 @@ def summary(name, array): summary("displace_to_unfold_vec", displace_to_unfold_vec) # create new shape as 5d vector image in native space -native_map_shape = np.ones(5,) +native_map_shape = np.ones( + 5, +) native_map_shape[:3] = mask.shape native_map_shape[-1] = 3 diff --git a/hippunfold/workflow/scripts/gen_volume_tsv.py b/hippunfold/workflow/scripts/gen_volume_tsv.py index 18e2c717..e663cf62 100644 --- a/hippunfold/workflow/scripts/gen_volume_tsv.py +++ b/hippunfold/workflow/scripts/gen_volume_tsv.py @@ -15,7 +15,6 @@ for in_img, hemi in zip(snakemake.input.segs, hemis): - img_nib = nib.load(in_img) img = img_nib.get_fdata() zooms = img_nib.header.get_zooms() diff --git a/hippunfold/workflow/scripts/laplace_coords.py b/hippunfold/workflow/scripts/laplace_coords.py index 7a965d9d..6360a478 100644 --- a/hippunfold/workflow/scripts/laplace_coords.py +++ b/hippunfold/workflow/scripts/laplace_coords.py @@ -77,7 +77,6 @@ # iterate until the solution doesn't change anymore (or reach max iters) for i in range(max_iters): - # debug: save niftis to check progress # if (i % 100 == 0): # tonii = coords.copy() diff --git a/hippunfold/workflow/scripts/laplace_coords_withinit.py b/hippunfold/workflow/scripts/laplace_coords_withinit.py index b078b3af..9c7046d8 100644 --- a/hippunfold/workflow/scripts/laplace_coords_withinit.py +++ b/hippunfold/workflow/scripts/laplace_coords_withinit.py @@ -56,7 +56,6 @@ # iterate until the solution doesn't change anymore (or reach max iters) for i in range(max_iters): - # debug: save niftis to check progress # if (i % 100 == 0): # tonii = coords.copy() From 4f69e0642e317f9e380f73641b00462fc17c2e00 Mon Sep 17 00:00:00 2001 From: "Jordan DeKraker - B. Bernhardt Lab" Date: Wed, 21 Feb 2024 15:50:21 -0500 Subject: [PATCH 10/15] more lint --- hippunfold/workflow/Snakefile | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hippunfold/workflow/Snakefile b/hippunfold/workflow/Snakefile index 919b6536..2b939bb8 100644 --- a/hippunfold/workflow/Snakefile +++ b/hippunfold/workflow/Snakefile @@ -139,11 +139,23 @@ if config["modality"] == "hippb500": include: "rules/autotop.smk" + + include: "rules/warps.smk" + + include: "rules/gifti.smk" + + include: "rules/subfields.smk" + + include: "rules/resample_final_to_crop_native.smk" + + include: "rules/qc.smk" + + include: "rules/myelin_map.smk" From c8efe711c2eda4a8610fe2da78347b1d40171607 Mon Sep 17 00:00:00 2001 From: "Jordan DeKraker - B. Bernhardt Lab" Date: Wed, 21 Feb 2024 15:58:31 -0500 Subject: [PATCH 11/15] minor fix --- .dryrun_test_all.sh | 4 ++-- hippunfold/workflow/rules/preproc_t1.smk | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.dryrun_test_all.sh b/.dryrun_test_all.sh index 74a3c865..4dccdf95 100755 --- a/.dryrun_test_all.sh +++ b/.dryrun_test_all.sh @@ -10,8 +10,8 @@ hippunfold test_data/bids_hippb500 test_out participant -np --modality hippb500 hippunfold test_data/bids_T1w_longitudinal test_out participant -np --modality T1w hippunfold test_data/bids_singleT2w_longitudinal test_out participant -np --modality T2w hippunfold test_data/bids_segT2w test_out participant -np --modality segT2w -hippunfold - test_out participant -np --modality cropseg --path_cropseg test_data/data_cropseg/sub-{subject}_hemi-{hemi}_dseg.nii.gz -hippunfold - test_out participant -np --modality cropseg --path_cropseg test_data/data_cropseg_1hemi/sub-{subject}_hemi-{hemi}_dseg.nii.gz --hemi L +hippunfold . test_out participant -np --modality cropseg --path_cropseg test_data/data_cropseg/sub-{subject}_hemi-{hemi}_dseg.nii.gz +hippunfold . test_out participant -np --modality cropseg --path_cropseg test_data/data_cropseg_1hemi/sub-{subject}_hemi-{hemi}_dseg.nii.gz --hemi L hippunfold test_data/bids_singleT2w test_out participant -np --modality T2w --t1_reg_template hippunfold test_data/bids_singleT2w test_out participant -np --modality T2w --output_space T1w hippunfold test_data/bids_T1w test_out participant -np --modality T1w --use-template-seg diff --git a/hippunfold/workflow/rules/preproc_t1.smk b/hippunfold/workflow/rules/preproc_t1.smk index c9140272..de65340e 100644 --- a/hippunfold/workflow/rules/preproc_t1.smk +++ b/hippunfold/workflow/rules/preproc_t1.smk @@ -297,7 +297,7 @@ rule warp_t1_to_corobl_crop: root=work, datatype="anat", **config["subj_wildcards"], - suffix="{modality}.nii.gz", + suffix="T1w.nii.gz", space="corobl", desc="preproc", hemi="{hemi,L|R}" From 66c4a93c3cccd26ed8d745e7ba0cf437598dade0 Mon Sep 17 00:00:00 2001 From: "Jordan DeKraker - B. Bernhardt Lab" Date: Wed, 21 Feb 2024 18:22:51 -0500 Subject: [PATCH 12/15] minor change --- hippunfold/workflow/rules/preproc_t1.smk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hippunfold/workflow/rules/preproc_t1.smk b/hippunfold/workflow/rules/preproc_t1.smk index de65340e..22853c44 100644 --- a/hippunfold/workflow/rules/preproc_t1.smk +++ b/hippunfold/workflow/rules/preproc_t1.smk @@ -291,7 +291,7 @@ rule warp_t1_to_corobl_crop: template_dir=Path(download_dir) / "template" / config["template"], params: ref=lambda wildcards, input: Path(input.template_dir) - / config["template_files"][config["template"]]["crop_ref"].format(**wildcards), + / config["template_files"][config["template"]]["crop_ref"].format(**wildcards, modality="T1w"), output: t1=bids( root=work, From 470e57c70380cc164df116c7fcefa0b51b170cf4 Mon Sep 17 00:00:00 2001 From: "Jordan DeKraker - B. Bernhardt Lab" Date: Wed, 21 Feb 2024 18:26:05 -0500 Subject: [PATCH 13/15] lint --- hippunfold/workflow/rules/preproc_t1.smk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hippunfold/workflow/rules/preproc_t1.smk b/hippunfold/workflow/rules/preproc_t1.smk index 22853c44..038b0dfb 100644 --- a/hippunfold/workflow/rules/preproc_t1.smk +++ b/hippunfold/workflow/rules/preproc_t1.smk @@ -291,7 +291,9 @@ rule warp_t1_to_corobl_crop: template_dir=Path(download_dir) / "template" / config["template"], params: ref=lambda wildcards, input: Path(input.template_dir) - / config["template_files"][config["template"]]["crop_ref"].format(**wildcards, modality="T1w"), + / config["template_files"][config["template"]]["crop_ref"].format( + **wildcards, modality="T1w" + ), output: t1=bids( root=work, From b834665e3fa398f3da9fb60e705b291ef1c32136 Mon Sep 17 00:00:00 2001 From: Ali Khan Date: Fri, 23 Feb 2024 14:13:17 -0500 Subject: [PATCH 14/15] fixes missing {hemi} wildcard CIVM template dseg/coords --- hippunfold/config/snakebids.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hippunfold/config/snakebids.yml b/hippunfold/config/snakebids.yml index c246ff54..57c7579c 100644 --- a/hippunfold/config/snakebids.yml +++ b/hippunfold/config/snakebids.yml @@ -427,8 +427,8 @@ template_files: xfm_corobl: tpl-CIVM_from-native_to-corobl_type-itk_affine.txt crop_ref: tpl-CIVM_hemi-{hemi}_space-corobl_{modality}.nii.gz Mask_crop: tpl-CIVM_hemi-{hemi}_space-corobl_desc-hipp_mask.nii.gz - dseg: tpl-CIVM_hemi-R_space-corobl_desc-tissuemanual_dseg.nii.gz - coords: tpl-CIVM_dir-{dir}_hemi-R_space-corobl_label-{autotop}_desc-laplace_coords.nii.gz + dseg: tpl-CIVM_hemi-{hemi}_space-corobl_desc-tissuemanual_dseg.nii.gz + coords: tpl-CIVM_dir-{dir}_hemi-{hemi}_space-corobl_label-{autotop}_desc-laplace_coords.nii.gz upenn: T1w: tpl-upenn_desc-hipptissue_dseg.nii.gz dseg: tpl-upenn_desc-hipptissue_dseg.nii.gz From 3bcc825c6dd77f7bb9add140a774ee1fb01fbacb Mon Sep 17 00:00:00 2001 From: Ali Khan Date: Fri, 23 Feb 2024 14:17:12 -0500 Subject: [PATCH 15/15] update template-seg CLI message, and fix config - ensures entries in template_based_segmentation are correct (ie only include templates that have coords/dseg, and whatever hemis are available --- hippunfold/config/snakebids.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/hippunfold/config/snakebids.yml b/hippunfold/config/snakebids.yml index 57c7579c..4c9033c2 100644 --- a/hippunfold/config/snakebids.yml +++ b/hippunfold/config/snakebids.yml @@ -166,7 +166,7 @@ parse_args: 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)' + 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 vivo marmoset), or CIVM (ex vivo macaque) template. (default: %(default)s)' default: False action: 'store_true' @@ -367,15 +367,12 @@ singularity: xfm_identity: resources/etc/identity_xfm.txt #templates enabled for template-based segmentation are here +# TODO: should also perhaps include modalities avaialble, and any custom crop_native_res settings template_based_segmentation: CITI168: hemi: - R - L - dHCP: - hemi: - - R - - L CIVM: hemi: - R @@ -383,7 +380,6 @@ template_based_segmentation: MBMv2: hemi: - R - - L MBMv3: hemi: - R