spacr.spacrops

Module Contents

class spacr.spacrops.spacrStitcher(detector: str = 'ORB', nfeatures: int = 6000, max_keypoints: int | None = 2000, downsample: float = 0.5, ransac_thresh_px: float = 3.0, allow_scale: bool = False, allow_rotation: bool = False, outline_source: str = 'otsu', canny: Tuple[int, int] = (40, 120), blur_sigma: float = 0.0, dilate_ksize: int = 0, line_thickness: int = 1, outline_alpha: float = 1.0, outdir: str = './sbs_out', save_qc: bool = True, save_stitched_default: bool = True, all_scores: bool = False, score_threshold: float | None = None, verbose: bool = False, feature_cache_mode: str = 'disk', feature_cache_dir: str | None = None, max_ram_features: int = 256, n_workers_features: int | None = None, pair_batch_size: int = 8000, stream_csv: bool = True, opencv_threads: int = 1, arr_axes: str = 'AUTO', mip: bool = False, z_index: int = 0, t_index: int = 0, squeeze_singleton: bool = True)[source]

Pairwise stitcher with downsampled scoring and whole-well mosaic assembly.

Robustness features for very large datasets:
  • feature_cache_mode: “disk” (default) writes DS features to disk with an LRU RAM cap

  • pair_batch_size: limit number of concurrent pair futures

  • stream_csv: write pairwise rows immediately (low RAM)

  • opencv_threads: limit OpenCV internal threading to avoid oversubscription

Transform control

allow_scale: if True → use RANSAC affine (rotation+scale+translation)

if False → enforce unit scale (see allow_rotation)

allow_rotation: if True → rotation+translation

if False → translation-only

Mosaic

Uses topology-aware pruning + maximum spanning tree on pairwise scores to build a cohesive grid. Exports mosaic image and a mosaic.csv manifest.

Axis & Z handling

arr_axesstr in {“AUTO”} or a string over {T,C,Z,Y,X} (e.g. “CZYX”, “CYX”, “ZYX”).

Determines how to interpret multi-dimensional TIFFs.

mip : bool. If True and Z exists, perform max-intensity projection over Z. z_index : int (if mip=False) choose Z slice index. t_index : int choose time index if T exists.

detector = ''[source]
nfeatures = 6000[source]
max_keypoints = None[source]
downsample[source]
ransac_thresh_px[source]
allow_scale = False[source]
allow_rotation = False[source]
outline_source = ''[source]
canny = (40, 120)[source]
blur_sigma[source]
dilate_ksize = 0[source]
line_thickness = 1[source]
outline_alpha[source]
outdir = b'.'[source]
save_qc = True[source]
save_stitched_default = True[source]
all_scores = False[source]
score_threshold = None[source]
verbose = False[source]
feature_cache_mode = ''[source]
n_workers_features[source]
pair_batch_size = 8000[source]
stream_csv = True[source]
arr_axes = ''[source]
mip = False[source]
z_index = 0[source]
t_index = 0[source]
squeeze_singleton = True[source]
set_meta_regex(pattern: str | re.Pattern)[source]

Replace the filename regex used to parse well, site, channel and magnification.

prepare_features(paths: List[str], channel_index: int, num_workers: int | None = None)[source]

Precompute keypoints and descriptors for paths and cache them.

In disk mode every result is flushed to the on-disk feature store with only an LRU-sized subset kept in RAM; in ram mode results are held in memory only.

Parameters:
  • paths – image files to feature.

  • channel_index – channel to read from multi-channel TIFFs.

  • num_workers – worker thread count; defaults to self.n_workers_features.

Returns:

None.

stitch_pair(pathA: str, pathB: str, channel_index: int = 0, score_threshold: float | None = None, save_stitched: bool | None = None, force_no_qc: bool = False, qc_only_if_score_ge: float | None = None) Dict | None[source]

Estimate the B-to-A affine, score the overlap, and optionally write the stitched pair.

Parameters:
  • pathA – reference image path.

  • pathB – image to align to pathA.

  • channel_index – channel used for feature matching. Default 0.

  • score_threshold – minimum edge-ZNCC score required to save the stitched TIFF; falls back to self.score_threshold.

  • save_stitched – override for whether to write the stitched image; falls back to self.save_stitched_default.

  • force_no_qc – suppress QC overlay images regardless of settings.

  • qc_only_if_score_ge – emit QC overlays only when the pair score meets this cutoff.

Returns:

dict of pair metrics and output paths, or None when matching/RANSAC fails.

run_folder(folder: str, csv_path: str, *, channel_index: int = 0, exts: Tuple[str, Ellipsis] = ('.tif', '.tiff'), recursive: bool = False, same_well_only: bool = True, max_site_gap: int = 3, n_workers: int = 8, stitch: bool = True, score_threshold: float | None = None, meta_regex: str | re.Pattern | None = None, mosaic: bool = False, mosaic_out: str | None = None, mosaic_min_score: float | None = None, mosaic_csv_out: str | None = None, mosaic_all_channels: bool = False, mosaic_channel_count: int | None = None, mosaic_channel_index_order: List[int] | None = None, qc_pairs_threshold: int = 1000, qc_only_above_threshold_when_many: bool = True) str[source]

Score every candidate pair in folder and optionally build a whole-well mosaic.

When the number of candidate pairs exceeds qc_pairs_threshold, QC overlays are skipped in the first pass and reissued only for pairs whose score clears the auto-threshold in the second pass.

Parameters:
  • folder – directory of tiles to scan.

  • csv_path – destination CSV for pairwise metrics.

  • channel_index – channel used for feature scoring. Default 0.

  • exts – accepted image extensions.

  • recursive – recurse into subfolders. Default False.

  • same_well_only – restrict pairings to the same parsed well. Default True.

  • max_site_gap – maximum site-index gap between candidate neighbours. Default 3.

  • n_workers – worker threads for the scoring pass. Default 8.

  • stitch – save stitched TIFFs for pairs above the score threshold.

  • score_threshold – minimum score required to save the stitched image.

  • meta_regex – override the filename regex before scanning.

  • mosaic – build a single-channel mosaic once pair scoring finishes.

  • mosaic_out – output TIFF path for the mosaic (single-channel mode).

  • mosaic_min_score – minimum edge score used when pruning mosaic edges.

  • mosaic_csv_out – output CSV path for the mosaic manifest.

  • mosaic_all_channels – build a CYX mosaic across all channels.

  • mosaic_channel_count – force this many channels for the multi-channel mosaic.

  • mosaic_channel_index_order – explicit channel order for the multi-channel mosaic.

  • qc_pairs_threshold – pair count above which QC plotting is gated.

  • qc_only_above_threshold_when_many – enable the second-pass, score-gated QC output.

Returns:

path to the pairwise-metrics CSV.

build_multichannel_mosaic_from_manifest(manifest_csv: str, out_tif: str, out_png: str | None = None, channel_indices: List[int] | None = None, blend: str = 'max', tmp_dir: str | None = None, preview_downsample: int = 8)[source]

Build a CYX BigTIFF mosaic from a ‘mosaic.csv’ manifest written by spacrStitcher.render_mosaic_from_csv(…).

Expected CSV columns (per tile row):
  • path, H, W, M00, M01, M02, M10, M11, M12, canvas_x, canvas_y, best_pair_score

Notes

  • Uses the 2x3 affine in the manifest (already includes global offset).

  • If channel_indices is None, infers the channel count from the first valid tile.

  • blend=”max” takes per-pixel max across overlapping tiles; blend=”overwrite” writes the latest tile over earlier ones where coverage>0.

  • If tmp_dir is provided (or available from self.feature_cache_dir), the output workspace uses a disk memmap to reduce RAM.

render_mosaic_from_csv(csv_path: str, out_tif: str, out_png: str | None = None, channel_index: int = 0, min_score: float | None = None, *, angle_tol_deg: float = 30.0, step_tol_frac: float = 0.25, rot_tol_deg: float = 5.0, scale_tol: float = 0.03, cap_one_per_dir: bool = True, out_csv: str | None = None) Tuple[str, str | None][source]

Assemble a mosaic image (and manifest) from a pairwise-metrics CSV.

Pass out_tif=None together with an out_csv to run in manifest-only mode (transforms are computed and written but no image is rendered).

Parameters:
  • csv_path – input pairwise metrics CSV.

  • out_tif – mosaic TIFF output path (None for manifest-only).

  • out_png – optional preview PNG output path.

  • channel_index – channel used for rendering. Default 0.

  • min_score – minimum pair score kept for the mosaic (auto-detected when None).

  • angle_tol_deg – tolerance for classifying edges into R/L/U/D bins.

  • step_tol_frac – fractional tolerance around the estimated grid step.

  • rot_tol_deg – max allowed rotation when rotation is disabled.

  • scale_tol – max allowed scale deviation when scaling is disabled.

  • cap_one_per_dir – keep at most one edge per direction per tile.

  • out_csv – optional path to the per-tile manifest CSV.

Returns:

tuple (out_tif, out_png).

mosaic_all_channels_from_csv(csv_path: str, out_tif: str | None, *, min_score: float | None = None, channel_count: int | None = None, channel_index_order: List[int] | None = None, angle_tol_deg: float = 30.0, step_tol_frac: float = 0.25, rot_tol_deg: float = 5.0, scale_tol: float = 0.03, cap_one_per_dir: bool = True, out_csv: str | None = None) str | None[source]

Assemble a multi-channel CYX mosaic by reusing pairwise transforms across channels.

Pass out_tif=None with an out_csv to run in manifest-only mode (compute transforms and canvas geometry, write manifest, skip rendering).

Parameters:
  • csv_path – input pairwise metrics CSV.

  • out_tif – mosaic TIFF output path (None for manifest-only).

  • min_score – minimum pair score kept for the mosaic (auto-detected when None).

  • channel_count – force this many channels; auto-detected when None.

  • channel_index_order – explicit channel index ordering for the output.

  • angle_tol_deg – tolerance for classifying edges into R/L/U/D bins.

  • step_tol_frac – fractional tolerance around the estimated grid step.

  • rot_tol_deg – max allowed rotation when rotation is disabled.

  • scale_tol – max allowed scale deviation when scaling is disabled.

  • cap_one_per_dir – keep at most one edge per direction per tile.

  • out_csv – optional per-tile manifest CSV path.

Returns:

path to the mosaic TIFF (or None in manifest-only mode).

class spacr.spacrops.StitchedMultiAligner(detector: str = 'ORB', nfeatures: int = 6000, max_keypoints: int | None = 2000, downsample: float = 0.5, ransac_thresh_px: float = 3.0, allow_scale: bool = False, allow_rotation: bool = False, outdir: str = './align_out', opencv_threads: int = 1, arr_axes: str = 'AUTO', mip: bool = False, z_index: int = 0, t_index: int = 0, squeeze_singleton: bool = True)[source]

Align an arbitrary number of stitched mosaics (multi-channel, arbitrary axes) to a common reference using the nuclei/ Hoechst channel. Saves a channel-concatenated aligned stack and a CSV manifest describing the mapping from input channels to output channels and the estimated transforms/scores.

Output image axes: CYX (channels stacked in the order inputs are provided).

Parameters:
  • detector ({"ORB","SIFT"}) – Feature detector for keypoint matching.

  • nfeatures (int) – Feature budget for detector.

  • max_keypoints (Optional[int]) – Hard cap on kept keypoints after detection (by detector’s internal ranking).

  • downsample (float in (0,1]) – Downsample factor for feature/score pass.

  • ransac_thresh_px (float) – Reprojection threshold (pixels) for affine estimation (downsampled space).

  • allow_scale (bool) – If False, constrain to rotation+translation (or translation only if allow_rotation=False).

  • allow_rotation (bool) – If False, constrain to translation only.

  • outdir (str) – Output directory for images/csv.

  • opencv_threads (int) – Limit OpenCV internal threading (avoid oversubscription).

  • reading) (# Axis/Z/time handling (for TIFF)

  • arr_axes ("AUTO" or a string over {T,C,Z,Y,X})

  • mip (bool) – If True and Z exists, max-project Z.

  • z_index (int) – If mip=False, choose Z slice.

  • t_index (int) – Choose T index if T exists.

  • squeeze_singleton (bool) – Squeeze 1-length axes after slicing.

Notes

  • Alignment is done to the first image in paths (reference).

  • For each image, you can provide a per-image nuclei channel index via nuclei_channel_indices. If None, defaults to 0 for all.

detector = ''[source]
nfeatures = 6000[source]
max_keypoints = None[source]
downsample[source]
ransac_thresh_px[source]
allow_scale = False[source]
allow_rotation = False[source]
outdir = b'.'[source]
arr_axes = ''[source]
mip = False[source]
z_index = 0[source]
t_index = 0[source]
squeeze_singleton = True[source]
align(paths: List[str], nuclei_channel_indices: List[int] | None = None, out_tif: str | None = None, out_png_preview: str | None = None, csv_path: str | None = None) Tuple[str, str | None, str | None][source]

Align every stitched mosaic in paths to the first and save a CYX stack.

Alignment uses the specified nuclei channel per image; the resulting stack concatenates all input channels in the order given.

Parameters:
  • paths – stitched TIFFs to align; paths[0] is the reference.

  • nuclei_channel_indices – per-image nuclei channel indices; defaults to zeros.

  • out_tif – output aligned stack path; defaults to <outdir>/aligned_allc.tif.

  • out_png_preview – optional preview PNG path.

  • csv_path – manifest CSV path; defaults to <outdir>/aligned_manifest.csv.

Returns:

tuple (out_tif, out_png_preview, csv_path).

spacr.spacrops.stitch_cycle_wells(settings)[source]

Organize a plate of TIFFs into per-well folders and stitch each well.

Groups images by well from filename metadata, optionally moves or symlinks them into per-well folders, then runs spacrStitcher on each well to produce pairwise CSVs and single- or multi-channel mosaics.

Parameters:

settings – dict of preprocess settings; see get_preprocess_ops_settings() for supported keys.

Returns:

dict with keys organized (move/symlink summary) and wells (per-well output paths).

spacr.spacrops.get_preprocess_ops_settings(settings)[source]

Fill in defaults for the ops preprocessing / stitching / alignment pipeline.

Parameters:

settings – user-supplied settings dict, updated in place with defaults.

Returns:

the settings dict with all defaults populated.

class spacr.spacrops.FOVAlignAndCropper(detector: str = 'ORB', nfeatures: int = 6000, max_keypoints: int | None = 2000, downsample: float = 0.5, ransac_thresh_px: float = 3.0, allow_scale: bool = False, allow_rotation: bool = False, outdir: str = './fov_out', opencv_threads: int = 1, arr_axes: str = 'AUTO', mip: bool = False, z_index: int = 0, t_index: int = 0, squeeze_singleton: bool = True, folder_image_scale: float = 1.0)[source]

Align individual FOVs to a stitched mosaic and export FOV-frame stacks.

For each FOV, saves a .npy with shape (C_fov + C_mosaic, H_fov, W_fov) (native FOV channels stacked with the mosaic channels warped into the FOV frame) and a CSV row with the transform, score and mosaic bbox.

Delegates feature/matching helpers to StitchedMultiAligner.

Parameters:
  • detector – keypoint detector ('ORB' or 'SIFT'). Default 'ORB'.

  • nfeatures – feature budget for the detector.

  • max_keypoints – hard cap on kept keypoints after detection.

  • downsample – downsample factor for the feature/score pass.

  • ransac_thresh_px – RANSAC reprojection threshold (pixels, downsampled space).

  • allow_scale – allow scale in the estimated affine.

  • allow_rotation – allow rotation in the estimated affine.

  • outdir – output directory. Default './fov_out'.

  • opencv_threads – OpenCV internal thread cap.

  • arr_axes – TIFF axis interpretation ('AUTO' or string over TCZYX).

  • mip – max-project Z when present.

  • z_index – Z slice to select if mip is false.

  • t_index – T slice to select if T is present.

  • squeeze_singleton – squeeze length-1 axes after slicing.

  • folder_image_scale – default FOV-to-mosaic pixel-scale factor used by run().

outdir = b'.'[source]
folder_image_scale[source]
run(stitched_path: str, folder: str, *, stitched_nuclei_idx: int = 0, fov_nuclei_idx: int = 0, exts: Tuple[str, Ellipsis] = ('.tif', '.tiff'), recursive: bool = False, csv_path: str | None = None, npy_dir: str | None = None, folder_image_scale: float | None = None) str[source]

Align every FOV in folder to stitched_path and export FOV-frame stacks.

Uses the nuclei channel for alignment and writes one .npy per FOV containing the FOV channels plus mosaic channels warped into the FOV frame.

Parameters:
  • stitched_path – path to the reference stitched mosaic.

  • folder – directory of FOV TIFFs to align.

  • stitched_nuclei_idx – nuclei channel index in the mosaic. Default 0.

  • fov_nuclei_idx – nuclei channel index in each FOV. Default 0.

  • exts – accepted FOV extensions.

  • recursive – recurse into subfolders.

  • csv_path – output manifest CSV path; defaults to <outdir>/fov_align_manifest.csv.

  • npy_dir – output folder for the per-FOV .npy stacks; defaults to <outdir>/npy.

  • folder_image_scale – FOV-to-mosaic pixel-scale factor; falls back to self.folder_image_scale.

Returns:

path to the manifest CSV.

spacr.spacrops.align_image_to_stitch(stitch_dst_root: str, align_src: str, *, meta_regex: str = '(?P<mag>\\d+X)_c(?P<chan>\\d+)_?(?P<well>[A-H]\\d{1,2}).*?Site[-_](?P<site>\\d+)\\.(?:tif|tiff)$', well_group: str = 'well', channel_index: int = 0, relative_scale: float = 2.0, downsample: float = 0.5, nfeatures: int = 4000, ransac_thresh_px: float = 3.0, allow_scale: bool = False, allow_rotation: bool = False, qc_outlines: bool = False, recursive_align_src: bool = True, exts: tuple = ('.tif', '.tiff')) Dict[str, Dict[str, str]][source]

Align each well’s higher-mag FOVs to that well’s stitched mosaic.

For every well with a mosaic at <stitch_dst_root>/<WELL>/_stitch/mosaic_allc.tif, groups images from align_src by well and runs FOVAlignAndCropper to produce per-well crop manifests and .npy crops.

Parameters:
  • stitch_dst_root – root folder containing per-well stitched mosaics.

  • align_src – folder of higher-magnification images to align.

  • meta_regex – regex extracting well/site metadata from filenames.

  • well_group – named capture group holding the well identifier.

  • channel_index – nuclei channel index. Default 0.

  • relative_scale – FOV-to-mosaic pixel-scale factor. Default 2.0.

  • downsample – feature-pass downsample factor. Default 0.5.

  • nfeatures – keypoint budget for the detector.

  • ransac_thresh_px – RANSAC reprojection threshold in pixels.

  • allow_scale – allow scale in the estimated affine.

  • allow_rotation – allow rotation in the estimated affine.

  • qc_outlines – emit QC outline overlays.

  • recursive_align_src – recurse when scanning align_src.

  • exts – accepted image extensions.

Returns:

mapping {well: {'mosaic': path, 'align_folder': path, 'manifest_csv': path}}.

spacr.spacrops.ops_preprocess(settings)[source]

Run the full ops preprocessing pipeline: per-genotype stitching + phenotype alignment.

Iterates over one or more genotype folders, calls stitch_cycle_wells() on each, then aligns the phenotype images to the resulting mosaics via align_image_to_stitch().

Parameters:

settings – dict of preprocessing settings; see get_preprocess_ops_settings() for supported keys.

Returns:

dict with stitch (per-genotype summaries), align (per-genotype align results) and npy_out_root (npy output root path).