"""Synthesize a clean microscopy-like image and a degraded (blurred + noisy) version.""" from __future__ import annotations import numpy as np def clean_image(h: int = 256, w: int = 256, seed: int = 0) -> np.ndarray: """A microscopy-style scene: blobs (cells) + filaments, values in [0, 1].""" rng = np.random.default_rng(seed) img = np.zeros((h, w), np.float32) yy, xx = np.mgrid[0:h, 0:w] for _ in range(35): # blobs cy, cx = rng.uniform(0, h), rng.uniform(0, w) r = rng.uniform(3, 9) img += rng.uniform(0.4, 1.0) * np.exp(-(((yy - cy) ** 2 + (xx - cx) ** 2) / (2 * r ** 2))) for _ in range(12): # filaments y0, x0 = rng.uniform(0, h), rng.uniform(0, w) ang = rng.uniform(0, np.pi) for t in np.linspace(0, rng.uniform(20, 60), 200): y, x = int(y0 + t * np.sin(ang)), int(x0 + t * np.cos(ang)) if 0 <= y < h and 0 <= x < w: img[max(0, y - 1):y + 1, max(0, x - 1):x + 1] += 0.5 return np.clip(img / max(img.max(), 1e-6), 0, 1) def degrade(clean: np.ndarray, psf_sigma: float = 2.0, peak: float = 40.0, read_sigma: float = 0.03, seed: int = 1) -> np.ndarray: """Blur with a Gaussian PSF, then add Poisson (shot) + Gaussian (read) noise.""" from scipy.ndimage import gaussian_filter rng = np.random.default_rng(seed) blurred = gaussian_filter(clean, sigma=psf_sigma) shot = rng.poisson(np.clip(blurred, 0, None) * peak) / peak # photon noise noisy = shot + rng.normal(0, read_sigma, clean.shape) # read noise return np.clip(noisy, 0, 1).astype(np.float32)