PSF Guard is my screening tool for N.I.N.A. astrophotography sessions: it sifts through captured sub-frames, grades them visually and automatically, and writes the verdicts back to the Target Scheduler database so rejected frames get recaptured on the next clear night. The 0.4 release (v0.4.0, with a v0.4.1 fix release close behind) is a big one: it gains a detection engine for the failure modes that conventional metrics are blind to.
The problem: global statistics lie
The classic screening signals — star count and HFR — are global statistics, and they fail in embarrassing ways. Validating against real sessions, frames with a visibly tree-occluded corner kept star counts within normal variation, and HFR stayed flat until frames were more than 60% blocked. Slow-growing occlusions were even worse: they absorbed into the rolling baselines (“boiling frog”) and stopped being flagged at all. Meanwhile small clouds and thin veils don’t remove stars, they dim them — frames with stars 20–40% dimmer were sailing through every existing check.
Spatial occlusion detection
Each frame now gets an 8×6 grid of local metrics: the fraction of “dead” cells with no detected stars, star uniformity, and background cell spread in physical ADU (comparable across frames — a subtle but critical fix, since FITS frames are rescaled per-frame). The sequence analyzer freezes its baseline on anomalous frames so slow occlusions can’t sneak in, and it distinguishes localized obstruction (trees, dome edges) from uniform veiling (clouds) and stray-light gradients. On a real night of progressive tree occlusion, scores degrade monotonically from 0.88 to 0.04 with the reject boundary confirmed frame-by-frame by eye.
Photometric screening
For the damage that dims rather than blocks, 0.4 adds classical differential photometry — no machine learning involved. Stars are matched across the session against a reference catalog with median fluxes, and each frame gets a transparency measure (median matched-star flux ratio — the same technique all-sky cloud monitors use) plus per-cell extinction maps. A thin veil reads as transparency 0.6–0.8 while every other metric stays normal; a small cloud’s footprint shows up as a patch of locally extinguished cells; a transient background rise that the frame’s own gradient can’t explain gets classified as errant light (car headlights, flashlights) and softened to a recoverable warning instead of a reject. On one archived session this pass found five true positives that both N.I.N.A. and the previous screening had accepted.
Show your work
My favorite part: every WARN or REJECT verdict can be rendered as an annotated diagnostic image — grid overlay with dead cells in red, localized extinction in orange with flux ratios, transient star loss in magenta, and background rises in yellow, plus a caption explaining the classifier’s reasoning. When the tool rejects a frame, you can see exactly why, and argue with it.

All of this is available three ways: the new DB-free psf-guard screen-fits
CLI command for any directory of FITS files, a “Scan Occlusion” button with
live progress in the desktop/web UI, and the server API — with the scan work
spread over a priority-aware worker pool so browsing stays responsive during
analysis.
Grab it from psf-guard.com or the GitHub releases — desktop apps for Windows/macOS/Linux, standalone CLI binaries, Fedora RPMs, and Docker images.