From 853b8fe32b3e9120e29c67592fe522766e0f2ce9 Mon Sep 17 00:00:00 2001 From: Ali Khan Date: Fri, 26 Feb 2021 21:21:18 -0500 Subject: [PATCH] add composed itk warps from T1w to unfold (incl corobl to unfold) (#36) Adds composed warps from T1w to unfold space, and subfields warped to unfolded space (from corobl). Also: Unrelated bugfix: * bugfix: missing nilearn dep (for qc) Other updates: * removed print statements about model dir env var * updated version to 0.3.0 in json --- hippunfold/config/snakebids.yml | 1 + hippunfold/pipeline_description.json | 2 +- .../resources/desc-flipLR_type-itk_xfm.txt | 5 ++ hippunfold/workflow/Snakefile | 4 +- hippunfold/workflow/rules/autotop.smk | 51 ++++++++++++++++++- hippunfold/workflow/rules/nnunet.smk | 2 - hippunfold/workflow/rules/subfields.smk | 15 ++++++ setup.py | 1 + 8 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 hippunfold/resources/desc-flipLR_type-itk_xfm.txt diff --git a/hippunfold/config/snakebids.yml b/hippunfold/config/snakebids.yml index 3f509336..f9069270 100644 --- a/hippunfold/config/snakebids.yml +++ b/hippunfold/config/snakebids.yml @@ -167,6 +167,7 @@ singularity: prepdwi: 'docker://khanlab/prepdwi:latest' autotop: 'docker://khanlab/autotop_deps:v0.2' fsl: '/project/6050199/akhanf/singularity/bids-apps/fsl_6.0.3_cuda9.1.sif' #fsl with cuda container not on docker hub yet.. only used for dwi workflow anyhow.. + ants: 'docker://kaczmarj/ants:2.3.4' template: CITI168 diff --git a/hippunfold/pipeline_description.json b/hippunfold/pipeline_description.json index f624d7d6..67cfc836 100644 --- a/hippunfold/pipeline_description.json +++ b/hippunfold/pipeline_description.json @@ -5,7 +5,7 @@ "GeneratedBy": [ { "Name": "hippunfold", - "Version": "0.1.0", + "Version": "0.3.0", "CodeURL": "https://github.com/khanlab/hippunfold", "Author": "Jordan DeKraker & Ali Khan", "AuthorEmail": "ali.khan@uwo.ca" diff --git a/hippunfold/resources/desc-flipLR_type-itk_xfm.txt b/hippunfold/resources/desc-flipLR_type-itk_xfm.txt new file mode 100644 index 00000000..335082b6 --- /dev/null +++ b/hippunfold/resources/desc-flipLR_type-itk_xfm.txt @@ -0,0 +1,5 @@ +#Insight Transform File V1.0 +#Transform 0 +Transform: MatrixOffsetTransformBase_double_3_3 +Parameters: -1 0 0 0 1 0 0 0 1 0 0 0 +FixedParameters: 0 0 0 diff --git a/hippunfold/workflow/Snakefile b/hippunfold/workflow/Snakefile index 0822c760..d4e9e5b3 100644 --- a/hippunfold/workflow/Snakefile +++ b/hippunfold/workflow/Snakefile @@ -62,9 +62,10 @@ def get_final_subfields(): for modality in config['modality']: mod_index = get_modality_key(modality) subfields = subfields + \ - expand(bids(root='results',datatype='seg_{modality}',desc='subfields',suffix='dseg.nii.gz', space='cropT1w',hemi='{hemi}', **config['subj_wildcards']), + expand(bids(root='results',datatype='seg_{modality}',desc='subfields',suffix='dseg.nii.gz', space='{space}',hemi='{hemi}', **config['subj_wildcards']), modality=modality, hemi=['L','R'], + space=['cropT1w','unfold'], subject=config['input_lists'][mod_index]['subject'], session=config['sessions']) @@ -97,7 +98,6 @@ def get_final_anat(): return anat - def get_final_qc(): qc = [] qc = qc + expand(bids(root='work',datatype='qc',**config['subj_wildcards'],suffix='regqc.png', diff --git a/hippunfold/workflow/rules/autotop.smk b/hippunfold/workflow/rules/autotop.smk index bc604c28..cc2e5dad 100644 --- a/hippunfold/workflow/rules/autotop.smk +++ b/hippunfold/workflow/rules/autotop.smk @@ -50,6 +50,8 @@ rule run_autotop: warp_unfold2native_extrap = bids(root='work',**config['subj_wildcards'],suffix='autotop/Warp_unfold2native_extrapolateNearest.nii',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='{modality}'), warp_unfold2native = bids(root='work',**config['subj_wildcards'],suffix='autotop/Warp_unfold2native.nii',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='{modality}'), warp_native2unfold= bids(root='work',**config['subj_wildcards'],suffix='autotop/Warp_native2unfold.nii',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='{modality}'), + warpitk_unfold2native = bids(root='work',**config['subj_wildcards'],suffix='autotop/WarpITK_unfold2native.nii',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='{modality}'), + warpitk_native2unfold= bids(root='work',**config['subj_wildcards'],suffix='autotop/WarpITK_native2unfold.nii',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='{modality}'), gii = expand(bids(root='work',suffix='autotop/{surfname}.unfoldedtemplate.surf.gii',desc='cropped', space='corobl',hemi='{hemi,Lflip|R}',modality='{modality}', **config['subj_wildcards']),surfname=['inner','outer','midthickness'],allow_missing=True), coords = expand(bids(root='work',suffix='autotop/coords-{dir}.nii.gz',desc='cropped', space='corobl',hemi='{hemi,Lflip|R}',modality='{modality}', **config['subj_wildcards']),dir=['AP','PD','IO'],allow_missing=True) threads: 8 @@ -88,8 +90,10 @@ rule run_autotop_inputseg: output: out_dir = directory(bids(root='work',**config['subj_wildcards'],suffix='autotop',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='seg{modality}')), #subfields = bids(root='work',**config['subj_wildcards'],suffix='autotop/subfields-BigBrain.nii.gz',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='seg{modality}'), - warp_unfold2native = bids(root='work',**config['subj_wildcards'],suffix='autotop/Warp_unfold2native.nii',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='seg{modality}'), - warp_native2unfold= bids(root='work',**config['subj_wildcards'],suffix='autotop/Warp_native2unfold.nii',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='seg{modality}'), + warp_unfold2native = bids(root='work',**config['subj_wildcards'],suffix='autotop/Warp_unfold2native.nii',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='{modality}'), + warp_native2unfold= bids(root='work',**config['subj_wildcards'],suffix='autotop/Warp_native2unfold.nii',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='{modality}'), + warpitk_unfold2native = bids(root='work',**config['subj_wildcards'],suffix='autotop/WarpITK_unfold2native.nii',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='{modality}'), + warpitk_native2unfold= bids(root='work',**config['subj_wildcards'],suffix='autotop/WarpITK_native2unfold.nii',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='{modality}'), gii = expand(bids(root='work',suffix='autotop/{surfname}.unfoldedtemplate.surf.gii',desc='cropped', space='corobl',hemi='{{hemi}}',modality='seg{{modality}}', **config['subj_wildcards']),surfname=['inner','outer','midthickness'],allow_missing=True) threads: 8 resources: @@ -120,6 +124,9 @@ rule map_to_full_grid: script = os.path.join(config['snakemake_dir'],'workflow','scripts','mapUnfoldToFullGrid.sh') output: warp_unfoldtemplate2unfold = bids(root='work',**config['subj_wildcards'],suffix='autotop/Warp_unfoldtemplate2unfold.nii',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='{modality}'), + warp_unfold2unfoldtemplate = bids(root='work',**config['subj_wildcards'],suffix='autotop/Warp_unfold2unfoldtemplate.nii',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='{modality}'), + warpitk_unfoldtemplate2unfold = bids(root='work',**config['subj_wildcards'],suffix='autotop/WarpITK_unfold2unfoldtemplate_0InverseWarp.nii.gz',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='{modality}'), + warpitk_unfold2unfoldtemplate = bids(root='work',**config['subj_wildcards'],suffix='autotop/WarpITK_unfold2unfoldtemplate_0Warp.nii.gz',desc='cropped',space='corobl',hemi='{hemi,Lflip|R}',modality='{modality}'), container: config['singularity']['autotop'] group: 'subj' threads: 8 @@ -142,5 +149,45 @@ rule unflip_autotop_nii: shell: 'c3d {input} -flip x {output}' +rule compose_warps_corobl2unfold_rhemi: + """ Compose corobl to unfold (unfold-template), for right hemi (ie no flip)""" + input: + native2unfold = bids(root='work',**config['subj_wildcards'],suffix='autotop/WarpITK_native2unfold.nii',desc='cropped',space='corobl',hemi='R',modality='{modality}'), + unfold2unfoldtemplate = bids(root='work',**config['subj_wildcards'],suffix='autotop/WarpITK_unfold2unfoldtemplate_0Warp.nii.gz',desc='cropped',space='corobl',hemi='R',modality='{modality}'), + ref = os.path.join(config['snakemake_dir'],'hippocampal_autotop','misc','unfold_ref_256x128x16.nii.gz'), + output: + corobl2unfold = bids(root='work',datatype='seg_{modality}',**config['subj_wildcards'],suffix='xfm.nii.gz',hemi='R',from_='corobl',to='unfold',mode='image') + container: config['singularity']['ants'] + group: 'subj' + shell: 'ComposeMultiTransform 3 {output.corobl2unfold} -R {input.ref} {input.unfold2unfoldtemplate} {input.native2unfold}' + + +rule compose_warps_corobl2unfold_lhemi: + """ Compose corobl to unfold (unfold-template), for left hemi (ie with flip)""" + input: + native2unfold = bids(root='work',**config['subj_wildcards'],suffix='autotop/WarpITK_native2unfold.nii',desc='cropped',space='corobl',hemi='Lflip',modality='{modality}'), + unfold2unfoldtemplate = bids(root='work',**config['subj_wildcards'],suffix='autotop/WarpITK_unfold2unfoldtemplate_0Warp.nii.gz',desc='cropped',space='corobl',hemi='Lflip',modality='{modality}'), + ref = os.path.join(config['snakemake_dir'],'hippocampal_autotop','misc','unfold_ref_256x128x16.nii.gz'), + flipLR_xfm = os.path.join(config['snakemake_dir'],'resources','desc-flipLR_type-itk_xfm.txt') + output: + corobl2unfold = bids(root='work',datatype='seg_{modality}',**config['subj_wildcards'],suffix='xfm.nii.gz',hemi='L',from_='corobl',to='unfold',mode='image') + container: config['singularity']['ants'] + group: 'subj' + shell: 'ComposeMultiTransform 3 {output.corobl2unfold} -R {input.ref} {input.unfold2unfoldtemplate} {input.native2unfold} {input.flipLR_xfm}' + + + +rule compose_warps_t1_to_unfold: + """ Compose warps from T1w to unfold """ + input: + corobl2unfold = bids(root='work',datatype='seg_{modality}',**config['subj_wildcards'],suffix='xfm.nii.gz',hemi='{hemi}',from_='corobl',to='unfold',mode='image'), + ref = os.path.join(config['snakemake_dir'],'hippocampal_autotop','misc','unfold_ref_256x128x16.nii.gz'), + t1w2corobl = bids(root='work',datatype='anat',**config['subj_wildcards'],suffix='xfm.txt',from_='T1w',to='corobl',desc='affine',type_='itk'), + output: + bids(root='results',datatype='seg_{modality}',**config['subj_wildcards'],suffix='xfm.nii.gz',hemi='{hemi}',from_='T1w',to='unfold',mode='image') + container: config['singularity']['ants'] + group: 'subj' + shell: 'ComposeMultiTransform 3 {output} -R {input.ref} {input.corobl2unfold} {input.t1w2corobl}' + diff --git a/hippunfold/workflow/rules/nnunet.smk b/hippunfold/workflow/rules/nnunet.smk index 01d37a96..588749d9 100644 --- a/hippunfold/workflow/rules/nnunet.smk +++ b/hippunfold/workflow/rules/nnunet.smk @@ -13,10 +13,8 @@ def get_nnunet_input (wildcards): def get_model_tar (wildcards): if 'HIPPUNFOLD_CACHE_DIR' in os.environ.keys(): - print(f"HIPPUNFOLD_CACHE_DIR defined, using: {os.environ['HIPPUNFOLD_CACHE_DIR']}") download_dir = os.environ['HIPPUNFOLD_CACHE_DIR'] else: - print(f'HIPPUNFOLD_CACHE_DIR not defined, using default location') #create local download dir if it doesn't exist dirs = AppDirs('hippunfold','khanlab') download_dir = dirs.user_cache_dir diff --git a/hippunfold/workflow/rules/subfields.smk b/hippunfold/workflow/rules/subfields.smk index f6784323..6c77b88a 100644 --- a/hippunfold/workflow/rules/subfields.smk +++ b/hippunfold/workflow/rules/subfields.smk @@ -135,3 +135,18 @@ rule concat_subj_vols_tsv: import pandas as pd pd.concat([pd.read_table(in_tsv) for in_tsv in input ]).to_csv(output.tsv,sep='\t',index=False) + +rule resample_subfields_to_unfold: + """Resampling to unfold space""" + input: + nii = bids(root='work',datatype='seg_{modality}',desc='subfields',suffix='dseg.nii.gz', space='corobl',hemi='{hemi}', **config['subj_wildcards']), + xfm = bids(root='work',datatype='seg_{modality}',**config['subj_wildcards'],suffix='xfm.nii.gz',hemi='{hemi}',from_='corobl',to='unfold',mode='image') + output: + nii = bids(root='results',datatype='seg_{modality}',suffix='dseg.nii.gz', desc='subfields',space='unfold',hemi='{hemi}', **config['subj_wildcards']) + container: config['singularity']['autotop'] + group: 'subj' + shell: + 'ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS={threads} ' + 'antsApplyTransforms -d 3 --interpolation MultiLabel -i {input.nii} -o {output.nii} -r {input.xfm} -t {input.xfm}' + + diff --git a/setup.py b/setup.py index 1f7a6cc5..0803d62e 100644 --- a/setup.py +++ b/setup.py @@ -42,6 +42,7 @@ "nibabel", "numpy", "scipy", + "nilearn", "seaborn" ], python_requires='>=3.7'