Integrating EZStitcher with Other Tools
This page demonstrates two realistic integration patterns that crop up in fluorescence-microscopy workflows:
Illumination correction with *BaSiCPy* ➜ self-supervised denoising with *N2V2* (Careamics)
Template-matching cropper - automatically grab a region of interest from the stitched mosaic.
If you have not read Advanced Usage, start there first - it explains custom functions and multithreading, which we reuse below.
All functions passed to Step must accept a list of images and return a list of images of equal length. Saving to disk should be handled by the pipeline or a separate post-hoc script.
1. BaSiCPy + N2V2 denoising
BaSiCPy removes slowly varying illumination fields. Careamics-N2V2 performs noise-to-void denoising without clean targets.
from pathlib import Path
import numpy as np
import basicpy # pip install basicpy (Peng-Lab fork)
from careamics.models import N2V2 # pip install careamics==0.1
from ezstitcher.core.pipeline_orchestrator import PipelineOrchestrator
from ezstitcher.factories import AutoPipelineFactory
from ezstitcher.core.pipeline import Pipeline
from ezstitcher.core.steps import Step
# -------------- orchestrator + stitching -----------------------
plate_path = Path("~/data/PlateA").expanduser()
orchestrator = PipelineOrchestrator(plate_path)
base_factory = AutoPipelineFactory(
input_dir=orchestrator.workspace_path,
normalize=True,
)
pipelines = base_factory.create_pipelines() # [0] = position, [1] = assembly
# -------------- helper functions -------------------------------
def flatfield_basicpy(images):
"""Return BaSiCPy-corrected stack."""
stack = np.dstack(images) # z-axis last for BaSiCPy
shading, background = basicpy.BaSiC(threshold=0.01).fit(stack)
corrected = (stack - background) / shading
return [corrected[..., i] for i in range(corrected.shape[-1])]
n2v2 = N2V2.from_pretrained("n2v2_fluo")
def denoise_n2v2(images):
return [n2v2.predict(im, axes="YX") for im in images]
post_pipe = Pipeline(
input_dir=pipelines[1].output_dir, # stitched TIFFs
output_dir=Path("out/illcorr_n2v2"),
steps=[
Step(name="BaSiC flat-field", func=flatfield_basicpy),
Step(name="N2V2 denoise", func=denoise_n2v2),
],
name="BaSiC + N2V2",
)
pipelines.append(post_pipe)
orchestrator.run(pipelines=pipelines)
2. ROI extraction via template matching (Multi-Template-Matching)
For a lighter dependency we use the Multi-Template-Matching wrapper around OpenCV. It can handle multiple templates and returns bounding boxes directly.
Install once with
pip install multitpletematch # actual PyPI name: multitpletematch
from pathlib import Path
import numpy as np
import cv2
import multitpletematch as mtm # MultiTemplateMatching
templates = [cv2.imread(str(p), cv2.IMREAD_ANYDEPTH)
for p in Path("templates").glob("*.tif")]
matcher = mtm.MultiTemplateMatching(method=cv2.TM_CCOEFF_NORMED,
maxOverlap=0.1,
scoreThreshold=0.6)
def crop_by_template(images, pad=20):
"""Crop around first high-score template match for each image."""
outs = []
for im in images:
bboxes, _ = matcher.matchTemplates(templates, im, N_object=1)
if not bboxes:
outs.append(im) # fallback: no crop
continue
x, y, w, h = bboxes[0]['bbox'] # mtm gives (x, y, w, h)
y1 = max(y - pad, 0)
x1 = max(x - pad, 0)
y2 = min(y + h + pad, im.shape[0])
x2 = min(x + w + pad, im.shape[1])
outs.append(im[y1:y2, x1:x2])
return outs
crop_pipe = Pipeline(
input_dir=pipelines[1].output_dir,
output_dir=Path("out/roi_crop"),
steps=[Step(name="Template crop", func=crop_by_template)],
name="ROI Cropper",
)
orchestrator.run(pipelines=[crop_pipe])