Skip to content

Commit

Permalink
Merge pull request #7 from anroy1/synthregistration
Browse files Browse the repository at this point in the history
[New module] Freesurfer synthregistration
  • Loading branch information
AlexVCaron authored Oct 2, 2024
2 parents 28d2a37 + 94ff19d commit 8ac6fc4
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/run_checks_suite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ jobs:
path: modules/nf-neuro/registration/easyreg
- runner: scilus-nf-neuro-bigmem-runners
path: modules/nf-neuro/segmentation/synthseg
- runner: scilus-nf-neuro-bigmem-runners
path: modules/nf-neuro/registration/synthregistration
exclude:
- path: subworkflows/nf-neuro/load_test_data
uses: ./.github/workflows/test_component.yml
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
channels: []
dependencies: []
name: registration_synthregistration
63 changes: 63 additions & 0 deletions modules/nf-neuro/registration/synthregistration/main.nf
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
process REGISTRATION_SYNTHREGISTRATION {
tag "$meta.id"
label 'process_single'

container "freesurfer/synthmorph:3"
containerOptions "--entrypoint ''"

input:
tuple val(meta), path(moving), path(fixed)

output:
tuple val(meta), path("*__output_warped.nii.gz"), emit: warped_image
tuple val(meta), path("*__affine_warp.lta"), emit: affine_transform
tuple val(meta), path("*__deform_warp.nii.gz"), emit: deform_transform
path "versions.yml" , emit: versions

when:
task.ext.when == null || task.ext.when

script:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"

def affine = task.ext.affine ? "-m " + task.ext.affine : "-m affine"
def warp = task.ext.warp ? "-m " + task.ext.warp : "-m deform"
def header = task.ext.header ? "-H" : ""
def gpu = task.ext.gpu ? "-g" : ""
def lambda = task.ext.lambda ? "-r " + task.ext.lambda : ""
def steps = task.ext.steps ? "-n " + task.ext.steps : ""
def extent = task.ext.extent ? "-e " + task.ext.extent : ""
def weight = task.ext.weight ? "-w " + task.ext.weight : ""

"""
export ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=1
export OMP_NUM_THREADS=1
export OPENBLAS_NUM_THREADS=1
mri_synthmorph -j $task.cpus ${affine} -t ${prefix}__affine_warp.lta $moving $fixed
mri_synthmorph -j $task.cpus ${warp} ${gpu} ${lambda} ${steps} ${extent} ${weight} -i ${prefix}__affine_warp.lta -t ${prefix}__deform_warp.nii.gz -o ${prefix}__output_warped.nii.gz $moving $fixed
cat <<-END_VERSIONS > versions.yml
"${task.process}":
Freesurfer: 7.4
END_VERSIONS
"""

stub:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"

"""
mri_synthmorph -h
touch ${prefix}__output_warped.nii.gz
touch ${prefix}__affine_warp.lta
touch ${prefix}__deform_warp.nii.gz
cat <<-END_VERSIONS > versions.yml
"${task.process}":
Freesurfer: 7.4
END_VERSIONS
"""
}
61 changes: 61 additions & 0 deletions modules/nf-neuro/registration/synthregistration/meta.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
name: "registration_synthregistration"
description: Perform registration using SynthMorph from Freesurfer. Outputs transforms in Freesurfer format .lta for affine and .nii.gz (synthmorph also supports .mgz) for deform, both in RAS orientation. Conversion to other formats is done using lta_convert and mri_warp_convert respectively, which support a wide range of conversion formats and orientations, such as ANTs ans FSL. To convert the output of this module, use the registration/convert module successively to it. Note that tests using synthmorph are non-reproductible.
keywords:
- Registration
- Brain imaging
- MRI
- Synthetic
- AI
- CNN
tools:
- "Freesurfer":
description: "Freesurfer Synthmorph"
homepage: "https://martinos.org/malte/synthmorph/"

input:
- meta:
type: map
description: |
Groovy Map containing sample information
e.g. `[ id:'test', single_end:false ]`
- moving:
type: file
description: Nifti volume moving for registration
pattern: "*.{nii,nii.gz}"

- fixed:
type: file
description: Nifti volume fixed for registration
pattern: "*.{nii,nii.gz}"

output:
- meta:
type: map
description: |
Groovy Map containing sample information
e.g. `[ id:'test', single_end:false ]`
- affine_transform:
type: file
description: Affine transform for initialization
pattern: "*.{lta}"

- deform_transform:
type: file
description: Deform transformation
pattern: "*.{nii.gz}"

- warped_image:
type: file
description: Warped image
pattern: "*.{nii,.nii.gz}"

- versions:
type: file
description: File containing software versions
pattern: "versions.yml"

authors:
- "@anroy1"
56 changes: 56 additions & 0 deletions modules/nf-neuro/registration/synthregistration/tests/main.nf.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
nextflow_process {

name "Test Process REGISTRATION_SYNTHREGISTRATION"
script "../main.nf"
process "REGISTRATION_SYNTHREGISTRATION"

tag "modules"
tag "modules_nfcore"
tag "registration"
tag "registration/synthregistration"

tag "subworkflows"
tag "subworkflows/load_test_data"

// ** Assertion only uses file name since there is a discrepancy when tests are ran remotly. ** //
// ** Synthmorph is an AI model and freesurfer does not control for randomness in computation yet, both in terms of seeding and operation ordering.** //

setup {
run("LOAD_TEST_DATA", alias: "LOAD_DATA") {
script "../../../../../subworkflows/nf-neuro/load_test_data/main.nf"
process {
"""
input[0] = Channel.from( [ "processing.zip" ] )
input[1] = "test.load-test-data"
"""
}
}
}

test("registration - synthregistration") {
config "./nextflow.config"
when {
process {
"""
input[0] = LOAD_DATA.out.test_data_directory
.map{ test_data_directory -> [
[ id:'test', single_end:false ],
file("\${test_data_directory}/mni_masked_2x2x2.nii.gz"),
file("\${test_data_directory}/b0_mean.nii.gz")
]}
"""
}
}
then {
assertAll(
{ assert process.success },
{ assert snapshot(
file(process.out.warped_image.get(0).get(1)).name,
file(process.out.affine_transform.get(0).get(1)).name,
file(process.out.deform_transform.get(0).get(1)).name,
process.out.versions
).match() }
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"registration - synthregistration": {
"content": [
"test__output_warped.nii.gz",
"test__affine_warp.lta",
"test__deform_warp.nii.gz",
[
"versions.yml:md5,49fb9c85da9f696926d1ab46ef0968fb"
]
],
"meta": {
"nf-test": "0.9.0",
"nextflow": "24.04.4"
},
"timestamp": "2024-10-01T22:36:18.972035"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
process {
memory = "20G"
withName: "REGISTRATION_SYNTHREGISTRATION" {
publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" }
ext.affine = "affine"
ext.warp = "deform"
ext.lambda = 0.9
ext.steps = 9
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
registration/synthregistration:
- "modules/nf-neuro/registration/synthregistration/**"

0 comments on commit 8ac6fc4

Please sign in to comment.