Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 13 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,53 +21,33 @@

## Introduction

**nf-core/lsmquant** is a bioinformatics pipeline that performs preprocessing and analysis of light-sheet microscopy images of tissue cleared samples. The pipeline takes 2D single-channel 16-bit `.tif` images as input. The preprocessing consists of intesity adjustment, channel alignment, and tile stitching to reconstruct the 3D image. For mousebrain samples it offers a registration to the Allen Mouse Brain Reference Atlas for precise region annotation. Cell nuclei quantification is perfomed on the nuclear channel by a 3D-Unet.
**nf-core/lsmquant** is a bioinformatics pipeline that performs preprocessing and analysis of light-sheet microscopy images of tissue cleared samples. The pipeline takes raw images from a directory or a zip archive as input. The images need to be in a 2D single-channel 16-bit `tif`format.

<div style="text-align: center;">
<img src="docs/images/lsmquant-metromap.svg" alt="lasmquant metromap">
</div>

## Basic workflow

**Preprocessing**

1. Intensity Adjustment
2. Channel Alignment
3. Iterative Stitching

**ARA Registration**

4. ARA Registration subworkflow (optional)
5. Cell Nuclei Quantification

**Full**

1. Preprocessing
2. Nuclei quantification

## Pipeline Summary

The pipeline consists of two major workflows `preprocessing` and the `full` workflow. The `ara-regsitration` is an optional subworkflow that works only for whole mouse brain samples.
The pipeline consists of 3 major components: Preprocessing, Cell-Nuclei quantification, and Allen Reference Atlas registration. A detailed explanation on each method can be found in the [Methods description](./docs/usage.md) section.

### Preprocessing
**Preprocessing**

Preprocessing is performed on raw 2D single-channel 16-bit `.tif` images produced by a light sheet microscope. Three individual steps are performed:
This stage reconstructs the 3D image from raw light-sheet data. Here two different workflows can be chosen:

- **Intensity adjustments** to correct for the Gaussian shape of the lightsheet and intensity differences between adjacent tiles
- **Image channel alignment** using a 2D rigid approach or a nonlinear 3D approach using Elastix.
- **Image tile stitching** via an iterative 2D stitching approach by calculating z displacements and xy translations using phase correlation and SIFT.
1. `align_stitch` for multi-channel brain images: \
Performs intensity adjustment, channel alignment, and iterative tile stitching

### Full
2. `stitch` for single-channel images: \
Performs intensity adjustment and interactive tile stitching.

Quantification of cell-nuclei is performed using a 3D-Unet. It is performed on the nuclear channel only, assuming that the corresponding image file names contain the pattern `C1`.
**Allen Brain Atlas Registration (Optional)**

### ARA Registration
This workflow registers full brain images to the Allen Brain Reference Atlas. This is an optional workflow and can be chosen by setting the parameter: `ara_registartion`

Optional registration to the Allen Reference Atlas (ARA) for functional brain region annotation can be perfomed before segmentation.
This includes the following two steps:
**Cell Nuclei Quantification**

- Downsampling of the high resolution stitched images
- Registration to the ARA
Quantification of cell-nuclei is performed using a 3D-Unet and it is performed on the nuclear channel only. This is an optional workflow and can be chosen by setting the parameter:`nuclei_quantification`

## Usage

Expand Down Expand Up @@ -130,7 +110,7 @@ We thank the following people for their extensive assistance in the development
[Mark Polster](https://github.com/mapo9)\
[Susi Jo](https://github.com/SusiJo)\
[Luis Kuhn Cuellar](https://github.com/luiskuhn)\
[Daniel Straub](https://github.com/d4straub)
[Daniel Straub](https://github.com/d4straub)\
[Tatiana Woller](https://github.com/tatianawoller)\
[Niklas Grote](https://github.com/HomoPolyethylen)\
Jason Stein\
Expand Down
3 changes: 2 additions & 1 deletion conf/test.config
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ params {
config_profile_name = 'Test profile'
config_profile_description = 'Minimal test dataset to check pipeline function'
input = params.pipelines_testdata_base_path + '/test_data/samplesheets/sample_sheet.csv'
stage = 'full'
stage = 'align_stitch'
nuclei_quantification = true
}
3 changes: 2 additions & 1 deletion conf/test_full.config
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ params {
config_profile_name = 'Full test profile'
config_profile_description = 'Full test dataset to check pipeline function'
input = params.pipelines_testdata_base_path + '/test_data/samplesheets/sample_sheet.csv'
stage = 'full'
stage = 'align_stitch'
nuclei_quantification = true
}
12 changes: 10 additions & 2 deletions modules/local/numorphstitch/main.nf
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,20 @@ process NUMORPHSTITCH {
script:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"
def alignment_table = alignment_table_mat.name ? alignment_table_mat : ''
def z_displacement_align = z_displacement_align_mat ? z_displacement_align_mat : ''
"""

mkdir -p results/variables/

ln -sr ${alignment_table_mat} results/variables
ln -sr ${z_displacement_align_mat} results/variables
if [ -n "${alignment_table}" ]; then
ln -sr ${alignment_table} results/variables/
fi

if [ -n "${z_displacement_align}" ]; then
ln -sr ${z_displacement_align} results/variables
fi

ln -sr ${thresholds_mat} results/variables
ln -sr ${adj_params_mat} results/variables
ln -sr ${path_table_mat} results/variables
Expand Down
15 changes: 8 additions & 7 deletions nextflow.config
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ params {

// Input options
input = null
stage = 'preprocessing'
stage = 'align_stitch'
ara_registration = false
nuclei_quantification = false
model_file = 'https://zenodo.org/records/16893708/files/075_121_model.h5' // Path to the pre-trained model file


// MultiQC options
multiqc_config = null
multiqc_title = null
multiqc_logo = null
max_multiqc_email_size = '25.MB'
multiqc_config = null
multiqc_title = null
multiqc_logo = null
max_multiqc_email_size = '25.MB'
multiqc_methods_description = null

// Boilerplate options
Expand All @@ -37,8 +38,8 @@ params {
version = false
pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/lsmquant/'
trace_report_suffix = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss')// Config options
config_profile_name = null
config_profile_description = null
config_profile_name = null
config_profile_description = null

custom_config_version = 'master'
custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}"
Expand Down
8 changes: 7 additions & 1 deletion nextflow_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"stage": {
"type": "string",
"description": "The stage of the pipeline to run.",
"help_text": "The stage of the pipeline to run. The pipeline has multiple stages that can be run separately or the complete pipeline can be run. Stages are: `full`, `preprocess`",
"help_text": "The stage of the pipeline to run. The pipeline has multiple stages that can be run separately or the complete pipeline can be run. Stages are: `stitch`, `align_stitch`",
"fa_icon": "fas fa-cogs"
},
"ara_registration": {
Expand All @@ -38,6 +38,12 @@
"help_text": "Performs Allen Reference Atlas registration of stitched images. This step is optional and can be skipped if the images are already registered.",
"fa_icon": "fas fa-file-image"
},
"nuclei_quantification": {
"type": "boolean",
"description": "Performs cell nuclei quantification using a pre-trained model.",
"help_text": "Performs cell nuclei quantification using a pre-trained model. This step is optional and can be skipped if not needed.",
"fa_icon": "fas fa-calculator"
},
"model_file": {
"type": "string",
"description": "Path to the pre-trained model file.",
Expand Down
2 changes: 1 addition & 1 deletion ro-crate-metadata.json

Large diffs are not rendered by default.

76 changes: 76 additions & 0 deletions subworkflows/local/numorph_stitch/main.nf
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
include { NUMORPHINTENSITY } from '../../../modules/local/numorphintensity/'
include { NUMORPHSTITCH } from '../../../modules/local/numorphstitch/'
include { MAT2JSON as MAT2JSON_INT } from '../../../modules/local/mat2json/'
include { MAT2JSON as MAT2JSON_STITCH } from '../../../modules/local/mat2json/'
include { softwareVersionsToYAML } from '../../../subworkflows/nf-core/utils_nfcore_pipeline/'

workflow NUMORPH_STITCH {

take:

samplesheet // channel: [ val(meta), path(img_directory), path(parameter_file) ]


main:

ch_versions = Channel.empty()

sample_meta = samplesheet.map { meta, img_dir, params -> meta }

NUMORPHINTENSITY (samplesheet)
def intensity_out = NUMORPHINTENSITY.out
ch_versions = ch_versions.mix(intensity_out.versions)

// Create a tuple channel with all mat files and appropriate meta
sample_meta.combine(NUMORPHINTENSITY.out.adj_params_mat)
.mix(
sample_meta.combine(NUMORPHINTENSITY.out.path_table_mat),
sample_meta.combine(NUMORPHINTENSITY.out.thresholds_mat),
sample_meta.combine(NUMORPHINTENSITY.out.NM_variables)
)
.set { mat_files_int}

// empty channels for alignment outputs
empty_align_table_mat = samplesheet.map {[]}
empty_z_displacement_align_mat = samplesheet.map {[]}

NUMORPHSTITCH (
samplesheet,
empty_align_table_mat,
empty_z_displacement_align_mat,
intensity_out.path_table_mat,
intensity_out.thresholds_mat,
intensity_out.adj_params_mat,
intensity_out.NM_variables
)

def stitch_out = NUMORPHSTITCH.out
ch_versions = ch_versions.mix(stitch_out.versions)

stitch_out.variables
.flatten()
.filter { file -> file.toString().endsWith('.mat') }
.combine(sample_meta)
.map {file, meta -> tuple(meta, file) }
.set { mat_files_stitch }

MAT2JSON_INT (mat_files_int, "intensity" )
MAT2JSON_STITCH (mat_files_stitch, "stitch" )
ch_versions = ch_versions.mix(MAT2JSON_INT.out.versions)

// Collate and save software versions
//
softwareVersionsToYAML(ch_versions)
.collectFile(
storeDir: "${params.outdir}/pipeline_info",
name: 'nf_core_' + 'lsmquant_software_' + 'mqc_' + 'versions.yml',
sort: true,
newLine: true
).set { ch_collated_versions }

emit:
stitched = stitch_out.stitched // channel: [ path(stitched_dir) ]
intensity_thresholds = intensity_out.thresholds_mat // channel: [path(thresholds_mat) ]
NM_variables = stitch_out.NM_variables // channel: [path(NM_variables) ]
versions = ch_collated_versions
}
47 changes: 47 additions & 0 deletions subworkflows/local/numorph_stitch/meta.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json
name: "numorph_stitch"
description: perform preprocessing with only intensity adjustment and stitching of 2D single channel single tile TIFF images.
keywords:
- intensity
- stitching
- tiff
components:
- numorphintensity
- numorphstitch
- mat2json
input:
- samplesheet:
type: tuple
description: |
The input channel containing the metadata, image directory and parameter file.
Structure: [ val(meta), path(img_directory), path(parameter_file)]
pattern: "*.{tif/tiff/csv}"
output:
- stitched:
type: path
description: |
Channel containing path to stitched Tiff files
Structure: [ val(meta), path(stitched) ]
pattern: "*.tif/tiff"
- intensity_thresholds:
type: file
description: |
Channel containing intensity threshold (MAT) file
Structure: path(thresholds_mat)
pattern: "*.mat"
- NM_variables:
type: file
description: |
Channel containing numorph processing parameter file (MAT)
Structure: path(NM_variables.mat)
pattern: "*.mat"
- versions:
type: file
description: |
File containing software versions
Structure: [ path(versions.yml) ]
pattern: "versions.yml"
authors:
- "@CaroAMN"
maintainers:
- "@CaroAMN"
64 changes: 64 additions & 0 deletions subworkflows/local/numorph_stitch/tests/main.nf.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
nextflow_workflow {

name "Test Subworkflow NUMORPH_STITCH"
script "../main.nf"
workflow "NUMORPH_STITCH"

tag "subworkflows"
tag "subworkflows_"
tag "subworkflows/numorph_stitch"
tag "numorph"
tag "numorph preprocessing"
tag "numorph intensity"
tag "numorph stitch"


test("Numorph intensity and stitch only") {

setup {
run ("UNZIP") {
script "../../../../modules/nf-core/unzip/main.nf"
process {
"""
input[0] = Channel.fromList([
tuple([ id:'TEST1'],
file('https://zenodo.org/records/14916478/files/ctip2_topro.zip'))
])
"""
}
}
}
when {
params {
outdir = "$outputDir"
}
workflow {
"""
input[0] = UNZIP.out.unzipped_archive.map { meta, unzipped_archive ->
tuple(
meta,
unzipped_archive,
file(params.pipelines_testdata_base_path + '/test_data/parameterfiles/params_TEST1_lsmquant.csv'))
}
"""
}
}

then {
def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}'])
def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'subworkflows/local/numorph_preprocessing/tests/.nftignore')
assert workflow.success
assertAll(
{ assert snapshot(
// Number of successful tasks
workflow.trace.succeeded().size(),
removeNextflowVersion("$outputDir/pipeline_info/nf_core_lsmquant_software_mqc_versions.yml"),
// All stable path name, with a relative path
stable_name.isEmpty() ? 'No stable paths' : stable_name,
// All files with stable contents
stable_path
).match()}
)
}
}
}
Loading
Loading