diff --git a/subworkflows/nf-neuro/preproc_t1/main.nf b/subworkflows/nf-neuro/preproc_t1/main.nf index 2c37238a..5b408716 100644 --- a/subworkflows/nf-neuro/preproc_t1/main.nf +++ b/subworkflows/nf-neuro/preproc_t1/main.nf @@ -3,18 +3,22 @@ include { DENOISING_NLMEANS } from '../../../modules/nf-neuro/denoising/nlmeans/ include { PREPROC_N4 } from '../../../modules/nf-neuro/preproc/n4/main' include { IMAGE_RESAMPLE } from '../../../modules/nf-neuro/image/resample/main' include { BETCROP_ANTSBET } from '../../../modules/nf-neuro/betcrop/antsbet/main' +include { BETCROP_SYNTHBET} from '../../../modules/nf-neuro/betcrop/synthbet/main' include { BETCROP_CROPVOLUME as BETCROP_CROPVOLUME_T1 } from '../../../modules/nf-neuro/betcrop/cropvolume/main' include { BETCROP_CROPVOLUME as BETCROP_CROPVOLUME_MASK } from '../../../modules/nf-neuro/betcrop/cropvolume/main' +params.run_synthbet = params.run_synthbet ?: false + workflow PREPROC_T1 { take: ch_image // channel: [ val(meta), [ image ] ] - ch_template // channel: [ val(meta), [ template ] ] - ch_probability_map // channel: [ val(meta), [ probability_map ] ] + ch_template // channel: [ val(meta), [ template ] ] , optional + ch_probability_map // channel: [ val(meta), [ probability_map ] ] , optional ch_mask_nlmeans // channel: [ val(meta), [ mask ] ] , optional ch_ref_n4 // channel: [ val(meta), [ ref, ref_mask ] ] , optional ch_ref_resample // channel: [ val(meta), [ ref ] ] , optional + ch_weights // channel: [ val(meta), [ weights ] ] , optional main: @@ -36,28 +40,48 @@ workflow PREPROC_T1 { ch_versions = ch_versions.mix(IMAGE_RESAMPLE.out.versions.first()) // ** Brain extraction ** // - ch_bet = IMAGE_RESAMPLE.out.image.join(ch_template).join(ch_probability_map) + if ( params.run_synthbet) { BETCROP_ANTSBET ( ch_bet ) + ch_bet = IMAGE_RESAMPLE.out.image.join(ch_weights) ch_versions = ch_versions.mix(BETCROP_ANTSBET.out.versions.first()) + BETCROP_SYNTHBET ( ch_bet ) + ch_versions = ch_versions.mix(BETCROP_SYNTHBET.out.versions.first()) + + // ** Setting BET output ** // + image_bet = BETCROP_SYNTHBET.out.bet_image + mask_bet = BETCROP_SYNTHBET.out.brain_mask + } + + else { + ch_template = ch_template.ifEmpty(Channel.error('Template is required for ANTS registration')) + ch_probability_map = ch_probability_map.ifEmpty(Channel.error('Probability map is required for ANTS registration')) + ch_bet = IMAGE_RESAMPLE.out.image.join(ch_template).join(ch_probability_map) + BETCROP_ANTSBET ( ch_bet ) + ch_versions = ch_versions.mix(BETCROP_ANTSBET.out.versions.first()) + + // ** Setting BET output ** // + image_bet = BETCROP_ANTSBET.out.t1 + mask_bet = BETCROP_ANTSBET.out.mask + } // ** crop image ** // - ch_crop = BETCROP_ANTSBET.out.t1.map{it + [[]]} + ch_crop = image_bet.t1.map{it + [[]]} BETCROP_CROPVOLUME_T1 ( ch_crop ) ch_versions = ch_versions.mix(BETCROP_CROPVOLUME_T1.out.versions.first()) // ** crop mask ** // - ch_crop_mask = BETCROP_ANTSBET.out.mask.join(BETCROP_CROPVOLUME_T1.out.bounding_box) + ch_crop_mask = mask_bet.mask.join(BETCROP_CROPVOLUME_T1.out.bounding_box) BETCROP_CROPVOLUME_MASK ( ch_crop_mask ) ch_versions = ch_versions.mix(BETCROP_CROPVOLUME_MASK.out.versions.first()) emit: - image_nlmeans = DENOISING_NLMEANS.out.image // channel: [ val(meta), [ image ] ] - image_N4 = PREPROC_N4.out.image // channel: [ val(meta), [ image ] ] - image_resample = IMAGE_RESAMPLE.out.image // channel: [ val(meta), [ image ] ] - image_bet = BETCROP_ANTSBET.out.t1 // channel: [ val(meta), [ t1 ] ] - mask_bet = BETCROP_ANTSBET.out.mask // channel: [ val(meta), [ mask ] ] + image_nlmeans = DENOISING_NLMEANS.out.image // channel: [ val(meta), [ image ] ] + image_N4 = PREPROC_N4.out.image // channel: [ val(meta), [ image ] ] + image_resample = IMAGE_RESAMPLE.out.image // channel: [ val(meta), [ image ] ] + image_bet = image_bet // channel: [ val(meta), [ t1 ] ] + mask_bet = mask_bet // channel: [ val(meta), [ mask ] ] crop_box = BETCROP_CROPVOLUME_T1.out.bounding_box // channel: [ val(meta), [ bounding_box ] ] - mask_final = BETCROP_CROPVOLUME_MASK.out.image // channel: [ val(meta), [ mask ] ] + mask_final = BETCROP_CROPVOLUME_MASK.out.image // channel: [ val(meta), [ mask ] ] t1_final = BETCROP_CROPVOLUME_T1.out.image // channel: [ val(meta), [ image ] ] - versions = ch_versions // channel: [ versions.yml ] + versions = ch_versions // channel: [ versions.yml ] } diff --git a/subworkflows/nf-neuro/preproc_t1/meta.yml b/subworkflows/nf-neuro/preproc_t1/meta.yml index 35baefa7..64e5abfb 100644 --- a/subworkflows/nf-neuro/preproc_t1/meta.yml +++ b/subworkflows/nf-neuro/preproc_t1/meta.yml @@ -21,7 +21,7 @@ description: | Resamples the T1 to an isotropic spatial resolution. The default is 1mm, a standard in humans which usually facilitate registration with corrected DWI images. This spatial resolution is modifiable in the configuration file. - Brain Extraction (bet, ANTs). + Brain Extraction (bet, ANTs, freesurfer). Isolates the brain tissue voxels from the remaining image. Also creates a binary brain mask. This brain extraction is required for the T1 to DWI Registration. Cropping (scil). @@ -42,6 +42,7 @@ components: - preproc/n4 - image/resample - betcrop/antsbet + - betcrop/synthbet - betcrop/cropvolume input: @@ -81,6 +82,12 @@ input: The input channel containing the reference for the resampling. Optional Structure: [ val(meta), path(ref) ] pattern: "*.{nii,nii.gz}" + - ch_weights: + type: file + description: | + The input channel containing an alternative model weights for synthbet. Optional + Structure: [ val(meta), path (weights)] + pattern: "*.pt" output: - image_nlmeans: type: file diff --git a/subworkflows/nf-neuro/preproc_t1/tests/main.nf.test b/subworkflows/nf-neuro/preproc_t1/tests/main.nf.test index 73086b21..97466b62 100644 --- a/subworkflows/nf-neuro/preproc_t1/tests/main.nf.test +++ b/subworkflows/nf-neuro/preproc_t1/tests/main.nf.test @@ -12,6 +12,7 @@ nextflow_workflow { tag "preproc/n4" tag "image/resample" tag "betcrop/antsbet" + tag "becrop/synthbet" tag "betcrop/cropvolume" tag "load_test_data" @@ -69,6 +70,11 @@ nextflow_workflow { [ id:'test', single_end:false ], [] ]} + input[6] = ch_split_test_data.antsbet.map{ + test_data_directory -> [ + [ id:'test', single_end:false ], + [] + ]} """ } } @@ -76,7 +82,17 @@ nextflow_workflow { then { assertAll( { assert workflow.success}, - { assert snapshot(workflow.out).match()} + { assert snapshot( + niftiMD5SUM(workflow.out.image_nlmeans.get(0).get(1)), + niftiMD5SUM(workflow.out.image_N4.get(0).get(1)), + niftiMD5SUM(workflow.out.image_resample.get(0).get(1)), + niftiMD5SUM(workflow.out.image_bet.get(0).get(1)), + niftiMD5SUM(workflow.out.mask_bet.get(0).get(1)), + workflow.out.crop_box, + niftiMD5SUM(workflow.out.mask_final.get(0).get(1)), + niftiMD5SUM(workflow.out.t1_final.get(0).get(1)), + workflow.out.versions + ).match()} ) } } @@ -123,6 +139,80 @@ nextflow_workflow { [ id:'test', single_end:false ], file("\${test_data_directory}/t1_unaligned.nii.gz") ]} + input[6] = ch_split_test_data.antsbet.map{ + test_data_directory -> [ + [ id:'test', single_end:false ], + [] + ]} + """ + } + } + + then { + assertAll( + { assert workflow.success}, + { assert snapshot( + niftiMD5SUM(workflow.out.image_nlmeans.get(0).get(1)), + niftiMD5SUM(workflow.out.image_N4.get(0).get(1)), + niftiMD5SUM(workflow.out.image_resample.get(0).get(1)), + niftiMD5SUM(workflow.out.image_bet.get(0).get(1)), + niftiMD5SUM(workflow.out.mask_bet.get(0).get(1)), + workflow.out.crop_box, + niftiMD5SUM(workflow.out.mask_final.get(0).get(1)), + niftiMD5SUM(workflow.out.t1_final.get(0).get(1)), + workflow.out.versions + ).match()} + ) + } + } + + test("preproc_t1_synthbet") { + config "./nextflow_synthbet.config" + + when { + workflow { + """ + ch_split_test_data = LOAD_DATA.out.test_data_directory + .branch{ + antsbet: it.simpleName == "antsbet" + others: it.simpleName == "others" + } + input[0] = ch_split_test_data.antsbet.map{ + test_data_directory -> [ + [ id:'test', single_end:false ], + file("\${test_data_directory}/t1_unaligned.nii.gz") + ]} + input[1] = ch_split_test_data.antsbet.map{ + test_data_directory -> [ + [ id:'test', single_end:false ], + [] + ]} + input[2] = ch_split_test_data.antsbet.map{ + test_data_directory -> [ + [ id:'test', single_end:false ], + [] + ]} + input[3] = ch_split_test_data.antsbet.map{ + test_data_directory -> [ + [ id:'test', single_end:false ], + [] + ]} + input[4] = ch_split_test_data.others.map{ + test_data_directory -> [ + [ id:'test', single_end:false ], + [], + [] + ]} + input[5] = ch_split_test_data.antsbet.map{ + test_data_directory -> [ + [ id:'test', single_end:false ], + [] + ]} + input[6] = ch_split_test_data.antsbet.map{ + test_data_directory -> [ + [ id:'test', single_end:false ], + [] + ]} """ } } @@ -130,7 +220,17 @@ nextflow_workflow { then { assertAll( { assert workflow.success}, - { assert snapshot(workflow.out).match()} + { assert snapshot( + niftiMD5SUM(workflow.out.image_nlmeans.get(0).get(1)), + niftiMD5SUM(workflow.out.image_N4.get(0).get(1)), + niftiMD5SUM(workflow.out.image_resample.get(0).get(1)), + niftiMD5SUM(workflow.out.image_bet.get(0).get(1)), + niftiMD5SUM(workflow.out.mask_bet.get(0).get(1)), + workflow.out.crop_box, + niftiMD5SUM(workflow.out.mask_final.get(0).get(1)), + niftiMD5SUM(workflow.out.t1_final.get(0).get(1)), + workflow.out.versions + ).match()} ) } }