Stitched Image Quality Control
Overview
Quality control for stitched microscopy images to detect common processing failures:
- Saturation: Images that appear blank white due to BaSiC correction issues
- Tile grid patterns: Visible seams between tiles due to improper blending
Trigger Conditions
Activate this skill when:
- User reports "blank white" or "saturated" stitched images
- User reports visible tile boundaries or grid patterns
- Processing stitched images for a new dataset
- Running QC on processed outputs
Problem Detection Criteria
Saturation Issues
- More than 50% of pixels at near-maximum value (>64000 for uint16)
- Mean intensity significantly higher than expected (>60000 for typical microscopy)
- Usually affects edge z-planes (z1, z13) or specific cycles
Tile Grid Patterns
- High std/mean ratio (>0.8) indicating intensity discontinuities
- Visible rectangular boundaries in the image
- Often caused by:
- Flatfield values too low (clamped to BASIC_FLATFIELD_MIN)
- Stitch model computed from incompatible z-plane
- Blend sigma too small
Root Causes
BaSiC Correction Failures
The BaSiC algorithm estimates flatfield and darkfield corrections. Failures occur when:
- Low flatfield values: If flatfield drops below
BASIC_FLATFIELD_MIN(default 0.1), correction amplifies signal excessively - Incorrect normalization: Input must be normalized to [0,1] before correction
- Per-z-plane estimation: BaSiC is run per-z-plane; edge planes may have different characteristics
Stitching Issues
- Stitch model mismatch: Position model computed from one z-plane may not work for another
- Insufficient overlap blending: Sigmoid taper sigma too small for contrast differences
Solution Approach
Diagnostic Steps
from skimage.io import imread
import numpy as np
# Check image statistics
img = imread('path/to/stitched.tif')
mean_val = img.mean()
pct_max = 100.0 * np.sum(img > 64000) / img.size
std_mean_ratio = img.std() / img.mean()
print(f"Mean: {mean_val:.0f}")
print(f"Pct at max: {pct_max:.1f}%")
print(f"Std/Mean ratio: {std_mean_ratio:.2f}")
# Saturation: pct_max > 50%
# Tile grid: std_mean_ratio > 0.8
Reprocessing Fix
Use the reprocessing script at notebooks/reprocess_problematic_images.py:
# Dry run first
python reprocess_problematic_images.py --dry-run
# Then reprocess
python reprocess_problematic_images.py
Manual Reprocessing
from kintsugi.kcorrect_gpu import KCorrectGPU
from kintsugi.stitch_blend import stitch_with_blending_gpu
# Load tiles and normalize
tiles = load_tiles(...)
tiles_norm = tiles.astype(np.float64) / 65535
# BaSiC correction
corrector = KCorrectGPU(use_gpu=True, working_size=128)
flatfield, darkfield = corrector.fit(tiles_norm, if_darkfield=True)
# Apply correction with safe flatfield minimum
flatfield_safe = np.clip(flatfield, 0.1, None)
corrected = np.clip((tiles_norm - darkfield) / flatfield_safe, 0, 1)
corrected_uint16 = (corrected * 65535).astype(np.uint16)
# Stitch with proper blending
stitched = stitch_with_blending_gpu(
corrected_uint16,
result_df,
sigma=10.0,
overlap_fraction=(0.3, 0.3)
)
Prevention
Cache Validation
Always validate cached statistics before using:
from Kio import validate_stats_cache
if CACHE_FILE.exists():
with open(CACHE_FILE, 'rb') as f:
cached_df = pickle.load(f)
if validate_stats_cache(cached_df, source_dir, phase='stitched'):
use_cache = True
else:
use_cache = False # Recompute
Quality Checks Post-Processing
Add automatic QC after stitching:
# After stitching
pct_max = 100.0 * np.sum(stitched > 64000) / stitched.size
if pct_max > 50:
print(f"WARNING: {pct_max:.1f}% saturated - check BaSiC parameters")
Related Files
notebooks/reprocess_problematic_images.py- Batch reprocessing scriptkintsugi/kcorrect_gpu.py- BaSiC GPU implementationkintsugi/stitch_blend.py- Sigmoid taper blendingnotebooks/Kio.py- Cache validation functionsnotebooks/Kutils.py- Quantification comparison functions
See Also
gpu-quality-priority- Always prioritize quality over speedbasic-caching-evaluation- BaSiC caching considerations