Metadata-Version: 2.5
Name: patchworks
Version: 3.4.0
Summary: Tiled processing of arbitrarily large images with globally consistent labels
Project-URL: Homepage, https://github.com/imcf/patchworks
Project-URL: Issues, https://github.com/imcf/patchworks/issues
Author-email: Laurent Guerard <laurent.guerard@unibas.ch>
License: GPL-3.0-only
License-File: LICENSE
Keywords: bioimage,chunked,dask,image processing,segmentation,tiling,zarr
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Image Processing
Requires-Python: >=3.11
Requires-Dist: dask[array]>=2024.10.0
Requires-Dist: numpy>=1.26
Requires-Dist: psutil
Requires-Dist: scipy>=1.11
Requires-Dist: zarr>=3.1.3
Provides-Extra: all
Requires-Dist: bioio; extra == 'all'
Requires-Dist: bioio-bioformats; extra == 'all'
Requires-Dist: bioio-czi; extra == 'all'
Requires-Dist: bioio-lif; extra == 'all'
Requires-Dist: bioio-nd2; extra == 'all'
Requires-Dist: bioio-ome-tiff; extra == 'all'
Requires-Dist: bioio-tifffile; extra == 'all'
Requires-Dist: dask[diagnostics,distributed]; extra == 'all'
Requires-Dist: imaris-ims-file-reader; extra == 'all'
Requires-Dist: ipykernel<7; extra == 'all'
Requires-Dist: lxml-html-clean; extra == 'all'
Requires-Dist: napari-chunked-regionprops>=0.1.0; extra == 'all'
Requires-Dist: napari[all]>=0.7.1; extra == 'all'
Requires-Dist: numpy<2.5; extra == 'all'
Requires-Dist: nvidia-ml-py; extra == 'all'
Requires-Dist: psutil; extra == 'all'
Requires-Dist: pyqt6<6.10; extra == 'all'
Requires-Dist: scikit-image; extra == 'all'
Requires-Dist: tqdm; extra == 'all'
Provides-Extra: bioio
Requires-Dist: bioio; extra == 'bioio'
Requires-Dist: bioio-bioformats; extra == 'bioio'
Requires-Dist: bioio-czi; extra == 'bioio'
Requires-Dist: bioio-lif; extra == 'bioio'
Requires-Dist: bioio-nd2; extra == 'bioio'
Requires-Dist: bioio-ome-tiff; extra == 'bioio'
Requires-Dist: bioio-tifffile; extra == 'bioio'
Provides-Extra: careamics
Requires-Dist: careamics>=0.3; extra == 'careamics'
Provides-Extra: cellpose
Requires-Dist: cellpose>=3.0; extra == 'cellpose'
Provides-Extra: cellpose3
Requires-Dist: cellpose<4,>=3.0; extra == 'cellpose3'
Provides-Extra: cellpose4
Requires-Dist: cellpose>=4; extra == 'cellpose4'
Provides-Extra: dev
Requires-Dist: jsonschema>=4.18; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: openpyxl; extra == 'dev'
Requires-Dist: pandas>=2.0; extra == 'dev'
Requires-Dist: psutil; extra == 'dev'
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: pytest-cov; extra == 'dev'
Requires-Dist: ruff==0.15.18; extra == 'dev'
Requires-Dist: scikit-image; extra == 'dev'
Requires-Dist: tqdm; extra == 'dev'
Provides-Extra: distributed
Requires-Dist: dask[diagnostics,distributed]; extra == 'distributed'
Provides-Extra: docs
Requires-Dist: mkdocstrings[python]>=0.24; extra == 'docs'
Requires-Dist: zensical>=0.0.72; extra == 'docs'
Provides-Extra: dog
Requires-Dist: pycudadecon; extra == 'dog'
Provides-Extra: gpu
Requires-Dist: nvidia-ml-py; extra == 'gpu'
Provides-Extra: imaris
Requires-Dist: imaris-ims-file-reader; extra == 'imaris'
Provides-Extra: io
Requires-Dist: psutil; extra == 'io'
Requires-Dist: tqdm; extra == 'io'
Provides-Extra: napari
Requires-Dist: ipykernel<7; extra == 'napari'
Requires-Dist: lxml-html-clean; extra == 'napari'
Requires-Dist: napari-chunked-regionprops>=0.1.0; extra == 'napari'
Requires-Dist: napari[all]>=0.7.1; extra == 'napari'
Requires-Dist: numpy<2.5; extra == 'napari'
Requires-Dist: pyqt6<6.10; extra == 'napari'
Provides-Extra: remote
Requires-Dist: fsspec[gcs,http,s3]; extra == 'remote'
Provides-Extra: review
Requires-Dist: openpyxl; extra == 'review'
Requires-Dist: pandas>=2.0; extra == 'review'
Provides-Extra: workflow
Requires-Dist: openpyxl; extra == 'workflow'
Requires-Dist: pandas>=2.0; extra == 'workflow'
Requires-Dist: scikit-image; extra == 'workflow'
Requires-Dist: snakemake-executor-plugin-slurm>=2.2; extra == 'workflow'
Requires-Dist: snakemake>=8; extra == 'workflow'
Description-Content-Type: text/markdown

<p align="center">
  <img src="https://raw.githubusercontent.com/imcf/patchworks/main/docs/assets/logo.svg" alt="patchworks logo" width="220">
</p>

# patchworks

[![PyPI](https://img.shields.io/pypi/v/patchworks.svg)](https://pypi.org/project/patchworks/)
[![Python versions](https://img.shields.io/pypi/pyversions/patchworks.svg)](https://pypi.org/project/patchworks/)
[![License: GPLv3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![Docs](https://img.shields.io/badge/docs-imcf.one%2Fpatchworks-blue)](https://imcf.one/patchworks/)

> Tiled processing of arbitrarily large images — any image, any function.

```text
┌──────┬──────┬──────┐     fn(tile) → labels      ┌──────┬──────┬──────┐
│ tile │ tile │ tile │  ─────────────────────►    │  1   │  2   │  3   │
├──────┼──────┼──────┤                            ├──────┼──────┼──────┤
│ tile │ tile │ tile │                            │  4   │  5   │  6   │   globally
├──────┼──────┼──────┤                            ├──────┼──────┼──────┤   consistent
│ tile │ tile │ tile │                            │  7   │  8   │  9   │   labels
└──────┴──────┴──────┘                            └──────┴──────┴──────┘
```

patchworks splits an image too large for memory into tiles, runs **any
segmentation function** on each tile, and stitches the results into one
consistent label image — stored with the image in a single OME-Zarr, with a
table of every object.

> [!NOTE]
> **On how this was written.** Large parts of patchworks were vibe coded —
> written with heavy LLM assistance rather than line by line. It is covered by
> a test suite and has been run on real data, so it is not untested, but the
> usual caveats apply: read the code before you trust it with anything
> irreplaceable, and please open an issue if something looks off.

## Install

```bash
pip install patchworks                 # core
pip install "patchworks[cellpose]"     # + Cellpose
pip install "patchworks[bioio,imaris]" # + converting CZI/LIF/ND2/TIFF/.ims to OME-Zarr
pip install "patchworks[napari]"       # + viewing and reviewing in napari
pip install "patchworks[all]"          # everything above and more
```

GPU options of the DoG plugin need `cupy` matching your CUDA version
(`pip install cupy-cuda12x`). PlantSeg is on conda-forge only. See
[Getting started](https://imcf.one/patchworks/getting_started/) for every
extra.

## Three ways to use it

**Python** — any function from a tile to labels:

```python
from patchworks import tile_process
from patchworks.plugins.cellpose import cellpose_fn

tile_process("scan.zarr", cellpose_fn("cyto3", gpu=True, diameter=30))
```

The labels go into `scan.zarr/labels/labels`, as a multiscale pyramid next
to the image.

**Command line** — the same building blocks, no script:

```bash
patchworks convert scan.czi scan.zarr
patchworks segment scan.zarr --method cellpose --model cyto3 --diameter 30 --gpu
patchworks view scan.zarr
```

**On a cluster** — a Snakemake workflow with a pixi environment: convert,
segment tile batches as GPU jobs, merge, relate label images (which cell
each nucleus is in), and bundle, from one YAML config per segmentation:

```bash
cd workflow
pixi run multi-slurm --config my_multi.yaml
```

## What you get

- **One OME-Zarr** holding the image and every label image, readable by
  napari, Fiji and any OME-Zarr tool.
- **Object tables** — size, position, shape — and **relations** between label
  images (the cell of each nucleus, the position of each cilium in its cell),
  exported as spreadsheets.
- **Review in napari**: `patchworks review scan.zarr` steps through the
  objects most likely to be wrong; corrections flow into the tables.
- Plugins for **Cellpose**, **PlantSeg**, a **nuclei-seeded watershed**,
  **difference of Gaussians** (cilia, spots) and **Noise2Void** denoising —
  or bring your own function.

## Documentation

**<https://imcf.one/patchworks/>** — getting started, the cluster workflow,
guides, examples and the API reference.

## License

GNU General Public License v3.0 (GPL-3.0). See [LICENSE](LICENSE).
