patchworks 3.1.0__tar.gz → 3.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {patchworks-3.1.0 → patchworks-3.2.0}/PKG-INFO +12 -1
- {patchworks-3.1.0 → patchworks-3.2.0}/README.md +8 -0
- patchworks-3.2.0/docs/api/plugins/careamics.md +11 -0
- patchworks-3.2.0/docs/api/plugins/plantseg.md +11 -0
- patchworks-3.2.0/docs/api/plugins/watershed.md +11 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/guide/cli.md +10 -1
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/guide/custom_segmentation.md +8 -0
- patchworks-3.2.0/docs/guide/membrane_cells.md +253 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/guide/snakemake.md +18 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/mkdocs.yml +4 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/pyproject.toml +7 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/cli.py +65 -0
- patchworks-3.2.0/src/patchworks/plugins/careamics.py +381 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/plugins/napari.py +22 -0
- patchworks-3.2.0/src/patchworks/plugins/plantseg.py +488 -0
- patchworks-3.2.0/src/patchworks/plugins/watershed.py +403 -0
- patchworks-3.2.0/tests/test_careamics.py +170 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_napari.py +27 -0
- patchworks-3.2.0/tests/test_plantseg.py +175 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_pw.py +242 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_run_multi.py +172 -5
- patchworks-3.2.0/tests/test_watershed.py +124 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/config/config.yaml +18 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/config/config_cyto.yaml +12 -0
- patchworks-3.2.0/workflow/config/config_cyto_plantseg.yaml +51 -0
- patchworks-3.2.0/workflow/config/multi_plantseg.yaml +33 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/pixi.toml +52 -5
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/scripts/_pw.py +205 -7
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/scripts/merge.py +2 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/scripts/prepare_tiles.py +5 -1
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/scripts/run_multi.py +95 -19
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/scripts/segment_tile.py +8 -2
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/scripts/view.py +13 -1
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/viewer/pixi.toml +12 -4
- {patchworks-3.1.0 → patchworks-3.2.0}/.github/min-versions.txt +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/.github/workflows/docs.yml +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/.github/workflows/lint.yml +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/.github/workflows/release.yml +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/.github/workflows/test.yml +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/.gitignore +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/.markdownlint-cli2.yaml +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/.pre-commit-config.yaml +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/LICENSE +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/benchmarks/bench.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/benchmarks/compare.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/cliff.toml +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/api/chunks.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/api/cluster.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/api/io.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/api/merge_tile_labels.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/api/plugins/cellpose.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/api/plugins/dog.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/api/plugins/napari.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/api/plugins/ome_zarr.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/api/postprocess.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/api/provenance.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/api/relabel.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/api/review.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/api/seams.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/api/tile_process.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/api/volume_filter.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/assets/logo.png +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/assets/review_panel.png +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/assets/review_position.png +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/examples/cellpose_2d.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/examples/cellpose_2d.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/examples/cellpose_3d.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/examples/cellpose_3d.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/examples/custom.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/examples/custom_method.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/examples/dog.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/examples/dog.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/examples/standalone_merge.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/examples/stardist.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/examples/stardist_2d.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/getting_started.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/guide/gpu_distributed.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/guide/label_relations.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/guide/launcher.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/guide/measurements.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/guide/merging.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/guide/ome_zarr_napari.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/guide/performance.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/guide/pitfalls.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/guide/review.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/guide/skip_empty.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/guide/tiling.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/docs/index.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/__init__.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_autotune.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_chunks.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_cluster.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_core.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_distributed.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_gpu.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_io.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_merge.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_notify.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_occupancy.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_postprocess.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_progress.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_provenance.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_relabel.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_relations.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_review.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_seams.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_tables.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/_volume_filter.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/plugins/__init__.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/plugins/cellpose.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/plugins/dog.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/plugins/ome_zarr.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/plugins/review.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/src/patchworks/py.typed +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/ngff_schemas/0.4/image.schema +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/ngff_schemas/0.4/label.schema +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/ngff_schemas/0.4/ome.schema +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/ngff_schemas/0.5/_version.schema +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/ngff_schemas/0.5/image.schema +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/ngff_schemas/0.5/label.schema +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/ngff_schemas/0.5/ome.schema +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/ngff_schemas/README.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_allocation.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_autotune.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_cellpose.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_cli.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_core.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_distributed.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_dog.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_gpu.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_launcher.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_notify.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_occupancy.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_ome_zarr.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_position.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_postprocess.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_progress.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_relations.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_remote.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_review.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_review_napari.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_seams.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_tables.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/tests/test_volume_filter.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/README.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/Snakefile +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/config/common.yaml +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/config/config_cilia.yaml +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/config/config_nuclei.yaml +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/config/multi.yaml +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/launcher/README.md +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/launcher/app.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/launcher/clusters.yaml +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/launcher/launcher_core.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/launcher/requirements.txt +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/profile/slurm/config.yaml +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/rules/common.smk +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/rules/convert.smk +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/rules/merge.smk +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/rules/segment.smk +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/scripts/build_occupancy.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/scripts/convert.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/scripts/export_iso.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/scripts/fetch_model.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/scripts/relate.py +0 -0
- {patchworks-3.1.0 → patchworks-3.2.0}/workflow/scripts/reshard_store.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: patchworks
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: Tiled processing of arbitrarily large images with globally consistent labels
|
|
5
5
|
Project-URL: Homepage, https://github.com/imcf/patchworks
|
|
6
6
|
Project-URL: Issues, https://github.com/imcf/patchworks/issues
|
|
@@ -52,6 +52,8 @@ Requires-Dist: bioio-lif; extra == 'bioio'
|
|
|
52
52
|
Requires-Dist: bioio-nd2; extra == 'bioio'
|
|
53
53
|
Requires-Dist: bioio-ome-tiff; extra == 'bioio'
|
|
54
54
|
Requires-Dist: bioio-tifffile; extra == 'bioio'
|
|
55
|
+
Provides-Extra: careamics
|
|
56
|
+
Requires-Dist: careamics>=0.3; extra == 'careamics'
|
|
55
57
|
Provides-Extra: cellpose
|
|
56
58
|
Requires-Dist: cellpose>=3.0; extra == 'cellpose'
|
|
57
59
|
Provides-Extra: cellpose3
|
|
@@ -99,6 +101,7 @@ Requires-Dist: pandas>=2.0; extra == 'review'
|
|
|
99
101
|
Provides-Extra: workflow
|
|
100
102
|
Requires-Dist: openpyxl; extra == 'workflow'
|
|
101
103
|
Requires-Dist: pandas>=2.0; extra == 'workflow'
|
|
104
|
+
Requires-Dist: scikit-image; extra == 'workflow'
|
|
102
105
|
Requires-Dist: snakemake-executor-plugin-slurm; extra == 'workflow'
|
|
103
106
|
Requires-Dist: snakemake>=8; extra == 'workflow'
|
|
104
107
|
Description-Content-Type: text/markdown
|
|
@@ -154,6 +157,7 @@ pip install "patchworks[cellpose]" # Cellpose plugin (>=3.0, v3 or v4)
|
|
|
154
157
|
pip install "patchworks[cellpose3]" # Cellpose plugin, pinned to v3.x
|
|
155
158
|
pip install "patchworks[cellpose4]" # Cellpose plugin, pinned to v4+
|
|
156
159
|
pip install "patchworks[dog]" # deconvolution + DoG plugin (pycudadecon)
|
|
160
|
+
pip install "patchworks[careamics]" # Noise2Void denoising before segmenting
|
|
157
161
|
pip install "patchworks[bioio]" # convert any image format to OME-ZARR
|
|
158
162
|
pip install "patchworks[imaris]" # convert Imaris .ims files to OME-ZARR
|
|
159
163
|
pip install "patchworks[napari]" # interactive napari viewer plugin
|
|
@@ -457,6 +461,13 @@ Optional:
|
|
|
457
461
|
- `cellpose` — Cellpose plugin, v3 or v4 (`patchworks[cellpose]`);
|
|
458
462
|
pin with `[cellpose3]` or `[cellpose4]`
|
|
459
463
|
- `pycudadecon` — deconvolution step of the `dog` plugin (`patchworks[dog]`)
|
|
464
|
+
- `careamics` — denoise tiles before segmenting them (Noise2Void),
|
|
465
|
+
`patchworks[careamics]`
|
|
466
|
+
- `plant-seg` — PlantSeg plugin (boundary U-Net + GASP/multicut), from
|
|
467
|
+
conda-forge only (`conda install -c conda-forge plant-seg`, or the
|
|
468
|
+
workflow's `pixi install -e plantseg`). The nuclei-seeded watershed plugin
|
|
469
|
+
needs only scikit-image. See the
|
|
470
|
+
[membrane cells guide](https://imcf.one/patchworks/guide/membrane_cells/).
|
|
460
471
|
- `bioio` + readers — convert CZI/LIF/ND2/OME-TIFF/… to OME-ZARR
|
|
461
472
|
(`patchworks[bioio]`)
|
|
462
473
|
- `imaris-ims-file-reader` — convert Imaris `.ims` (`patchworks[imaris]`)
|
|
@@ -49,6 +49,7 @@ pip install "patchworks[cellpose]" # Cellpose plugin (>=3.0, v3 or v4)
|
|
|
49
49
|
pip install "patchworks[cellpose3]" # Cellpose plugin, pinned to v3.x
|
|
50
50
|
pip install "patchworks[cellpose4]" # Cellpose plugin, pinned to v4+
|
|
51
51
|
pip install "patchworks[dog]" # deconvolution + DoG plugin (pycudadecon)
|
|
52
|
+
pip install "patchworks[careamics]" # Noise2Void denoising before segmenting
|
|
52
53
|
pip install "patchworks[bioio]" # convert any image format to OME-ZARR
|
|
53
54
|
pip install "patchworks[imaris]" # convert Imaris .ims files to OME-ZARR
|
|
54
55
|
pip install "patchworks[napari]" # interactive napari viewer plugin
|
|
@@ -352,6 +353,13 @@ Optional:
|
|
|
352
353
|
- `cellpose` — Cellpose plugin, v3 or v4 (`patchworks[cellpose]`);
|
|
353
354
|
pin with `[cellpose3]` or `[cellpose4]`
|
|
354
355
|
- `pycudadecon` — deconvolution step of the `dog` plugin (`patchworks[dog]`)
|
|
356
|
+
- `careamics` — denoise tiles before segmenting them (Noise2Void),
|
|
357
|
+
`patchworks[careamics]`
|
|
358
|
+
- `plant-seg` — PlantSeg plugin (boundary U-Net + GASP/multicut), from
|
|
359
|
+
conda-forge only (`conda install -c conda-forge plant-seg`, or the
|
|
360
|
+
workflow's `pixi install -e plantseg`). The nuclei-seeded watershed plugin
|
|
361
|
+
needs only scikit-image. See the
|
|
362
|
+
[membrane cells guide](https://imcf.one/patchworks/guide/membrane_cells/).
|
|
355
363
|
- `bioio` + readers — convert CZI/LIF/ND2/OME-TIFF/… to OME-ZARR
|
|
356
364
|
(`patchworks[bioio]`)
|
|
357
365
|
- `imaris-ims-file-reader` — convert Imaris `.ims` (`patchworks[imaris]`)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# CAREamics denoising plugin
|
|
2
|
+
|
|
3
|
+
See [Denoising first](../../guide/membrane_cells.md#denoising-first-careamics).
|
|
4
|
+
|
|
5
|
+
::: patchworks.plugins.careamics.denoise_fn
|
|
6
|
+
|
|
7
|
+
::: patchworks.plugins.careamics.denoise
|
|
8
|
+
|
|
9
|
+
::: patchworks.plugins.careamics.train_n2v
|
|
10
|
+
|
|
11
|
+
::: patchworks.plugins.careamics.training_crops
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# PlantSeg plugin
|
|
2
|
+
|
|
3
|
+
See [Cells from a membrane stain](../../guide/membrane_cells.md#plantseg).
|
|
4
|
+
|
|
5
|
+
::: patchworks.plugins.plantseg.plantseg_fn
|
|
6
|
+
|
|
7
|
+
::: patchworks.plugins.plantseg.fetch_model
|
|
8
|
+
|
|
9
|
+
::: patchworks.plugins.plantseg.available_models
|
|
10
|
+
|
|
11
|
+
::: patchworks.plugins.plantseg.rescale_factors
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Nuclei-seeded watershed plugin
|
|
2
|
+
|
|
3
|
+
See [Cells from a membrane stain](../../guide/membrane_cells.md).
|
|
4
|
+
|
|
5
|
+
::: patchworks.plugins.watershed.watershed_fn
|
|
6
|
+
|
|
7
|
+
::: patchworks.plugins.watershed.nuclei_seeds
|
|
8
|
+
|
|
9
|
+
::: patchworks.plugins.watershed.foreground_mask
|
|
10
|
+
|
|
11
|
+
::: patchworks.plugins.watershed.seeded_watershed
|
|
@@ -46,7 +46,16 @@ gives a child touching no parent the nearest one. See
|
|
|
46
46
|
| `custom` | any importable function | `--fn module:function`, `--fn-kwargs '{"k": 1}'` |
|
|
47
47
|
|
|
48
48
|
Cellpose's anisotropy and the DoG plugin's voxel size are read from the
|
|
49
|
-
store's own calibration, at the level being segmented
|
|
49
|
+
store's own calibration, at the level being segmented -- as is `voxel_size`
|
|
50
|
+
for a custom function that takes one, such as the PlantSeg and watershed
|
|
51
|
+
plugins: `--method custom --fn patchworks.plugins.plantseg:segment
|
|
52
|
+
--fn-kwargs '{"segmentation": "gasp"}' --stitch iou` (`iou`: these fill
|
|
53
|
+
space, so neighbouring cells touch at every seam).
|
|
54
|
+
|
|
55
|
+
`--denoise MODEL` denoises every tile with a CAREamics model before any
|
|
56
|
+
method segments it; `patchworks denoise-train STORE --channel 0 --out
|
|
57
|
+
n2v.ckpt` trains one (Noise2Void, no ground truth). See
|
|
58
|
+
[Cells from a membrane stain](membrane_cells.md).
|
|
50
59
|
|
|
51
60
|
Tiling and stitching take the same options as
|
|
52
61
|
[`tile_process`](../api/tile_process.md): `--tile-shape` (`z,y,x`, `auto` or
|
|
@@ -29,6 +29,14 @@ That is the whole interface. Anything that turns an image tile into a label
|
|
|
29
29
|
image works: classic image processing, StarDist, a trained model, an external
|
|
30
30
|
binary you shell out to, …
|
|
31
31
|
|
|
32
|
+
Ready-made ones ship with patchworks: `patchworks.plugins.dog` (spots,
|
|
33
|
+
cilia), and for cells from a membrane stain `patchworks.plugins.watershed`
|
|
34
|
+
(nuclei-seeded watershed) and `patchworks.plugins.plantseg` (PlantSeg) --
|
|
35
|
+
see [Cells from a membrane stain](membrane_cells.md). With
|
|
36
|
+
`nuclei_channel` set, the tile is `(2, z, y, x)`: `[channel,
|
|
37
|
+
nuclei_channel]` on the first axis. Any method can also run on
|
|
38
|
+
[denoised tiles](membrane_cells.md#denoising-first-careamics).
|
|
39
|
+
|
|
32
40
|
## Minimal example (no GPU, no deps beyond scikit-image)
|
|
33
41
|
|
|
34
42
|
```python
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# Cells from a membrane stain
|
|
2
|
+
|
|
3
|
+
Epithelia, organoids and tissues are often imaged with a **membrane** (or
|
|
4
|
+
cortex) marker plus a **nuclear** dye. Cellpose struggles there in a
|
|
5
|
+
recognisable way: Cellpose 4 (`cpsam`) reads every channel it is given
|
|
6
|
+
without a "cytoplasm" or "nucleus" role, so with a bright nuclear channel
|
|
7
|
+
next to a faint membrane it segments the **nuclei**; and on the membrane
|
|
8
|
+
alone, a wall that is faint in places merges two cells. Patchworks ships
|
|
9
|
+
three plugins for this case, plus an optional denoising step in front of any
|
|
10
|
+
method.
|
|
11
|
+
|
|
12
|
+
| | Needs | Cells come from | Best when |
|
|
13
|
+
| --- | --- | --- | --- |
|
|
14
|
+
| [Nuclei-seeded watershed](#nuclei-seeded-watershed) | scikit-image | the membrane, flooded from the nuclei | every cell has one nucleus; start here |
|
|
15
|
+
| [PlantSeg](#plantseg) | `plant-seg` (conda-forge) | a boundary U-Net, then GASP / multicut | the membrane is uneven or noisy |
|
|
16
|
+
| [PlantSeg + nuclei](#plantseg) | same | the U-Net's boundaries and the nuclei | both of the above |
|
|
17
|
+
| Cellpose, membrane only | cellpose | Cellpose | `nuclei_channel: null`, `do_3D: true` |
|
|
18
|
+
| [Denoising first](#denoising-first-careamics) | `careamics` | any of these, on denoised tiles | noisy acquisitions |
|
|
19
|
+
|
|
20
|
+
All of them are ordinary [custom functions](custom_segmentation.md): one
|
|
21
|
+
config block, the same tiling, merge, tables and review as any other run.
|
|
22
|
+
|
|
23
|
+
## Nuclei-seeded watershed
|
|
24
|
+
|
|
25
|
+
The nuclei are the easy part of the image: bright, compact, separated. They
|
|
26
|
+
say how many cells there are and where; flooding the membrane image from
|
|
27
|
+
them grows each nucleus out to its cell's walls. A cell can then not be
|
|
28
|
+
split (one seed each) or merged with its neighbour (two seeds never join),
|
|
29
|
+
even across a gap in the wall.
|
|
30
|
+
|
|
31
|
+
```yaml
|
|
32
|
+
channel: 0 # membrane
|
|
33
|
+
nuclei_channel: 1 # stacked onto each tile as [membrane, nuclei]
|
|
34
|
+
method: "custom"
|
|
35
|
+
label_name: "cyto_labels"
|
|
36
|
+
stitch: "iou" # required: see below
|
|
37
|
+
custom:
|
|
38
|
+
module: "patchworks.plugins.watershed"
|
|
39
|
+
kwargs:
|
|
40
|
+
nuclei_min_size: 200 # voxels: specks smaller than a nucleus
|
|
41
|
+
foreground: "otsu" # stop at the tissue edge
|
|
42
|
+
# max_radius_um: 15 # or: no further than this from the nucleus
|
|
43
|
+
# nuclei_threshold: 800 # intensity, if Otsu misses dim nuclei
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`stitch: "iou"` is required with this plugin and with PlantSeg, and
|
|
47
|
+
`prepare` refuses the config without it. They give every voxel to some
|
|
48
|
+
cell, so neighbouring cells touch at every tile seam, and the default
|
|
49
|
+
`"touch"` stitching would join each such pair: on a test grid of 12 cells
|
|
50
|
+
cut by six tiles, 5 came out. `"iou"` joins two pieces only where both tiles
|
|
51
|
+
agree on their overlap, and gives the 12. (From the command line, pass
|
|
52
|
+
`--stitch iou` yourself: nothing checks it there.)
|
|
53
|
+
|
|
54
|
+
Two nuclei touching each other give one seed, so one cell for two: raise
|
|
55
|
+
`nuclei_threshold` if that happens -- or grow the cells from nuclei you have
|
|
56
|
+
already segmented, with `seed_labels` instead of `nuclei_channel` (see
|
|
57
|
+
[the example below](#how-seed_labels-works)). Each tile's halo (`overlap`) must hold a
|
|
58
|
+
whole cell, as for any method.
|
|
59
|
+
|
|
60
|
+
## PlantSeg
|
|
61
|
+
|
|
62
|
+
[PlantSeg](https://github.com/kreshuklab/plant-seg) predicts cell
|
|
63
|
+
boundaries with a 3-D U-Net trained on membrane stains, then partitions the
|
|
64
|
+
boundary map into cells (supervoxels by a distance-transform watershed,
|
|
65
|
+
merged by GASP, mutex watershed or multicut). A wall the U-Net sees at all
|
|
66
|
+
gets closed by the partitioning, where Cellpose would merge across it.
|
|
67
|
+
|
|
68
|
+
PlantSeg is on conda-forge only, so it has its own pixi environment:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pixi install -e plantseg
|
|
72
|
+
pixi run -e plantseg plantseg-fetch generic_confocal_3D_unet # once, with internet
|
|
73
|
+
pixi run -e plantseg multi-slurm
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```yaml
|
|
77
|
+
method: "custom"
|
|
78
|
+
stitch: "iou" # required, as for the watershed
|
|
79
|
+
custom:
|
|
80
|
+
module: "patchworks.plugins.plantseg"
|
|
81
|
+
kwargs:
|
|
82
|
+
model: "generic_confocal_3D_unet" # or generic_light_sheet_3D_unet, ...
|
|
83
|
+
segmentation: "gasp" # gasp | mutex_ws | multicut | dt_watershed
|
|
84
|
+
beta: 0.6 # lower merges more, higher splits more
|
|
85
|
+
foreground: "otsu" # a boundary U-Net puts cells everywhere
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
With `nuclei_channel` set, two more `segmentation` modes use the nuclei:
|
|
89
|
+
|
|
90
|
+
- `"nuclei_watershed"` -- the U-Net's boundary map flooded from the nuclei:
|
|
91
|
+
the watershed above, on a much cleaner boundary image.
|
|
92
|
+
- `"lifted_multicut"` -- PlantSeg's lifted multicut: supervoxels in one
|
|
93
|
+
nucleus pulled together, in different nuclei pushed apart.
|
|
94
|
+
|
|
95
|
+
Each tile is resampled to the voxel size the model was trained at (from the
|
|
96
|
+
image's own calibration, `rescale: true`), which matters more than any other
|
|
97
|
+
setting for a pretrained U-Net; the prediction is resampled back.
|
|
98
|
+
|
|
99
|
+
## Example: Cellpose nuclei + PlantSeg cells in one run
|
|
100
|
+
|
|
101
|
+
The workflow ships this pairing ready to edit: Cellpose segments the nuclei,
|
|
102
|
+
then PlantSeg grows the cells from **exactly those nuclei** -- one cell per
|
|
103
|
+
nucleus Cellpose found -- and the two are related. Three files, next to
|
|
104
|
+
`config/multi.yaml`:
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
# config/multi_plantseg.yaml
|
|
108
|
+
common: config/common.yaml # input, work_dir, tile_shape, level: shared
|
|
109
|
+
|
|
110
|
+
segmentations:
|
|
111
|
+
- config/config_nuclei.yaml # Cellpose "nuclei" model on channel 1
|
|
112
|
+
- config/config_cyto_plantseg.yaml # PlantSeg on channel 0, seeded by nuclei_labels
|
|
113
|
+
|
|
114
|
+
relations:
|
|
115
|
+
- a: nuclei_labels
|
|
116
|
+
b: cyto_labels
|
|
117
|
+
output: nuclei_to_cyto.xlsx
|
|
118
|
+
|
|
119
|
+
review: # a sanity check: one nucleus per cell
|
|
120
|
+
expect:
|
|
121
|
+
cyto_labels:
|
|
122
|
+
nuclei_labels: 1
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
```yaml
|
|
126
|
+
# config/config_nuclei.yaml (unchanged)
|
|
127
|
+
channel: 1
|
|
128
|
+
overlap: [4, 30, 30]
|
|
129
|
+
method: "cellpose"
|
|
130
|
+
label_name: "nuclei_labels"
|
|
131
|
+
cellpose:
|
|
132
|
+
model: "nuclei"
|
|
133
|
+
diameter: 15
|
|
134
|
+
do_3D: true
|
|
135
|
+
gpu: true
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
# config/config_cyto_plantseg.yaml
|
|
140
|
+
channel: 0 # membrane
|
|
141
|
+
seed_labels: "nuclei_labels" # each tile becomes [membrane, nuclei labels]
|
|
142
|
+
overlap: [4, 40, 40] # the halo must hold a whole cell
|
|
143
|
+
stitch: "iou" # cells touch at every seam: join on agreement only
|
|
144
|
+
method: "custom"
|
|
145
|
+
label_name: "cyto_labels"
|
|
146
|
+
custom:
|
|
147
|
+
module: "patchworks.plugins.plantseg"
|
|
148
|
+
function: "segment"
|
|
149
|
+
kwargs:
|
|
150
|
+
model: "generic_confocal_3D_unet" # generic_light_sheet_3D_unet for light-sheet
|
|
151
|
+
segmentation: "nuclei_watershed" # U-Net boundaries flooded from the nuclei
|
|
152
|
+
foreground: "otsu" # keep the tissue only
|
|
153
|
+
# max_radius_um: 15
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Set `input` and `work_dir` in `config/common.yaml`, then, from `workflow/`:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
pixi install -e plantseg
|
|
160
|
+
pixi run -e plantseg plantseg-fetch generic_confocal_3D_unet # once, with internet
|
|
161
|
+
pixi run -e plantseg multi-plantseg-dry # check the plan
|
|
162
|
+
pixi run -e plantseg multi-plantseg-slurm # submit
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The `plantseg` environment is the default one plus PlantSeg, so the
|
|
166
|
+
Cellpose run comes from it too. Afterwards, `nuclei_to_cyto.xlsx` gives
|
|
167
|
+
each nucleus its cell, and `pixi run -e viewer review <work_dir>/image.zarr`
|
|
168
|
+
lists any cell not holding exactly one nucleus.
|
|
169
|
+
|
|
170
|
+
### How `seed_labels` works
|
|
171
|
+
|
|
172
|
+
- **Order.** `run_multi` starts the cells' config only once the config
|
|
173
|
+
producing `nuclei_labels` has finished; everything else listed (cilia,
|
|
174
|
+
say) runs alongside. If the nuclei fail, the cells are skipped, not run
|
|
175
|
+
without seeds. Two configs seeding each other are refused up front. A
|
|
176
|
+
dry run (`-n`) waits for nothing.
|
|
177
|
+
- **Tiles.** The nuclei label image is stacked onto the membrane as each
|
|
178
|
+
tile's second channel, halo included, so neighbouring tiles see the same
|
|
179
|
+
nuclei and a cell crossing a seam is grown from the same nucleus on both
|
|
180
|
+
sides. Both runs must use the same `level`, which `run_multi` already
|
|
181
|
+
enforces; the plugin is told `seeds: "labels"` automatically.
|
|
182
|
+
- **Seeds as given.** Two touching nuclei that Cellpose split stay two
|
|
183
|
+
cells; a dim nucleus Cellpose found still gets its cell. Cellpose's
|
|
184
|
+
mistakes carry over the same way: a nucleus split in two makes two
|
|
185
|
+
cells. Correcting the nuclei first (`patchworks review`, then
|
|
186
|
+
`--write-labels nuclei_labels` and `seed_labels: nuclei_labels_reviewed`)
|
|
187
|
+
gives the cells the corrected nuclei.
|
|
188
|
+
- **On its own**, outside `run_multi`, the cells' config needs
|
|
189
|
+
`labels/nuclei_labels` already in `image.zarr`: `prepare` checks, and
|
|
190
|
+
stops with a message rather than segmenting without seeds.
|
|
191
|
+
- **Re-segmenting the nuclei** does not re-run the cells by itself: delete
|
|
192
|
+
`<work_dir>/cyto_labels` and `image.zarr/labels/cyto_labels` to grow them
|
|
193
|
+
again from the new nuclei.
|
|
194
|
+
|
|
195
|
+
`nuclei_channel: 1` instead of `seed_labels` makes the plugin find the
|
|
196
|
+
nuclei itself, in the nuclear stain (Otsu per tile, `nuclei_*` options),
|
|
197
|
+
independently of Cellpose -- both segmentations then run at the same time.
|
|
198
|
+
|
|
199
|
+
Without PlantSeg, the same works with the plain
|
|
200
|
+
[nuclei-seeded watershed](#nuclei-seeded-watershed): set `module:
|
|
201
|
+
"patchworks.plugins.watershed"` with only the `foreground` and
|
|
202
|
+
`max_radius_um` keys, and use the default environment (`pixi run
|
|
203
|
+
multi-slurm` with this pair listed in `config/multi.yaml`).
|
|
204
|
+
|
|
205
|
+
## Cellpose: membrane only, in 3-D
|
|
206
|
+
|
|
207
|
+
If you stay with Cellpose on such images:
|
|
208
|
+
|
|
209
|
+
- Give it **only the membrane** (`nuclei_channel: null`): `cpsam` then has
|
|
210
|
+
nothing brighter to lock onto.
|
|
211
|
+
- `do_3D: true` combines the three orthogonal views, so a wall faint in one
|
|
212
|
+
plane is found in the others. `stitch_threshold` instead joins
|
|
213
|
+
independent 2-D masks across z and fixes nothing in the masks
|
|
214
|
+
themselves. A GPU (`gpu: true`) only changes the speed.
|
|
215
|
+
|
|
216
|
+
## Denoising first (CAREamics)
|
|
217
|
+
|
|
218
|
+
Noise breaks segmentations: a wall lost in the noise merges two cells.
|
|
219
|
+
[Noise2Void](https://careamics.github.io) learns to remove the noise from
|
|
220
|
+
the image itself (no clean ground truth, no annotation), so a model trained
|
|
221
|
+
once on a few crops of the store denoises every tile before any method sees
|
|
222
|
+
it.
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
pixi install -e careamics
|
|
226
|
+
# on a GPU node: the brightest crops of the channel, ~30 epochs
|
|
227
|
+
pixi run -e careamics denoise-train <work_dir>/image.zarr --channel 0 --out n2v_membrane.ckpt
|
|
228
|
+
pixi run -e careamics denoise-train <work_dir>/image.zarr --channel 1 --out n2v_nuclei.ckpt
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
then, in the segmentation config, with any `method`:
|
|
232
|
+
|
|
233
|
+
```yaml
|
|
234
|
+
denoise:
|
|
235
|
+
model: "/path/to/n2v_membrane.ckpt" # .ckpt, or a BioImage.IO .zip
|
|
236
|
+
nuclei_model: "/path/to/n2v_nuclei.ckpt" # optional, for nuclei_channel
|
|
237
|
+
# tile_size: [16, 256, 256] # CAREamics' tiling inside a tile (VRAM)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
and run from the `careamics` environment (`plantseg-careamics` for both).
|
|
241
|
+
The model paths are checked during `prepare`; the denoised image is not
|
|
242
|
+
stored, only used for segmenting. From the command line, `patchworks segment
|
|
243
|
+
... --denoise n2v_membrane.ckpt` does the same.
|
|
244
|
+
|
|
245
|
+
Look at a denoised tile before a full run:
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
from patchworks import load_ome_zarr
|
|
249
|
+
from patchworks.plugins.careamics import denoise
|
|
250
|
+
|
|
251
|
+
tile = load_ome_zarr("image.zarr", channel=0)[20:44, 1000:1512, 1000:1512]
|
|
252
|
+
clean = denoise(tile.compute(), model="n2v_membrane.ckpt")
|
|
253
|
+
```
|
|
@@ -696,6 +696,14 @@ cellpose:
|
|
|
696
696
|
usually improves cytoplasm segmentation. Both indices are 0-based, like
|
|
697
697
|
`channel`.
|
|
698
698
|
|
|
699
|
+
!!! tip "Cellpose 4 and a bright nuclear channel"
|
|
700
|
+
|
|
701
|
+
`cpsam` gives the two channels no roles, so next to a faint membrane it
|
|
702
|
+
may segment the nuclei instead of the cells. Give it the membrane alone
|
|
703
|
+
(`nuclei_channel: null`), or use the nuclei the other way round: as
|
|
704
|
+
seeds, with the nuclei-seeded watershed or PlantSeg plugins. See
|
|
705
|
+
[Cells from a membrane stain](membrane_cells.md).
|
|
706
|
+
|
|
699
707
|
Only the `segment` step reads it. The pair is stacked on a leading axis that
|
|
700
708
|
is *carried* into each tile rather than tiled, so the tile geometry, the
|
|
701
709
|
occupancy map and the staged labels are byte-for-byte what a single-channel
|
|
@@ -833,6 +841,11 @@ relations:
|
|
|
833
841
|
output: nuclei_to_cyto.xlsx # written into work_dir
|
|
834
842
|
```
|
|
835
843
|
|
|
844
|
+
A second example, `config/multi_plantseg.yaml`, pairs Cellpose nuclei with
|
|
845
|
+
PlantSeg cells seeded from the nuclei (`pixi run -e plantseg
|
|
846
|
+
multi-plantseg-slurm`); see [Cells from a membrane
|
|
847
|
+
stain](membrane_cells.md#example-cellpose-nuclei-plantseg-cells-in-one-run).
|
|
848
|
+
|
|
836
849
|
`common:` is optional — leave it out and each config must be self-contained,
|
|
837
850
|
as before. With it, changing the input path or turning on `shard` is a
|
|
838
851
|
one-line edit in one file instead of the same edit repeated per config.
|
|
@@ -1075,6 +1088,11 @@ pixi run go # run locally (8 cores)
|
|
|
1075
1088
|
pixi run slurm # submit to SLURM (edit profile/slurm/config.yaml first)
|
|
1076
1089
|
```
|
|
1077
1090
|
|
|
1091
|
+
Optional environments add methods: `-e plantseg` (PlantSeg, from
|
|
1092
|
+
conda-forge), `-e careamics` (the `denoise:` step and `pixi run denoise-train`),
|
|
1093
|
+
`-e plantseg-careamics` for both -- see
|
|
1094
|
+
[Cells from a membrane stain](membrane_cells.md).
|
|
1095
|
+
|
|
1078
1096
|
`pixi run …` activates the env, so the rule scripts execute in that env — do
|
|
1079
1097
|
**not** pass `--use-conda`. On a cluster, keep the `workflow/` directory on a
|
|
1080
1098
|
shared filesystem the compute nodes can read: the SLURM executor re-launches
|
|
@@ -42,6 +42,7 @@ nav:
|
|
|
42
42
|
- GPU & distributed: guide/gpu_distributed.md
|
|
43
43
|
- Performance & memory: guide/performance.md
|
|
44
44
|
- Custom segmentation function: guide/custom_segmentation.md
|
|
45
|
+
- Cells from a membrane stain: guide/membrane_cells.md
|
|
45
46
|
- Relating labels across segmentations: guide/label_relations.md
|
|
46
47
|
- Reviewing and correcting results: guide/review.md
|
|
47
48
|
- Measurements: guide/measurements.md
|
|
@@ -72,6 +73,9 @@ nav:
|
|
|
72
73
|
- Plugins:
|
|
73
74
|
- Cellpose: api/plugins/cellpose.md
|
|
74
75
|
- Difference of Gaussians: api/plugins/dog.md
|
|
76
|
+
- Nuclei-seeded watershed: api/plugins/watershed.md
|
|
77
|
+
- PlantSeg: api/plugins/plantseg.md
|
|
78
|
+
- CAREamics denoising: api/plugins/careamics.md
|
|
75
79
|
- OME-ZARR conversion: api/plugins/ome_zarr.md
|
|
76
80
|
- napari viewer: api/plugins/napari.md
|
|
77
81
|
|
|
@@ -59,6 +59,11 @@ cellpose4 = ["cellpose>=4"]
|
|
|
59
59
|
# path, isn't included here — it's CUDA-version-specific (e.g.
|
|
60
60
|
# cupy-cuda12x), install it separately to match your CUDA version.
|
|
61
61
|
dog = ["pycudadecon"]
|
|
62
|
+
# careamics: Noise2Void denoising before segmentation (patchworks.plugins.
|
|
63
|
+
# careamics, the workflow's `denoise:` step, `patchworks denoise-train`).
|
|
64
|
+
# Brings PyTorch. PlantSeg (patchworks.plugins.plantseg) has no extra: it is
|
|
65
|
+
# on conda-forge only (`plant-seg`; the workflow's `-e plantseg`).
|
|
66
|
+
careamics = ["careamics>=0.3"]
|
|
62
67
|
gpu = ["nvidia-ml-py"]
|
|
63
68
|
# remote reads/writes s3://, gs:// and https:// stores through fsspec
|
|
64
69
|
# (credentials come from the usual AWS/GCP environment or config files).
|
|
@@ -117,6 +122,8 @@ workflow = [
|
|
|
117
122
|
"snakemake-executor-plugin-slurm",
|
|
118
123
|
"openpyxl",
|
|
119
124
|
"pandas>=2.0",
|
|
125
|
+
# method: "threshold" and the nuclei-seeded watershed plugin
|
|
126
|
+
"scikit-image",
|
|
120
127
|
]
|
|
121
128
|
# review: the object tables' corrected view and exports, without napari
|
|
122
129
|
# (`patchworks review --summary/--export`). The napari panel needs [napari].
|
|
@@ -14,6 +14,7 @@ from __future__ import annotations
|
|
|
14
14
|
|
|
15
15
|
import argparse
|
|
16
16
|
import importlib
|
|
17
|
+
import inspect
|
|
17
18
|
import json
|
|
18
19
|
import logging
|
|
19
20
|
import sys
|
|
@@ -111,6 +112,15 @@ def _build_fn(args: argparse.Namespace, image: Any) -> Callable:
|
|
|
111
112
|
module, _, name = args.fn.partition(":")
|
|
112
113
|
fn = getattr(importlib.import_module(module), name or "segment")
|
|
113
114
|
kwargs = json.loads(args.fn_kwargs) if args.fn_kwargs else {}
|
|
115
|
+
# A function asking for voxel_size gets the store's calibration (as in
|
|
116
|
+
# the workflow); a **kwargs passthrough names its real target.
|
|
117
|
+
target = getattr(fn, "patchworks_kwargs_target", fn)
|
|
118
|
+
try:
|
|
119
|
+
takes_voxel = "voxel_size" in inspect.signature(target).parameters
|
|
120
|
+
except (TypeError, ValueError):
|
|
121
|
+
takes_voxel = False
|
|
122
|
+
if takes_voxel and voxel and "voxel_size" not in kwargs:
|
|
123
|
+
kwargs["voxel_size"] = voxel
|
|
114
124
|
return partial(fn, **kwargs) if kwargs else fn
|
|
115
125
|
|
|
116
126
|
|
|
@@ -143,6 +153,10 @@ def _cmd_segment(args: argparse.Namespace) -> int:
|
|
|
143
153
|
raise SystemExit("--method custom needs --fn module:function")
|
|
144
154
|
image = load_ome_zarr(args.image, channel=args.channel, level=args.level)
|
|
145
155
|
fn = _build_fn(args, image)
|
|
156
|
+
if args.denoise:
|
|
157
|
+
from .plugins.careamics import denoise_fn
|
|
158
|
+
|
|
159
|
+
fn = denoise_fn(fn, args.denoise)
|
|
146
160
|
tile_shape: Any = args.tile_shape
|
|
147
161
|
if tile_shape not in (None, "auto"):
|
|
148
162
|
tile_shape = _ints(tile_shape)
|
|
@@ -353,6 +367,25 @@ def _cmd_review(args: argparse.Namespace) -> int:
|
|
|
353
367
|
return 0
|
|
354
368
|
|
|
355
369
|
|
|
370
|
+
def _cmd_denoise_train(args: argparse.Namespace) -> int:
|
|
371
|
+
from .plugins.careamics import train_n2v
|
|
372
|
+
|
|
373
|
+
out = train_n2v(
|
|
374
|
+
args.image,
|
|
375
|
+
args.out,
|
|
376
|
+
channel=args.channel,
|
|
377
|
+
level=args.level,
|
|
378
|
+
crop_shape=args.crop_shape,
|
|
379
|
+
n_crops=args.crops,
|
|
380
|
+
patch_size=args.patch_size,
|
|
381
|
+
batch_size=args.batch_size,
|
|
382
|
+
epochs=args.epochs,
|
|
383
|
+
n2v2=args.n2v2,
|
|
384
|
+
)
|
|
385
|
+
print(out)
|
|
386
|
+
return 0
|
|
387
|
+
|
|
388
|
+
|
|
356
389
|
def build_parser() -> argparse.ArgumentParser:
|
|
357
390
|
"""The ``patchworks`` argument parser (exposed for tests and docs)."""
|
|
358
391
|
parser = argparse.ArgumentParser(
|
|
@@ -463,8 +496,40 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
463
496
|
g = p.add_argument_group("custom")
|
|
464
497
|
g.add_argument("--fn", help="module:function returning labels")
|
|
465
498
|
g.add_argument("--fn-kwargs", help="JSON object of keyword arguments")
|
|
499
|
+
p.add_argument(
|
|
500
|
+
"--denoise",
|
|
501
|
+
metavar="MODEL",
|
|
502
|
+
help="denoise each tile with this CAREamics model (.ckpt or .zip) "
|
|
503
|
+
"before segmenting it; see `patchworks denoise-train`",
|
|
504
|
+
)
|
|
466
505
|
p.set_defaults(func=_cmd_segment)
|
|
467
506
|
|
|
507
|
+
p = sub.add_parser(
|
|
508
|
+
"denoise-train",
|
|
509
|
+
help="train a Noise2Void denoiser on a store (CAREamics)",
|
|
510
|
+
description="Train a Noise2Void model on the brightest crops of one "
|
|
511
|
+
"channel -- no ground truth needed -- for `segment --denoise` or the "
|
|
512
|
+
"workflow's denoise: block. Run it on a GPU node.",
|
|
513
|
+
)
|
|
514
|
+
p.add_argument("image", help="OME-ZARR store")
|
|
515
|
+
p.add_argument("--out", required=True, help="checkpoint to write (.ckpt)")
|
|
516
|
+
p.add_argument("--channel", type=int, default=0)
|
|
517
|
+
p.add_argument("--level", type=int, default=0, help="pyramid level")
|
|
518
|
+
p.add_argument(
|
|
519
|
+
"--crop-shape",
|
|
520
|
+
type=_ints,
|
|
521
|
+
default=(32, 512, 512),
|
|
522
|
+
help="z,y,x of each training crop (default 32,512,512)",
|
|
523
|
+
)
|
|
524
|
+
p.add_argument("--crops", type=int, default=4, help="how many crops")
|
|
525
|
+
p.add_argument(
|
|
526
|
+
"--patch-size", type=_ints, help="training patch (default 16,64,64)"
|
|
527
|
+
)
|
|
528
|
+
p.add_argument("--batch-size", type=int, default=8)
|
|
529
|
+
p.add_argument("--epochs", type=int, default=30)
|
|
530
|
+
p.add_argument("--n2v2", action="store_true", help="use Noise2Void2")
|
|
531
|
+
p.set_defaults(func=_cmd_denoise_train)
|
|
532
|
+
|
|
468
533
|
p = sub.add_parser("seams", help="does the tiling show in the labels?")
|
|
469
534
|
p.add_argument("labels", help="label group (or any zarr group)")
|
|
470
535
|
p.add_argument("--tile-shape", type=_ints, required=True)
|