diff --git a/modules/nf-scil/segmentation/fastseg/main.nf b/modules/nf-scil/segmentation/fastseg/main.nf index 73ccba00..9bf3a44c 100644 --- a/modules/nf-scil/segmentation/fastseg/main.nf +++ b/modules/nf-scil/segmentation/fastseg/main.nf @@ -7,7 +7,7 @@ process SEGMENTATION_FASTSEG { 'scilus/scilus:2.0.2' }" input: - tuple val(meta), path(image), path(lesion) + tuple val(meta), path(image), path(lesion) /* optional, input = [] */ output: tuple val(meta), path("*mask_wm.nii.gz") , emit: wm_mask diff --git a/subworkflows/nf-scil/anatomical_segmentation/main.nf b/subworkflows/nf-scil/anatomical_segmentation/main.nf index 755a0b51..3cd45d05 100644 --- a/subworkflows/nf-scil/anatomical_segmentation/main.nf +++ b/subworkflows/nf-scil/anatomical_segmentation/main.nf @@ -1,6 +1,9 @@ // ** Importing modules from nf-scil ** // include { SEGMENTATION_FASTSEG } from '../../../modules/nf-scil/segmentation/fastseg/main' include { SEGMENTATION_FREESURFERSEG } from '../../../modules/nf-scil/segmentation/freesurferseg/main' +include { SEGMENTATION_SYNTHSEG } from '../../../modules/nf-scil/segmentation/synthseg/main' + +params.run_synthseg = params.run_synthseg ?: false workflow ANATOMICAL_SEGMENTATION { @@ -15,6 +18,10 @@ workflow ANATOMICAL_SEGMENTATION { ch_versions = Channel.empty() + if ( ch_image && ch_freesurferseg ) { + error('Both input channels cannot be passed simultaneously') + } + if ( ch_freesurferseg ) { // ** Freesurfer segmentation ** // SEGMENTATION_FREESURFERSEG ( ch_freesurferseg ) @@ -28,18 +35,35 @@ workflow ANATOMICAL_SEGMENTATION { gm_map = Channel.empty() csf_map = Channel.empty() } + else { - // ** FSL fast segmentation ** // - SEGMENTATION_FASTSEG ( ch_image ) - ch_versions = ch_versions.mix(SEGMENTATION_FASTSEG.out.versions.first()) + if ( params.run_synthseg ) { + // ** Freesurfer synthseg segmentation ** // + SEGMENTATION_SYNTHSEG ( ch_image ) + ch_versions = ch_versions.mix(SEGMENTATION_SYNTHSEG.out.versions.first()) - // ** Setting outputs ** // - wm_mask = SEGMENTATION_FASTSEG.out.wm_mask - gm_mask = SEGMENTATION_FASTSEG.out.gm_mask - csf_mask = SEGMENTATION_FASTSEG.out.csf_mask - wm_map = SEGMENTATION_FASTSEG.out.wm_map - gm_map = SEGMENTATION_FASTSEG.out.gm_map - csf_map = SEGMENTATION_FASTSEG.out.csf_map + // ** Setting outputs ** // + wm_mask = SEGMENTATION_SYNTHSEG.out.wm_mask + gm_mask = SEGMENTATION_SYNTHSEG.out.gm_mask + csf_mask = SEGMENTATION_SYNTHSEG.out.csf_mask + wm_map = Channel.empty() + gm_map = Channel.empty() + csf_map = Channel.empty() + } + + else { + // ** FSL fast segmentation ** // + SEGMENTATION_FASTSEG ( ch_image ) + ch_versions = ch_versions.mix(SEGMENTATION_FASTSEG.out.versions.first()) + + // ** Setting outputs ** // + wm_mask = SEGMENTATION_FASTSEG.out.wm_mask + gm_mask = SEGMENTATION_FASTSEG.out.gm_mask + csf_mask = SEGMENTATION_FASTSEG.out.csf_mask + wm_map = SEGMENTATION_FASTSEG.out.wm_map + gm_map = SEGMENTATION_FASTSEG.out.gm_map + csf_map = SEGMENTATION_FASTSEG.out.csf_map + } } emit: diff --git a/subworkflows/nf-scil/anatomical_segmentation/meta.yml b/subworkflows/nf-scil/anatomical_segmentation/meta.yml index a1f29a12..aba9145a 100644 --- a/subworkflows/nf-scil/anatomical_segmentation/meta.yml +++ b/subworkflows/nf-scil/anatomical_segmentation/meta.yml @@ -7,6 +7,8 @@ description: | and CSF masks/maps. 2) Channel with FreeSurfer's parcellations files will result in using Scilpy's tools to produce WM, GM, and CSF masks (probability maps are not produced with this option). + 3) Given the synthseg related parameter in entry, will use synthseg instead of FSL FAST, producing + WM, GM and CSF masks. Typical next steps after this subworkflow would be to combine the resulting masks/maps with fODF data to perform TRACKING. keywords: @@ -17,6 +19,7 @@ keywords: components: - segmentation/fastseg - segmentation/freesurferseg + - segmentation/synthseg input: - ch_image: type: file @@ -33,6 +36,12 @@ input: parcellations into masks. Structure: [ val(meta), path(aparc_aseg), path(wm_parc) ] pattern: "*.mgz" + - ch_lesion: + type: file + description: | + The optional input channel containing a Nifti lesion volume to correct the white matter with a lesion mask. The lesion mask must be a binary masks. + Structure: [ val(meta), path(image) ] + pattern: "*.{nii,nii.gz}" output: - wm_mask: type: file @@ -59,21 +68,21 @@ output: type: file description: | Channel containing WM probability maps. Will be only outputted if FSL's fast segmentation - is used and not with FreeSurfer's parcellation files. + is used and not with Synthseg and FreeSurfer's parcellation files. Structure: [ val(meta), path(wm_maps) ] pattern: "*.{nii,nii.gz}" - gm_maps: type: file description: | Channel containing GM probability maps. Will be only outputted if FSL's fast segmentation - is used and not with FreeSurfer's parcellation files. + is used and not with Synthseg and FreeSurfer's parcellation files. Structure: [ val(meta), path(gm_maps) ] pattern: "*.{nii,nii.gz}" - csf_maps: type: file description: | Channel containing CSF probability maps. Will be only outputted if FSL's fast segmentation - is used and not with FreeSurfer's parcellation files. + is used and not with Synthseg and FreeSurfer's parcellation files. Structure: [ val(meta), path(csf_maps) ] pattern: "*.{nii,nii.gz}" - versions: diff --git a/subworkflows/nf-scil/anatomical_segmentation/tests/main.nf.test b/subworkflows/nf-scil/anatomical_segmentation/tests/main.nf.test index b3836084..f34ed8ef 100644 --- a/subworkflows/nf-scil/anatomical_segmentation/tests/main.nf.test +++ b/subworkflows/nf-scil/anatomical_segmentation/tests/main.nf.test @@ -3,7 +3,6 @@ nextflow_workflow { name "Test Subworkflow ANATOMICAL_SEGMENTATION" script "../main.nf" workflow "ANATOMICAL_SEGMENTATION" - config "./nextflow.config" tag "subworkflows" tag "subworkflows_nfcore" @@ -12,6 +11,7 @@ nextflow_workflow { tag "segmentation" tag "segmentation/fastseg" tag "segmentation/freesurferseg" + tag "segmentation/synthseg" tag "load_test_data" @@ -28,16 +28,16 @@ nextflow_workflow { } test("anatomical_segmentation - fslfast") { - + config "./nextflow.config" when { workflow { """ ch_split_test_data = LOAD_DATA.out.test_data_directory .branch{ - t1w: it.simpleName == "T1w" + T1w: it.simpleName == "T1w" freesurfer: it.simpleName == "freesurfer_nifti" } - input[0] = ch_split_test_data.t1w.map{ + input[0] = ch_split_test_data.T1w.map{ test_data_directory -> [ [ id:'test' ], file("\${test_data_directory}/T1w.nii.gz", checkIfExists: true), @@ -51,19 +51,27 @@ nextflow_workflow { then { assertAll( { assert workflow.success}, - { assert snapshot(workflow.out).match()} + { assert snapshot( + niftiMD5SUM(workflow.out.wm_mask.get(0).get(1)), + niftiMD5SUM(workflow.out.gm_mask.get(0).get(1)), + niftiMD5SUM(workflow.out.csf_mask.get(0).get(1)), + niftiMD5SUM(workflow.out.wm_map.get(0).get(1)), + niftiMD5SUM(workflow.out.gm_map.get(0).get(1)), + niftiMD5SUM(workflow.out.csf_map.get(0).get(1)), + workflow.out.versions + ).match()} ) } } test("anatomical_segmentation - freesurferseg") { - + config "./nextflow.config" when { workflow { """ ch_split_test_data = LOAD_DATA.out.test_data_directory .branch{ - t1w: it.simpleName == "T1w" + T1w: it.simpleName == "T1w" freesurfer: it.simpleName == "freesurfer_nifti" } input[0] = [] @@ -81,7 +89,46 @@ nextflow_workflow { then { assertAll( { assert workflow.success }, - { assert snapshot(workflow.out).match() } + { assert snapshot( + niftiMD5SUM(workflow.out.wm_mask.get(0).get(1)), + niftiMD5SUM(workflow.out.gm_mask.get(0).get(1)), + niftiMD5SUM(workflow.out.csf_mask.get(0).get(1)), + workflow.out.versions + ).match() } + ) + } + } + + test("anatomical_segmentation - synthseg") { + config "./nextflow_synthseg.config" + when { + workflow { + """ + ch_split_test_data = LOAD_DATA.out.test_data_directory + .branch{ + T1w: it.simpleName == "T1w" + freesurfer: it.simpleName == "freesurfer_nifti" + } + input[0] = ch_split_test_data.T1w.map{ + test_data_directory -> [ + [ id:'test', single_end:false ], // meta map + file("\${test_data_directory}/anat/anat_image.nii.gz", checkIfExists: true), + [] + ]} + input[1] = [] + """ + } + } + + then { + assertAll( + { assert workflow.success}, + { assert snapshot( + niftiMD5SUM(workflow.out.wm_mask.get(0).get(1)), + niftiMD5SUM(workflow.out.gm_mask.get(0).get(1)), + niftiMD5SUM(workflow.out.csf_mask.get(0).get(1)), + workflow.out.versions + ).match()} ) } } diff --git a/subworkflows/nf-scil/anatomical_segmentation/tests/nextflow_synthseg.config b/subworkflows/nf-scil/anatomical_segmentation/tests/nextflow_synthseg.config new file mode 100644 index 00000000..2ffd03ce --- /dev/null +++ b/subworkflows/nf-scil/anatomical_segmentation/tests/nextflow_synthseg.config @@ -0,0 +1,9 @@ +process { + + publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } + +} + +params { + run_synthseg = true +}