Imaging Applications¶
Curve fitting workflows for image analysis and microscopy.
2D Gaussian Fitting¶
Point Spread Function (PSF)¶
import numpy as np
import jax.numpy as jnp
from nlsq import fit
def gaussian_2d(xy, amplitude, x0, y0, sigma_x, sigma_y, theta, offset):
"""2D Gaussian with rotation."""
x, y = xy
a = jnp.cos(theta) ** 2 / (2 * sigma_x**2) + jnp.sin(theta) ** 2 / (2 * sigma_y**2)
b = -jnp.sin(2 * theta) / (4 * sigma_x**2) + jnp.sin(2 * theta) / (4 * sigma_y**2)
c = jnp.sin(theta) ** 2 / (2 * sigma_x**2) + jnp.cos(theta) ** 2 / (2 * sigma_y**2)
return offset + amplitude * jnp.exp(
-(a * (x - x0) ** 2 + 2 * b * (x - x0) * (y - y0) + c * (y - y0) ** 2)
)
# Prepare data for 2D fitting
x = np.arange(image.shape[1])
y = np.arange(image.shape[0])
X, Y = np.meshgrid(x, y)
xy_data = (X.ravel(), Y.ravel())
z_data = image.ravel()
# Fit
popt, pcov = fit(
gaussian_2d,
xy_data,
z_data,
p0=[image.max(), image.shape[1] // 2, image.shape[0] // 2, 5, 5, 0, image.min()],
)
Symmetric 2D Gaussian¶
def gaussian_2d_symmetric(xy, amplitude, x0, y0, sigma, offset):
"""2D Gaussian with equal width in x and y."""
x, y = xy
r_sq = (x - x0) ** 2 + (y - y0) ** 2
return offset + amplitude * jnp.exp(-r_sq / (2 * sigma**2))
Airy Disk Pattern¶
from scipy.special import j1
def airy_disk(xy, I0, x0, y0, radius, offset):
"""Airy disk pattern for diffraction-limited spots."""
x, y = xy
r = jnp.sqrt((x - x0) ** 2 + (y - y0) ** 2) / radius
# Handle r=0 case
r = jnp.where(r < 1e-10, 1e-10, r)
pattern = (2 * j1(r) / r) ** 2
return offset + I0 * pattern
FRAP Analysis¶
Single Component Recovery¶
def frap_single(t, F0, Finf, tau):
"""Single-component FRAP recovery."""
return Finf - (Finf - F0) * jnp.exp(-t / tau)
Two Component Recovery¶
def frap_double(t, F0, Finf, f_fast, tau_fast, tau_slow):
"""Two-component FRAP (fast + slow diffusion)."""
recovery_fast = f_fast * (1 - jnp.exp(-t / tau_fast))
recovery_slow = (1 - f_fast) * (1 - jnp.exp(-t / tau_slow))
return F0 + (Finf - F0) * (recovery_fast + recovery_slow)
# FRAP fitting
popt, pcov = fit(
frap_single,
time,
fluorescence,
p0=[0.2, 1.0, 5.0],
bounds=([0, 0, 0.1], [1, 2, 1000]),
)
Large Image Handling¶
For images larger than 1 megapixel:
from nlsq import curve_fit_large
if image.size > 1_000_000:
popt, pcov = curve_fit_large(
gaussian_2d,
xy_data,
z_data,
p0=p0,
show_progress=True,
)
else:
popt, pcov = fit(gaussian_2d, xy_data, z_data, p0=p0)
Tips for Image Fitting¶
Pre-process images:
Subtract background
Remove hot pixels
Apply appropriate smoothing
Estimate initial guesses:
# Find centroid x0_guess = np.average(x, weights=image) y0_guess = np.average(y, weights=image) # Estimate width from second moments sigma_guess = np.sqrt(np.average((x - x0_guess) ** 2, weights=image))
Use ROI for faster fitting: Crop to region of interest
For batch spot fitting, consider using optimized libraries like scikit-image for detection, then NLSQ for precise fitting.
See Also¶
Large Datasets - Large dataset tutorial
Large Dataset Tutorial - Large data guide