patchworks 3.0.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.
Files changed (166) hide show
  1. {patchworks-3.0.0 → patchworks-3.2.0}/.github/min-versions.txt +1 -0
  2. {patchworks-3.0.0 → patchworks-3.2.0}/PKG-INFO +27 -1
  3. {patchworks-3.0.0 → patchworks-3.2.0}/README.md +18 -0
  4. patchworks-3.2.0/docs/api/plugins/careamics.md +11 -0
  5. patchworks-3.2.0/docs/api/plugins/plantseg.md +11 -0
  6. patchworks-3.2.0/docs/api/plugins/watershed.md +11 -0
  7. patchworks-3.2.0/docs/api/review.md +19 -0
  8. patchworks-3.2.0/docs/assets/review_panel.png +0 -0
  9. patchworks-3.2.0/docs/assets/review_position.png +0 -0
  10. {patchworks-3.0.0 → patchworks-3.2.0}/docs/guide/cli.md +25 -1
  11. {patchworks-3.0.0 → patchworks-3.2.0}/docs/guide/custom_segmentation.md +8 -0
  12. {patchworks-3.0.0 → patchworks-3.2.0}/docs/guide/label_relations.md +8 -0
  13. {patchworks-3.0.0 → patchworks-3.2.0}/docs/guide/measurements.md +20 -0
  14. patchworks-3.2.0/docs/guide/membrane_cells.md +253 -0
  15. patchworks-3.2.0/docs/guide/review.md +261 -0
  16. {patchworks-3.0.0 → patchworks-3.2.0}/docs/guide/snakemake.md +40 -3
  17. {patchworks-3.0.0 → patchworks-3.2.0}/mkdocs.yml +6 -0
  18. {patchworks-3.0.0 → patchworks-3.2.0}/pyproject.toml +20 -3
  19. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/__init__.py +12 -0
  20. patchworks-3.2.0/src/patchworks/_review.py +1243 -0
  21. patchworks-3.2.0/src/patchworks/_tables.py +786 -0
  22. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/cli.py +235 -0
  23. patchworks-3.2.0/src/patchworks/plugins/careamics.py +381 -0
  24. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/plugins/napari.py +34 -9
  25. patchworks-3.2.0/src/patchworks/plugins/plantseg.py +488 -0
  26. patchworks-3.2.0/src/patchworks/plugins/review.py +1056 -0
  27. patchworks-3.2.0/src/patchworks/plugins/watershed.py +403 -0
  28. patchworks-3.2.0/tests/test_careamics.py +170 -0
  29. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_cli.py +69 -0
  30. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_launcher.py +26 -1
  31. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_napari.py +36 -2
  32. patchworks-3.2.0/tests/test_plantseg.py +175 -0
  33. patchworks-3.2.0/tests/test_position.py +194 -0
  34. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_pw.py +242 -0
  35. patchworks-3.2.0/tests/test_review.py +168 -0
  36. patchworks-3.2.0/tests/test_review_napari.py +161 -0
  37. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_run_multi.py +310 -6
  38. patchworks-3.2.0/tests/test_tables.py +130 -0
  39. patchworks-3.2.0/tests/test_watershed.py +124 -0
  40. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/config/config.yaml +25 -0
  41. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/config/config_cyto.yaml +12 -0
  42. patchworks-3.2.0/workflow/config/config_cyto_plantseg.yaml +51 -0
  43. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/config/multi.yaml +23 -0
  44. patchworks-3.2.0/workflow/config/multi_plantseg.yaml +33 -0
  45. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/launcher/app.py +83 -4
  46. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/launcher/launcher_core.py +25 -1
  47. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/pixi.toml +52 -5
  48. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/scripts/_pw.py +218 -7
  49. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/scripts/merge.py +17 -0
  50. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/scripts/prepare_tiles.py +5 -1
  51. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/scripts/relate.py +71 -79
  52. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/scripts/run_multi.py +203 -19
  53. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/scripts/segment_tile.py +8 -2
  54. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/scripts/view.py +13 -1
  55. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/viewer/pixi.toml +12 -4
  56. {patchworks-3.0.0 → patchworks-3.2.0}/.github/workflows/docs.yml +0 -0
  57. {patchworks-3.0.0 → patchworks-3.2.0}/.github/workflows/lint.yml +0 -0
  58. {patchworks-3.0.0 → patchworks-3.2.0}/.github/workflows/release.yml +0 -0
  59. {patchworks-3.0.0 → patchworks-3.2.0}/.github/workflows/test.yml +0 -0
  60. {patchworks-3.0.0 → patchworks-3.2.0}/.gitignore +0 -0
  61. {patchworks-3.0.0 → patchworks-3.2.0}/.markdownlint-cli2.yaml +0 -0
  62. {patchworks-3.0.0 → patchworks-3.2.0}/.pre-commit-config.yaml +0 -0
  63. {patchworks-3.0.0 → patchworks-3.2.0}/LICENSE +0 -0
  64. {patchworks-3.0.0 → patchworks-3.2.0}/benchmarks/bench.py +0 -0
  65. {patchworks-3.0.0 → patchworks-3.2.0}/benchmarks/compare.py +0 -0
  66. {patchworks-3.0.0 → patchworks-3.2.0}/cliff.toml +0 -0
  67. {patchworks-3.0.0 → patchworks-3.2.0}/docs/api/chunks.md +0 -0
  68. {patchworks-3.0.0 → patchworks-3.2.0}/docs/api/cluster.md +0 -0
  69. {patchworks-3.0.0 → patchworks-3.2.0}/docs/api/io.md +0 -0
  70. {patchworks-3.0.0 → patchworks-3.2.0}/docs/api/merge_tile_labels.md +0 -0
  71. {patchworks-3.0.0 → patchworks-3.2.0}/docs/api/plugins/cellpose.md +0 -0
  72. {patchworks-3.0.0 → patchworks-3.2.0}/docs/api/plugins/dog.md +0 -0
  73. {patchworks-3.0.0 → patchworks-3.2.0}/docs/api/plugins/napari.md +0 -0
  74. {patchworks-3.0.0 → patchworks-3.2.0}/docs/api/plugins/ome_zarr.md +0 -0
  75. {patchworks-3.0.0 → patchworks-3.2.0}/docs/api/postprocess.md +0 -0
  76. {patchworks-3.0.0 → patchworks-3.2.0}/docs/api/provenance.md +0 -0
  77. {patchworks-3.0.0 → patchworks-3.2.0}/docs/api/relabel.md +0 -0
  78. {patchworks-3.0.0 → patchworks-3.2.0}/docs/api/seams.md +0 -0
  79. {patchworks-3.0.0 → patchworks-3.2.0}/docs/api/tile_process.md +0 -0
  80. {patchworks-3.0.0 → patchworks-3.2.0}/docs/api/volume_filter.md +0 -0
  81. {patchworks-3.0.0 → patchworks-3.2.0}/docs/assets/logo.png +0 -0
  82. {patchworks-3.0.0 → patchworks-3.2.0}/docs/examples/cellpose_2d.md +0 -0
  83. {patchworks-3.0.0 → patchworks-3.2.0}/docs/examples/cellpose_2d.py +0 -0
  84. {patchworks-3.0.0 → patchworks-3.2.0}/docs/examples/cellpose_3d.md +0 -0
  85. {patchworks-3.0.0 → patchworks-3.2.0}/docs/examples/cellpose_3d.py +0 -0
  86. {patchworks-3.0.0 → patchworks-3.2.0}/docs/examples/custom.md +0 -0
  87. {patchworks-3.0.0 → patchworks-3.2.0}/docs/examples/custom_method.py +0 -0
  88. {patchworks-3.0.0 → patchworks-3.2.0}/docs/examples/dog.md +0 -0
  89. {patchworks-3.0.0 → patchworks-3.2.0}/docs/examples/dog.py +0 -0
  90. {patchworks-3.0.0 → patchworks-3.2.0}/docs/examples/standalone_merge.md +0 -0
  91. {patchworks-3.0.0 → patchworks-3.2.0}/docs/examples/stardist.md +0 -0
  92. {patchworks-3.0.0 → patchworks-3.2.0}/docs/examples/stardist_2d.py +0 -0
  93. {patchworks-3.0.0 → patchworks-3.2.0}/docs/getting_started.md +0 -0
  94. {patchworks-3.0.0 → patchworks-3.2.0}/docs/guide/gpu_distributed.md +0 -0
  95. {patchworks-3.0.0 → patchworks-3.2.0}/docs/guide/launcher.md +0 -0
  96. {patchworks-3.0.0 → patchworks-3.2.0}/docs/guide/merging.md +0 -0
  97. {patchworks-3.0.0 → patchworks-3.2.0}/docs/guide/ome_zarr_napari.md +0 -0
  98. {patchworks-3.0.0 → patchworks-3.2.0}/docs/guide/performance.md +0 -0
  99. {patchworks-3.0.0 → patchworks-3.2.0}/docs/guide/pitfalls.md +0 -0
  100. {patchworks-3.0.0 → patchworks-3.2.0}/docs/guide/skip_empty.md +0 -0
  101. {patchworks-3.0.0 → patchworks-3.2.0}/docs/guide/tiling.md +0 -0
  102. {patchworks-3.0.0 → patchworks-3.2.0}/docs/index.md +0 -0
  103. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_autotune.py +0 -0
  104. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_chunks.py +0 -0
  105. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_cluster.py +0 -0
  106. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_core.py +0 -0
  107. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_distributed.py +0 -0
  108. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_gpu.py +0 -0
  109. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_io.py +0 -0
  110. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_merge.py +0 -0
  111. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_notify.py +0 -0
  112. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_occupancy.py +0 -0
  113. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_postprocess.py +0 -0
  114. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_progress.py +0 -0
  115. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_provenance.py +0 -0
  116. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_relabel.py +0 -0
  117. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_relations.py +0 -0
  118. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_seams.py +0 -0
  119. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/_volume_filter.py +0 -0
  120. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/plugins/__init__.py +0 -0
  121. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/plugins/cellpose.py +0 -0
  122. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/plugins/dog.py +0 -0
  123. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/plugins/ome_zarr.py +0 -0
  124. {patchworks-3.0.0 → patchworks-3.2.0}/src/patchworks/py.typed +0 -0
  125. {patchworks-3.0.0 → patchworks-3.2.0}/tests/ngff_schemas/0.4/image.schema +0 -0
  126. {patchworks-3.0.0 → patchworks-3.2.0}/tests/ngff_schemas/0.4/label.schema +0 -0
  127. {patchworks-3.0.0 → patchworks-3.2.0}/tests/ngff_schemas/0.4/ome.schema +0 -0
  128. {patchworks-3.0.0 → patchworks-3.2.0}/tests/ngff_schemas/0.5/_version.schema +0 -0
  129. {patchworks-3.0.0 → patchworks-3.2.0}/tests/ngff_schemas/0.5/image.schema +0 -0
  130. {patchworks-3.0.0 → patchworks-3.2.0}/tests/ngff_schemas/0.5/label.schema +0 -0
  131. {patchworks-3.0.0 → patchworks-3.2.0}/tests/ngff_schemas/0.5/ome.schema +0 -0
  132. {patchworks-3.0.0 → patchworks-3.2.0}/tests/ngff_schemas/README.md +0 -0
  133. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_allocation.py +0 -0
  134. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_autotune.py +0 -0
  135. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_cellpose.py +0 -0
  136. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_core.py +0 -0
  137. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_distributed.py +0 -0
  138. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_dog.py +0 -0
  139. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_gpu.py +0 -0
  140. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_notify.py +0 -0
  141. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_occupancy.py +0 -0
  142. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_ome_zarr.py +0 -0
  143. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_postprocess.py +0 -0
  144. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_progress.py +0 -0
  145. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_relations.py +0 -0
  146. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_remote.py +0 -0
  147. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_seams.py +0 -0
  148. {patchworks-3.0.0 → patchworks-3.2.0}/tests/test_volume_filter.py +0 -0
  149. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/README.md +0 -0
  150. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/Snakefile +0 -0
  151. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/config/common.yaml +0 -0
  152. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/config/config_cilia.yaml +0 -0
  153. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/config/config_nuclei.yaml +0 -0
  154. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/launcher/README.md +0 -0
  155. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/launcher/clusters.yaml +0 -0
  156. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/launcher/requirements.txt +0 -0
  157. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/profile/slurm/config.yaml +0 -0
  158. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/rules/common.smk +0 -0
  159. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/rules/convert.smk +0 -0
  160. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/rules/merge.smk +0 -0
  161. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/rules/segment.smk +0 -0
  162. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/scripts/build_occupancy.py +0 -0
  163. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/scripts/convert.py +0 -0
  164. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/scripts/export_iso.py +0 -0
  165. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/scripts/fetch_model.py +0 -0
  166. {patchworks-3.0.0 → patchworks-3.2.0}/workflow/scripts/reshard_store.py +0 -0
@@ -4,3 +4,4 @@ dask==2024.10.0
4
4
  numpy==1.26.0
5
5
  zarr==3.1.3
6
6
  scipy==1.11.1
7
+ pandas==2.0.3
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: patchworks
3
- Version: 3.0.0
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
@@ -62,6 +64,7 @@ Provides-Extra: dev
62
64
  Requires-Dist: jsonschema>=4.18; extra == 'dev'
63
65
  Requires-Dist: mypy>=1.10; extra == 'dev'
64
66
  Requires-Dist: openpyxl; extra == 'dev'
67
+ Requires-Dist: pandas>=2.0; extra == 'dev'
65
68
  Requires-Dist: psutil; extra == 'dev'
66
69
  Requires-Dist: pytest; extra == 'dev'
67
70
  Requires-Dist: pytest-cov; extra == 'dev'
@@ -92,8 +95,13 @@ Requires-Dist: numpy<2.5; extra == 'napari'
92
95
  Requires-Dist: pyqt6<6.10; extra == 'napari'
93
96
  Provides-Extra: remote
94
97
  Requires-Dist: fsspec[gcs,http,s3]; extra == 'remote'
98
+ Provides-Extra: review
99
+ Requires-Dist: openpyxl; extra == 'review'
100
+ Requires-Dist: pandas>=2.0; extra == 'review'
95
101
  Provides-Extra: workflow
96
102
  Requires-Dist: openpyxl; extra == 'workflow'
103
+ Requires-Dist: pandas>=2.0; extra == 'workflow'
104
+ Requires-Dist: scikit-image; extra == 'workflow'
97
105
  Requires-Dist: snakemake-executor-plugin-slurm; extra == 'workflow'
98
106
  Requires-Dist: snakemake>=8; extra == 'workflow'
99
107
  Description-Content-Type: text/markdown
@@ -149,6 +157,7 @@ pip install "patchworks[cellpose]" # Cellpose plugin (>=3.0, v3 or v4)
149
157
  pip install "patchworks[cellpose3]" # Cellpose plugin, pinned to v3.x
150
158
  pip install "patchworks[cellpose4]" # Cellpose plugin, pinned to v4+
151
159
  pip install "patchworks[dog]" # deconvolution + DoG plugin (pycudadecon)
160
+ pip install "patchworks[careamics]" # Noise2Void denoising before segmenting
152
161
  pip install "patchworks[bioio]" # convert any image format to OME-ZARR
153
162
  pip install "patchworks[imaris]" # convert Imaris .ims files to OME-ZARR
154
163
  pip install "patchworks[napari]" # interactive napari viewer plugin
@@ -284,6 +293,16 @@ Pyramids downsample **X/Y only** (Z kept full-res) and are built level-by-level
284
293
  from disk, so terabyte volumes convert in bounded RAM. See the
285
294
  [OME-ZARR & napari guide](https://imcf.one/patchworks/guide/ome_zarr_napari/).
286
295
 
296
+ ### Check and correct the result
297
+
298
+ Every label image comes with an object table (size, position, which cell
299
+ each nucleus or cilium is in). `patchworks review scan.zarr` opens napari on
300
+ the objects most likely to be wrong — a cilium in no cell, a cell with two
301
+ nuclei, a nucleus cut in two at a tile seam — one at a time; one key
302
+ accepts, rejects, reassigns or joins. The corrections flow into the tables
303
+ and workbooks. See
304
+ [Reviewing and correcting results](https://imcf.one/patchworks/guide/review/).
305
+
287
306
  ---
288
307
 
289
308
  ## From the command line
@@ -442,6 +461,13 @@ Optional:
442
461
  - `cellpose` — Cellpose plugin, v3 or v4 (`patchworks[cellpose]`);
443
462
  pin with `[cellpose3]` or `[cellpose4]`
444
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/).
445
471
  - `bioio` + readers — convert CZI/LIF/ND2/OME-TIFF/… to OME-ZARR
446
472
  (`patchworks[bioio]`)
447
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
@@ -184,6 +185,16 @@ Pyramids downsample **X/Y only** (Z kept full-res) and are built level-by-level
184
185
  from disk, so terabyte volumes convert in bounded RAM. See the
185
186
  [OME-ZARR & napari guide](https://imcf.one/patchworks/guide/ome_zarr_napari/).
186
187
 
188
+ ### Check and correct the result
189
+
190
+ Every label image comes with an object table (size, position, which cell
191
+ each nucleus or cilium is in). `patchworks review scan.zarr` opens napari on
192
+ the objects most likely to be wrong — a cilium in no cell, a cell with two
193
+ nuclei, a nucleus cut in two at a tile seam — one at a time; one key
194
+ accepts, rejects, reassigns or joins. The corrections flow into the tables
195
+ and workbooks. See
196
+ [Reviewing and correcting results](https://imcf.one/patchworks/guide/review/).
197
+
187
198
  ---
188
199
 
189
200
  ## From the command line
@@ -342,6 +353,13 @@ Optional:
342
353
  - `cellpose` — Cellpose plugin, v3 or v4 (`patchworks[cellpose]`);
343
354
  pin with `[cellpose3]` or `[cellpose4]`
344
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/).
345
363
  - `bioio` + readers — convert CZI/LIF/ND2/OME-TIFF/… to OME-ZARR
346
364
  (`patchworks[bioio]`)
347
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
@@ -0,0 +1,19 @@
1
+ # Object tables and review
2
+
3
+ See [Reviewing and correcting results](../guide/review.md) for the workflow.
4
+
5
+ ::: patchworks.measure_objects
6
+
7
+ ::: patchworks.compute_table
8
+
9
+ ::: patchworks.relate_tables
10
+
11
+ ::: patchworks._tables.nearest_parents
12
+
13
+ ::: patchworks._tables.shape_columns
14
+
15
+ ::: patchworks.read_table
16
+
17
+ ::: patchworks.Review
18
+
19
+ ::: patchworks.plugins.review.review_in_napari
@@ -19,8 +19,23 @@ patchworks seams scan.zarr/labels/labels --tile-shape 16,1024,1024
19
19
 
20
20
  # Look at the result (needs patchworks[napari])
21
21
  patchworks view scan.zarr
22
+
23
+ # One row per object; which cell each nucleus is in
24
+ patchworks tables scan.zarr --relate nuclei:cells
25
+
26
+ # Look at the likely mistakes one by one and fix them (napari)
27
+ patchworks review scan.zarr --expect cells:nuclei=1
22
28
  ```
23
29
 
30
+ `patchworks review` without a window: `--summary` (counts and error
31
+ estimate), `--export DIR --format csv|xlsx|parquet` (corrected tables),
32
+ `--workbooks DIR` (relation workbooks), `--write-labels NAME` (a label image
33
+ with the corrections applied). `--position CHILD:PARENT=APICAL` classifies
34
+ children as apical/basal/lateral/central (APICAL: `+z`, or a label image to
35
+ point away from, such as the nuclei); `patchworks tables --max-distance UM`
36
+ gives a child touching no parent the nearest one. See
37
+ [Reviewing and correcting results](review.md).
38
+
24
39
  ## Segmentation methods
25
40
 
26
41
  | `--method` | What it does | Main flags |
@@ -31,7 +46,16 @@ patchworks view scan.zarr
31
46
  | `custom` | any importable function | `--fn module:function`, `--fn-kwargs '{"k": 1}'` |
32
47
 
33
48
  Cellpose's anisotropy and the DoG plugin's voxel size are read from the
34
- 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).
35
59
 
36
60
  Tiling and stitching take the same options as
37
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
@@ -53,6 +53,14 @@ with open("nuclei_to_cell.csv", "w", newline="") as f:
53
53
  w.writerow([nucleus_id, m["match"], m["overlap_voxels"], m["overlap_fraction"]])
54
54
  ```
55
55
 
56
+ To keep the result with the labels instead, as columns of the object
57
+ tables (the corrections made in
58
+ [`patchworks review`](review.md) then apply to it):
59
+
60
+ ```bash
61
+ patchworks tables results/image.zarr --relate nuclei_labels:cyto_labels
62
+ ```
63
+
56
64
  On the cluster, producing the two label stores in the first place is a
57
65
  matter of running the workflow twice against the same `work_dir` — see
58
66
  [Running two segmentations](snakemake.md#running-two-segmentations-eg-nuclei-cytoplasm).
@@ -3,6 +3,26 @@
3
3
  `skimage.measure.regionprops` needs the full labelled + intensity array in
4
4
  RAM — fine for one tile, not for a hundred-thousand-object OME-ZARR.
5
5
 
6
+ ## Already measured: the object tables
7
+
8
+ The workflow measures every object once, right after the merge: size
9
+ (`area_voxels`, `area_um3`), centroid, bounding box and spread (second
10
+ moments, from which the corrected view derives `length_um`, `elongation`
11
+ and the main axis), plus mean/std intensity for the channels listed in
12
+ `table_channels`. The table is stored
13
+ with the labels (`image.zarr/labels/<name>/table`):
14
+
15
+ ```python
16
+ from patchworks import read_table
17
+
18
+ cells = read_table("results/image.zarr/labels/cyto_labels") # pandas
19
+ ```
20
+
21
+ For a store without one, `patchworks tables results/image.zarr --channels 0,1`
22
+ adds them. With review corrections applied, and as csv files that
23
+ napari-chunked-regionprops loads directly: `patchworks review
24
+ results/image.zarr --export tables/` (see [Reviewing](review.md)).
25
+
6
26
  ## Interactively, in napari
7
27
 
8
28
  [napari-chunked-regionprops](https://github.com/imcf/napari-chunked-regionprops)
@@ -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
+ ```