photometry op• Data kinds: image2d × keypoints → table
• Call: import fullseye as fs; fs.ledger.psf_fit(image, centers, model='gaussian', box=11, max_iter=200) (to call the implementation directly, import astrostack; astrostack.psf_fit(image, centers, model='gaussian', box=11, max_iter=200); from the registry, opsastrostack.get("psf_fit"))
Fit a PSF to a star image and get its centre and FWHM.
*model* "gaussian" is a 6-parameter fit of an elliptical Gaussian bkg + amp * exp(-((dr/sr)^2 + (dc/sc)^2)/2), and the roundness (roundness = min(sr,sc)/max(sr,sc)) comes out as a by-product —— star images stretched by tracking error or wind show up here. "moffat" is the circularly symmetric bkg + amp * (1 + r^2/alpha^2)^(-beta) (Moffat 1969), with beta also a free parameter. Least squares is scipy.optimize.least_squares (Trust Region Reflective), with deterministic initial values built from the 2nd moments —— no random numbers are used, so the same input gives the same answer.
FWHM is a closed form from the fitted parameters:
for the Gaussian 2 sqrt(2 ln 2) * sqrt(sr*sc) (geometric mean), for Moffat 2 alpha sqrt(2^(1/beta) - 1).
It always comes out wider by the pixel box. What is fitted here is a *continuous* Gaussian, but each pixel of the image is the continuous distribution integrated over a 1-pixel box. The variance of a uniform box of width 1 is 1/12, so the returned sigma is not the true sigma but sqrt(sigma^2 + 1/12) —— this is not an estimation error; the image is made that way. Measurements agree well with this prediction::
true FWHM predicted = 2.3548*sqrt(sigma^2+1/12) measured (median)
2.5 2.5908 2.5930
3.5 3.5654 3.5625
5.0 5.0460 5.0145
If you want the true sigma, subtract it as sqrt(sigma_fit^2 - 1/12), but by default it is not subtracted —— the "FWHM" commonly quoted in stellar measurement is the apparent width on the image, and silently inserting a correction would make it disagree with other tools' values.
Returns a list of one dict per star (table vocabulary). Keys are row / col (fitted centre), fwhm_px, amplitude, background, roundness, rms (residual RMS), converged (bool), model, and the model-dependent sigma_row_px / sigma_col_px or alpha_px / beta. Stars whose window sticks out of the image and stars whose fit did not converge are also returned, not dropped, with converged=False —— silently removing them would let nobody notice that "stars went missing".
Raises ValueError: if *model* is not in PSF_MODELS / *box* is less than 5 or even / *centers* is not (N, 2).
• Sample-data catalog (download URLs / licences) — 2-D uses skimage.data (BSD/public domain) plus synthetic images; 3-D lists download URLs for real data sources (Stanford, PDS, …).
• Operator provenance and references — the sources of the research/methods this op family came from.
• The canonical algorithm (author, year) and its uses are named in the family usage guide above.
• astro_stacking — py -3.11 examples/astro_stacking.py
• poc_star_astrometry — py -3.11 examples/poc_star_astrometry.py
table as input)—
photometry)star_detect · aperture_photometry
*Provenance: astrostack.py — ASTROSTACK operator registry. This per-op note is generated by tools/opdocs.py md (do not hand-edit).*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.