Skip to content

Getting Started

Installation

blockbuster can be installed from PyPI on all operating systems, for Python ≥ 3.9.

Virtual environment (recommended)

We recommend creating a dedicated environment:

conda create -n blockbuster python=3.12
conda activate blockbuster
or with pixi:
pixi init blockbuster && cd blockbuster
pixi add python=3.12

pip install blockbuster

pip install "blockbuster[gpu]"
Installs nvidia-ml-py to query free GPU VRAM when auto-sizing tiles.

pip install "blockbuster[cellpose]"
pip install "blockbuster[all]"

The one function you need

from blockbuster import tile_process

result = tile_process(image, fn)

tile_process(image, fn) splits image into tiles, runs fn on each tile, and returns a globally consistent label array.

  • image — a dask array or a path to an OME-ZARR store
  • fn — any callable (ndarray) -> ndarray returning integer labels

Step 1: write your function

blockbuster is method-agnostic. Your function receives a NumPy array (one tile) and must return an integer label array of the same shape:

import numpy as np

def my_fn(tile: np.ndarray) -> np.ndarray:
    from skimage.filters import threshold_otsu
    from skimage.measure import label
    binary = tile > threshold_otsu(tile)
    return label(binary).astype("int32")

The function is called independently on every tile. blockbuster ensures that objects spanning tile boundaries are merged into a single label.


Step 2: run it

from blockbuster import tile_process

result = tile_process("image.zarr", my_fn, compute=True)
print(result.shape)   # (z, y, x)
print(result.max())   # number of objects found
import dask.array as da
from blockbuster import tile_process

arr = da.from_zarr("image.zarr")
result = tile_process(arr, my_fn, compute=True)

from blockbuster import tile_process

tile_process(
    "image.zarr", my_fn,
    write_to="labels.zarr",
    progress=True,
)
The output is written tile by tile — peak RAM is one tile, not the whole image.


Set the tile size

result = tile_process("image.zarr", my_fn,
                      tile_shape=(1, 1024, 1024))
result = tile_process("image.zarr", my_fn,
                      tile_shape="auto",
                      use_gpu=True)  # sizes against GPU VRAM
from functools import partial
from blockbuster import auto_tile_shape_cellpose, tile_process

tile_fn = partial(auto_tile_shape_cellpose, diameter=30, use_gpu=True)
result = tile_process("image.zarr", my_fn, tile_shape=tile_fn)

Add overlap

Methods like Cellpose and StarDist need spatial context at tile boundaries. Use overlap (in voxels) so boundary objects are fully visible:

result = tile_process(
    "image.zarr", my_fn,
    tile_shape=(1, 2048, 2048),
    overlap=20,  # 20-voxel halo on every side
)

How overlap works

Each tile is expanded by overlap voxels on every side before calling fn. The halo is trimmed before merging — the final output has the original shape. Objects near boundaries have enough context to be segmented correctly.


Use Cellpose

from blockbuster import tile_process
from blockbuster.plugins.cellpose import cellpose_fn

fn = cellpose_fn("cyto3", gpu=True, diameter=30)

tile_process(
    "image.zarr", fn,
    channel=0,
    tile_shape=(1, 2048, 2048),
    overlap=20,
    write_to="labels.zarr",
    progress=True,
)

See the Cellpose 2-D example for the full workflow.


What's next?