Skip to content

Segmentation API

Cell and nucleus segmentation for whole-slide images with Cellpose 3 or 4, importable from smint.segmentation. There are two pipelines; pick one by image size and hardware:

Pipeline Runs on Tiles Boundary cells Entry point
Distributed Dask workers: local CPUs/GPUs or SLURM Overlapping Stitched and reconciled run_distributed_segmentation
Single process One process, one GPU or CPU Non-overlapping Split at tile edges process_large_image

Both write outline CSVs in pixel coordinates of the full image; see Data formats. Every model load and eval call goes through the Cellpose compatibility layer, so the same code runs on Cellpose 3 and 4.

flowchart LR
    A[OME-TIFF / OME-Zarr] --> B[generate_tiles]
    B --> C[segment_tile<br/>on each worker]
    C -->|core region| Z[cells.zarr / nuclei.zarr]
    C -->|outlines of expanded tile| D[stitch_and_reconcile]
    D --> E[cells / nuclei<br/>outlines + summary CSVs]

Distributed segmentation

The image is cut into core tiles; each worker segments its tile expanded by an overlap margin, writes the core region into shared Zarr label masks and returns outlines of every object it saw whole. The coordinator then stitches duplicate outlines and reconciles cells with nuclei. Needs pip install 'smint[distributed]' and Cellpose.

from smint.segmentation import run_distributed_segmentation

result = run_distributed_segmentation(
    "slide.ome.tif", "results/dist", config_path="my_config.yaml",
    backend="slurm", n_workers=4, slurm={"gpu_type": "A30"},
)
print(result["total_cells"], result["total_nuclei"], result["failed_tiles"])

smint.segmentation.run_distributed_segmentation

run_distributed_segmentation(image_path, output_dir, config_path=None, n_workers=None, use_gpu=None, chunk_size=None, tile_info_path=None, live_update_image_path=None, backend=None, scheduler_address=None, tile_overlap=None, cell_model=None, nuclei_model=None, cell_params=None, nuclei_params=None, split_multinucleated=None, reconcile_nuclei=None, stitch_merge_thresh=None, stitch_trim_thresh=None, slurm=None, worker_wait_timeout=None)

Segment cells and nuclei across a whole slide with Dask workers.

Arguments left as None come from the YAML config, then from defaults. Config keys: model_paths ([cell_model, nuclei_model]), cell_model_params / nuclei_model_params (diameter, flow_threshold, cellprob_threshold, channels), n_workers, use_gpu, chunk_size, and an optional distributed section with backend, scheduler_address, tile_overlap, split_multinucleated, reconcile_nuclei, stitch_merge_thresh, stitch_trim_thresh, worker_wait_timeout and slurm.

Writes to output_dir:

  • cells_outlines.csv / nuclei_outlines.csv: one row per outline vertex, global_cell_id, x, y, IDs from 1 after stitching.
  • cells_summary.csv: global_cell_id, x_centroid, y_centroid, area, n_nuclei; nuclei_summary.csv: the same with cell_id (the containing cell's global_cell_id) in place of n_nuclei.
  • cells.zarr / nuclei.zarr: raw label masks. Their IDs are per-tile and are not the stitched IDs.
  • distributed_seg_<timestamp>.log.

Parameters:

Name Type Description Default
image_path str

Zarr / OME-Zarr store or TIFF / OME-TIFF file. Must be readable by every worker (for SLURM, on shared storage).

required
output_dir str

Output directory, shared with the workers.

required
config_path str

YAML configuration file.

None
n_workers int

Number of Dask workers.

None
use_gpu bool

Use GPU workers. Default True.

None
chunk_size tuple

Core tile (height, width); tiles are square, so the first value is used. Default 2048.

None
tile_info_path str

Tile-info file for the live viewer.

None
live_update_image_path str

PNG updated as tiles finish.

None
backend str

'local' (default) or 'slurm'.

None
scheduler_address str

Use an existing Dask scheduler.

None
tile_overlap int

Expansion on each tile side; must exceed the largest cell radius. Default 256.

None
cell_model str

Cell model name or path; False skips cells.

None
nuclei_model str

Nuclei model name or path; False skips nuclei.

None
cell_params dict

Cell model parameters.

None
nuclei_params dict

Nuclei model parameters.

None
split_multinucleated bool

Split cells with several nuclei. Default True.

None
reconcile_nuclei bool

Reconcile cells with nuclei and assign each nucleus to a cell. Default True.

None
stitch_merge_thresh float

Merge above this overlap. Default 0.5.

None
stitch_trim_thresh float

Trim below this overlap, remove the smaller object at or above it. Default 0.25.

None
slurm dict

SLURMCluster options, see setup_dask_client.

None
worker_wait_timeout int

Seconds to wait for workers. Default 600.

None

Returns:

Type Description
dict

cells_csv_path, nuclei_csv_path, cells_summary_path, nuclei_summary_path, cells_zarr_path, nuclei_zarr_path, total_cells, total_nuclei, n_tiles, failed_tiles (core coordinates of tiles that failed) and processing_time (seconds).

Raises:

Type Description
ImportError

A required package is missing.

ValueError

No model was given, a model is neither a file nor a built-in name, or the tile grid would overflow uint32 label IDs.

RuntimeError

Every tile failed.

Building blocks

smint.segmentation.distributed_seg.open_image

open_image(image_path)

Open a large image lazily as a (C, Y, X) Dask array.

Supports Zarr / OME-Zarr stores and TIFF / OME-TIFF files. Nothing is read until the array is sliced and computed.

Parameters:

Name Type Description Default
image_path str

Path to the image.

required

Returns:

Type Description
Array

(C, Y, X) array.

smint.segmentation.distributed_seg.generate_tiles

generate_tiles(image_shape, tile_size)

Non-overlapping core tile grid as [(tile_id, (y0, x0, y1, x1)), ...].

smint.segmentation.distributed_seg.setup_dask_client

setup_dask_client(backend='local', n_workers=None, use_gpu=True, scheduler_address=None, slurm=None, worker_wait_timeout=600)

Create a Dask client.

Parameters:

Name Type Description Default
backend str

'local' or 'slurm'. Ignored when scheduler_address is given.

'local'
n_workers int

Number of workers. Local default: one per GPU with dask_cuda, otherwise min(4, cpu_count). SLURM default: 4.

None
use_gpu bool

Request GPU workers.

True
scheduler_address str

Connect to an existing scheduler.

None
slurm dict

dask_jobqueue.SLURMCluster options. SMINT defaults: queue='gpuq', memory='64GB', walltime='12:00:00', gpu_type (adds --gres=gpu:<type>:1), python (the current interpreter).

None
worker_wait_timeout int

Seconds to wait for the first worker.

600

Returns:

Type Description
tuple

(client, cluster); cluster is None for an external scheduler.

smint.segmentation.distributed_seg.segment_tile

segment_tile(tile_id, tile_coords, image_path, image_shape, overlap, cell_model, cell_params, nuclei_model, nuclei_params, cells_zarr_path, nuclei_zarr_path, use_gpu=None, split_multinucleated=True, max_cells_per_tile=MAX_CELLS_PER_TILE)

Segment one tile. Runs on a Dask worker.

Parameters:

Name Type Description Default
tile_id int

Tile index; offsets label IDs so tiles never collide.

required
tile_coords tuple

Core region (y_start, x_start, y_end, x_end).

required
image_path str

Image path, readable from the worker.

required
image_shape tuple

Full image (height, width).

required
overlap int

Pixels the tile is expanded by on each side.

required
cell_model str or None

Cell model name or path; None skips cells.

required
cell_params dict

diameter, flow_threshold, cellprob_threshold, channels for the cell model.

required
nuclei_model str or None

Nuclei model name or path; None skips nuclei.

required
nuclei_params dict

As cell_params, for the nuclei model.

required
cells_zarr_path str

Label-mask Zarr for cells.

required
nuclei_zarr_path str

Label-mask Zarr for nuclei.

required
use_gpu bool

Use the GPU. Defaults to what is available.

None
split_multinucleated bool

Split cells containing several nuclei.

True
max_cells_per_tile int

Label ID offset between tiles.

MAX_CELLS_PER_TILE

Returns:

Type Description
dict

tile_id, tile_coords, success, error, n_cells, n_nuclei and the tile's cell_outlines / nuclei_outlines (dicts with global_id, x_coords, y_coords in full-image pixels, covering the whole expanded tile).

smint.segmentation.distributed_seg.stitch_and_reconcile

stitch_and_reconcile(cell_outlines, nuclei_outlines, merge_threshold=0.5, trim_threshold=0.25, reconcile=True)

Turn raw per-tile outlines into final, non-overlapping cells and nuclei.

Nuclei are stitched first; cells are filtered to those touching a stitched nucleus, then stitched; finally cells and nuclei are reconciled so every nucleus sits inside exactly one cell. See smint.segmentation.stitching.

Parameters:

Name Type Description Default
cell_outlines list or None

Raw cell outline dicts, or None to skip cells.

required
nuclei_outlines list or None

Raw nucleus outline dicts, or None.

required
merge_threshold float

Merge pairs overlapping by more than this.

0.5
trim_threshold float

Trim below, remove smaller at or above this.

0.25
reconcile bool

Run cell / nucleus reconciliation when both exist.

True

Returns:

Type Description
tuple

(cells, nuclei, nucleus_cell); nucleus_cell holds each nucleus's index into cells, or None when not reconciled.

smint.segmentation.distributed_seg.polygons_to_dataframe

polygons_to_dataframe(polygons)

Flatten polygons to SMINT's global_cell_id, x, y vertex table, IDs from 1.

smint.segmentation.distributed_seg.polygon_summary

polygon_summary(polygons, **columns)

One row per polygon: global_cell_id, centroid, area, plus columns.

smint.segmentation.distributed_seg.setup_logging

setup_logging(output_dir=None)

Set up logging for a distributed run.

Parameters:

Name Type Description Default
output_dir str

Directory for a timestamped log file. If None, log to the console only.

None

Returns:

Type Description
Logger

The smint.distributed_seg logger.

Stitching and reconciliation

smint.segmentation.stitching is a Python port of an R stitching workflow (stitching.Rmd). It works on Shapely polygons, so you can also use it on outlines from any other tiled segmentation. Stage 1 runs per object type, stage 2 on cells and nuclei together:

flowchart LR
    subgraph S1[Stage 1: stitch_polygons]
        M[merge<br/>overlap > merge_threshold] --> T[trim<br/>overlap < trim_threshold] --> R[remove smaller<br/>overlap >= trim_threshold]
    end
    S1 --> F[filter_by_nuclei]
    F --> S2[Stage 2: reconcile_cells_and_nuclei<br/>one nucleus per cell]
from smint.segmentation.stitching import (
    polygons_from_outlines, stitch_polygons, reconcile_cells_and_nuclei,
)

# cell_outlines / nucleus_outlines: lists of {"x_coords": array, "y_coords": array}
nuclei = stitch_polygons(polygons_from_outlines(nucleus_outlines))
cells = stitch_polygons(polygons_from_outlines(cell_outlines))
cells, nuclei, nucleus_cell = reconcile_cells_and_nuclei(cells, nuclei)

*_outlines are lists of dicts with x_coords / y_coords arrays, as segment_tile and get_cell_outlines return them.

smint.segmentation.stitching.stitch_polygons

stitch_polygons(geoms, merge_threshold=0.5, trim_threshold=0.25, max_merge_rounds=10, min_overlap_area=1.0)

Resolve duplicate and colliding polygons from overlapping tiles.

Runs three phases in order, each on the result of the last. The maximum overlap of a pair is their intersection area divided by the smaller polygon's area.

  1. Merge: union pairs whose maximum overlap exceeds merge_threshold (the same object seen by two tiles), repeating until nothing merges.
  2. Trim: for pairs below trim_threshold (a minor collision), remove the overlap from both.
  3. Remove: for pairs at or above trim_threshold, drop the smaller polygon.

Parameters:

Name Type Description Default
geoms sequence

Shapely polygons.

required
merge_threshold float

Merge pairs whose maximum overlap exceeds this.

0.5
trim_threshold float

Trim pairs below this; remove the smaller of pairs at or above it (and not merged).

0.25
max_merge_rounds int

Cap on merge iterations.

10
min_overlap_area float

Ignore intersections smaller than this.

1.0

Returns:

Type Description
ndarray

Stitched polygons.

smint.segmentation.stitching.reconcile_cells_and_nuclei

reconcile_cells_and_nuclei(cells, nuclei, min_overlap_area=1.0, min_nucleus_fraction=0.1, split_keep_fraction_2=0.4, split_keep_fraction_3plus=0.3)

Make cells and nuclei consistent and assign each nucleus to one cell.

Steps, following stitching.Rmd:

  1. Drop cells touching no nucleus, and cells whose only nucleus overlaps them by less than min_nucleus_fraction of the nucleus.
  2. Grow a cell over a nucleus that touches only that cell and is more than half (but not fully) inside it.
  3. Split nuclei straddling several cells into per-cell pieces. A piece is kept if it holds at least 50% of the nucleus, or -- for a cell with no other nucleus -- at least split_keep_fraction_2 (nucleus in 2 cells) or split_keep_fraction_3plus (3+ cells); a single-nucleus cell holding less than that is dropped.
  4. Remove identical, contained and mostly-covered duplicates among cells and among nuclei; cut remaining overlaps out of the larger object.
  5. Assign: a nucleus more than half inside a cell is absorbed into it; one less than half inside is cut out of the cell (and the cell out of it). Nuclei left without a cell become nucleus-only cells; nuclei still straddling a boundary are dropped; cells with no nucleus are dropped.

Parameters:

Name Type Description Default
cells sequence

Stitched cell polygons.

required
nuclei sequence

Stitched nucleus polygons.

required
min_overlap_area float

Ignore intersections smaller than this.

1.0
min_nucleus_fraction float

Step 1 threshold.

0.1
split_keep_fraction_2 float

Step 3 threshold, nucleus in 2 cells.

0.4
split_keep_fraction_3plus float

Step 3 threshold, nucleus in 3+ cells.

0.3

Returns:

Type Description
tuple

(cells, nuclei, nucleus_cell) where nucleus_cell[k] is the index into cells of the cell containing nucleus k.

Stitching steps

smint.segmentation.stitching.merge_overlapping

merge_overlapping(geoms, merge_threshold=0.5, max_rounds=10, min_overlap_area=1.0)

Union polygons whose maximum overlap exceeds merge_threshold.

Overlapping pairs are joined into connected groups and each group is unioned; this repeats on the result until no pair qualifies (or max_rounds is reached), since a merged polygon can newly overlap another by more than the threshold.

Returns:

Type Description
ndarray

Polygons after merging.

smint.segmentation.stitching.trim_collisions

trim_collisions(geoms, trim_threshold=0.25, min_overlap_area=1.0)

Remove small overlaps from both polygons of each pair.

For pairs with maximum overlap below trim_threshold, each polygon loses its intersection with the other (computed against the untrimmed neighbours).

Returns:

Type Description
ndarray

Polygons after trimming.

smint.segmentation.stitching.remove_conflicts

remove_conflicts(geoms, trim_threshold=0.25, min_overlap_area=1.0)

Drop the smaller polygon of each pair overlapping by trim_threshold or more.

Returns:

Type Description
ndarray

Remaining polygons.

smint.segmentation.stitching.filter_by_nuclei

filter_by_nuclei(cells, nuclei)

Keep only cells that touch at least one nucleus.

smint.segmentation.stitching.polygons_from_outlines

polygons_from_outlines(outlines)

Build polygons from outline dicts with x_coords / y_coords.

Parameters:

Name Type Description Default
outlines list

Dicts with x_coords and y_coords arrays.

required

Returns:

Type Description
ndarray

Valid Polygons (outlines with < 3 vertices are skipped).

smint.segmentation.stitching.clean_polygons

clean_polygons(geoms, min_area=0.0)

Make geometries valid single polygons and drop empty or tiny ones.

Parameters:

Name Type Description Default
geoms sequence

Shapely geometries.

required
min_area float

Drop polygons with area <= this.

0.0

Returns:

Type Description
ndarray

Object array of valid Polygons.

Single-process segmentation

Segments the image chunk by chunk in one process, with no overlap and no stitching, so a cell crossing a chunk edge is reported once per chunk. Use it for images that fit in memory on one machine, or as the fallback when Dask is not available.

smint.segmentation.process_large_image

process_large_image(image_path, csv_base_path, chunk_size=(2048, 2048), cell_model_path='cyto3', cells_diameter=120.0, cells_flow_threshold=0.4, cells_cellprob_threshold=-1.5, cells_channels=[1, 2], nuclei_model_path='nuclei', nuclei_diameter=40.0, nuclei_flow_threshold=0.4, nuclei_cellprob_threshold=-1.2, nuclei_channels=[2, 0], enable_adaptive_nuclei=False, nuclei_adaptive_cellprob_lower_limit=-6.0, nuclei_adaptive_cellprob_step_decrement=0.2, nuclei_max_adaptive_attempts=3, adaptive_nuclei_trigger_ratio=0.05, visualize=True, visualize_output_dir=None, num_visualize_chunks=5, visualize_roi_size=(2024, 2024), vis_bg_channel_indices=[0, 1], live_update_image_path=None, tile_info_file_for_viewer=None, use_gpu=None)

Segment cells and nuclei in a large TIFF, chunk by chunk, in one process.

The image is read whole with tifffile and reduced to (C, Y, X); each non-overlapping chunk is segmented with the cell model and the nuclei model. There is no overlap and no stitching, so an object crossing a chunk edge is reported once per chunk; use run_distributed_segmentation when that matters.

Always pass cell_model_path (a model file, or a built-in name such as "cyto3" on Cellpose 3 or "cpsam" on Cellpose 4). It defaults to "cyto3" (Cellpose 4 substitutes cpsam); when a model file cannot be found, cell segmentation is skipped with a warning. The same applies to nuclei_model_path, which defaults to "nuclei" (Cellpose 3 only; Cellpose 4 substitutes cpsam).

Writes <csv_base_path>_cells.csv and <csv_base_path>_nuclei.csv (global_cell_id, chunk_id, x, y, one row per outline vertex), <csv_base_path>.log and, when visualize is on, chunk_<row>_<col>.png overlays. The directory of csv_base_path is created if it does not exist.

Parameters:

Name Type Description Default
image_path str

Path to the input TIFF / OME-TIFF.

required
csv_base_path str

Path prefix for the output files.

required
chunk_size tuple

Chunk (height, width) in pixels.

(2048, 2048)
cells_diameter float

Diameter of cells for segmentation

120.0
cells_flow_threshold float

Flow threshold for cell segmentation

0.4
cells_cellprob_threshold float

Cell probability threshold

-1.5
cells_channels list

Cellpose-style [main, nuclear] channel pair for the cell model (1-based, 0 = none)

[1, 2]
nuclei_model_path str

Nuclei model file or built-in name

'nuclei'
nuclei_diameter float

Diameter of nuclei for segmentation

40.0
nuclei_flow_threshold float

Flow threshold for nuclei segmentation

0.4
nuclei_cellprob_threshold float

Nuclei probability threshold

-1.2
nuclei_channels list

Channel pair for the nuclei model

[2, 0]
enable_adaptive_nuclei bool

Re-run the nuclei model on a chunk with a lower cellprob_threshold while the nuclei-to-cells ratio is below adaptive_nuclei_trigger_ratio

False
nuclei_adaptive_cellprob_lower_limit float

Lowest threshold to try

-6.0
nuclei_adaptive_cellprob_step_decrement float

Threshold decrease per attempt

0.2
nuclei_max_adaptive_attempts int

Maximum re-runs per chunk

3
adaptive_nuclei_trigger_ratio float

Nuclei / cells ratio below which a chunk is re-run

0.05
visualize bool

Save outline overlays for some chunks

True
visualize_output_dir str

Directory for the overlays; default visualizations/ beside csv_base_path

None
num_visualize_chunks int

Number of randomly chosen chunks to overlay

5
visualize_roi_size tuple

Logged only; each overlay covers one chunk

(2024, 2024)
vis_bg_channel_indices list

0-based channels shown under the outlines

[0, 1]
live_update_image_path str

PNG rewritten after every chunk, for the live viewer

None
tile_info_file_for_viewer str

Tile-info file rewritten after every chunk, for the live viewer

None
use_gpu bool

Run Cellpose on the GPU. Default None: use it when one is available.

None

Returns:

Type Description
dict

cells_csv_path, nuclei_csv_path (None when nothing was found), total_cells, total_nuclei, processing_time (seconds), start_time and end_time. On failure to load the image or the models, {"error": message} instead of raising.

smint.segmentation.segment_chunk

segment_chunk(chunk_data, model_instance, chunk_position=None, diameter=80, flow_threshold=0.8, cellprob_threshold=-3.5, channels=[0, 0], object_type='object')

Segment a chunk of an image using Cellpose.

Parameters:

Name Type Description Default
chunk_data ndarray

Chunk of image data to segment

required
model_instance CellposeModel

Loaded Cellpose model.

required
chunk_position tuple

Position of chunk in the original image (y_start, x_start)

None
diameter float

Expected object diameter

80
flow_threshold float

Flow threshold for segmentation

0.8
cellprob_threshold float

Cell probability threshold

-3.5
channels list

Channels to use for segmentation

[0, 0]
object_type str

Type of object being segmented (for logging)

'object'

Returns:

Type Description
tuple

(masks, outlines). masks is the uint16 label mask of the chunk; outlines is a list of dicts with cell_id, x_coords / y_coords (in full-image pixels when chunk_position is given) and chunk_id ("<y>_<x>", the chunk's origin).

smint.segmentation.get_cell_outlines

get_cell_outlines(masks)

Extract cell outlines from a segmentation mask.

Parameters:

Name Type Description Default
masks ndarray

Segmentation mask with cell IDs

required

Returns:

Type Description
list

One dict per label with cell_id and x_coords / y_coords (the longest contour, from skimage.measure.find_contours).

Cellpose 3 and 4 compatibility

Cellpose 4 ships a single model (Cellpose-SAM, cpsam), ignores model_type and ignores channels. These helpers make a model name and a Cellpose 3 style channel pair behave the same on both versions.

channels Cellpose sees
[0, 0] the first channel, greyscale
[2, 1] channel index 1 as the cytoplasm, channel index 0 as the nucleus
[1, 0] channel index 0 alone

Indices are 1-based into the channel axis; 0 means "none".

smint.segmentation.cellpose_compat.load_model

load_model(model, gpu=None)

Load a Cellpose model by built-in name or file path.

Parameters:

Name Type Description Default
model str

A path to a trained model, or a built-in name. On Cellpose 3 the names are cyto, cyto2, cyto3, nuclei etc. On Cellpose 4 the only built-in is cpsam; legacy names fall back to it with a warning.

required
gpu bool

Use the GPU. Defaults to whatever is available.

None

Returns:

Type Description
CellposeModel

The loaded model.

smint.segmentation.cellpose_compat.run_eval

run_eval(model, image, channels=(0, 0), **kwargs)

Run model.eval with channel handling that behaves the same on 3 and 4.

Parameters:

Name Type Description Default
model CellposeModel

A loaded Cellpose model, e.g. from load_model.

required
image ndarray

(Y, X) or (C, Y, X) array.

required
channels sequence of int

Cellpose 3 style channel pair, see select_channels.

(0, 0)
**kwargs Any

Passed through to eval (diameter, flow_threshold, cellprob_threshold ...).

{}

Returns:

Type Description
ndarray

Integer label mask.

smint.segmentation.cellpose_compat.select_channels

select_channels(image, channels)

Pick the channels Cellpose should see, using Cellpose 3's convention.

channels is [main, optional_nuclear] with 1-based indices into the channel axis and 0 meaning "none": [0, 0] is grayscale (first channel), [2, 1] is channel index 1 as the main channel with index 0 as the nuclear channel.

Parameters:

Name Type Description Default
image ndarray

(Y, X) or (C, Y, X) array.

required
channels sequence of int

Cellpose-style channel pair.

required

Returns:

Type Description
ndarray

(Y, X) for a single channel, otherwise (2, Y, X).

smint.segmentation.cellpose_compat.is_known_model

is_known_model(model)

True if model is a file path or a name Cellpose can load.

smint.segmentation.cellpose_compat.cellpose_major_version

cellpose_major_version()

Return the installed Cellpose major version as an int, or None if absent.

smint.segmentation.cellpose_compat.use_gpu

use_gpu()

Whether Cellpose can use a GPU in this process.

Post-processing

smint.segmentation.postprocess.calculate_centroids

calculate_centroids(contours_df, output_csv=None)

Calculate centroids for cells from contour data.

Parameters:

Name Type Description Default
contours_df DataFrame

DataFrame with contour points

required
output_csv str

Path to save centroids CSV

None

Returns:

Type Description
DataFrame

DataFrame with cell centroids

smint.segmentation.postprocess.combine_segmentation_results

combine_segmentation_results(csv_files, output_csv=None)

Combine multiple segmentation result CSV files.

Parameters:

Name Type Description Default
csv_files list

List of CSV file paths

required
output_csv str

Path to save combined CSV

None

Returns:

Type Description
DataFrame

Combined dataframe

smint.segmentation.extract_contours

extract_contours(mask_file, output_csv=None)

Extract contours from a mask file and optionally save to CSV.

Parameters:

Name Type Description Default
mask_file str

Path to mask file

required
output_csv str

Path to save CSV file

None

Returns:

Type Description
list

List of dictionaries containing contour information

smint.segmentation.save_masks

save_masks(masks_dict, output_path)

Save segmentation masks as PNG files.

Parameters:

Name Type Description Default
masks_dict dict

Dictionary containing masks from segmentation

required
output_path str

Path to save the masks

required

Returns:

Type Description
str

Path to the saved mask file

Configuration helpers

Used by scripts/run_segmentation.py to read and merge the YAML configuration described in Configuration.

smint.utils.config.load_config

load_config(config_path=None)

Load a YAML configuration file.

Parameters:

Name Type Description Default
config_path str

Path to the configuration file. If None, the first that exists of ./configs/segmentation_config.yaml, ~/.smint/config.yaml and the repository's configs/segmentation_config.yaml (see get_default_config_path).

None

Returns:

Type Description
dict

Configuration dictionary; empty (with a logged warning or error) if the file is missing or cannot be parsed.

smint.utils.config.merge_configs

merge_configs(base_config, override_config)

Merge two configuration dictionaries, with override_config taking precedence.

Parameters:

Name Type Description Default
base_config dict

Base configuration dictionary.

required
override_config dict

Configuration dictionary with overrides.

required

Returns:

Type Description
dict

Merged configuration dictionary.

smint.utils.config.validate_config

validate_config(config, schema=None)

Validate a configuration against a schema.

Parameters:

Name Type Description Default
config dict

Configuration dictionary to validate.

required
schema dict

Schema dictionary. If None, uses a basic schema.

None

The default schema requires model_paths and output_dir and checks that model_paths and chunk_size, when present, are lists.

Returns:

Type Description
tuple

(is_valid, errors): a bool and a list of error messages.

smint.utils.config.save_config

save_config(config, config_path=None)

Save a configuration to a file.

Parameters:

Name Type Description Default
config dict

Configuration dictionary.

required
config_path str

Path to save the configuration file. If None, uses the default location.

None

Returns:

Type Description
bool

True if successfully saved, False otherwise.

smint.utils.config.get_config_value

get_config_value(config, key_path, default=None)

Get a value from a nested configuration dictionary.

Parameters:

Name Type Description Default
config dict

Configuration dictionary.

required
key_path str

Path to the key, using dots to separate levels (e.g., 'model_params.diameter').

required
default Any

Value to return if the key is not found.

None

Returns:

Type Description
Any

The value at the specified key path, or default if not found.

smint.utils.config.get_default_config_path

get_default_config_path()

Get the default path for the configuration file.

Returns:

Type Description
Path

Path to the default configuration file.

Next steps