Quality Screening

A quality scan measures each light frame's stars, sky, photometry and plate solve, then scores the frame against its session and its whole target. This page covers what the scan catches, how scores and causes work, how to cut and select frames in Sequence, and how to run the scan from the app or the CLI.

New in 0.12. The Sequence chart marks each frame's grade, Cutoff measures stars or HFR as well as the score, a Select rule stays on, and Scoring has defaults of its own and two more penalties, HFR rise and Star loss.

Run a quality scan

In the app
Choose a target and click Analyze Quality.

The button shows in Images and Sequence when the target has new frames or results from an older quality model, and hides when every frame is up to date.

Sequence view →

The scan runs in the background: spatial and photometric screening, then a fresh plate solve of each frame, then new sequence scores. Both stages work on several frames at once, up to the share set in Settings › Performance › Processor use. The header's jobs chip shows progress from any view and any database. A scan with failed frames leaves a note on the chip, with a link to the target's sequence, until you dismiss it; with nothing else running the chip reads Finished with errors. Results persist across restarts.

Settings › Databases holds the database-wide actions. Analyze Missing Quality scans frames that have no results. Rescan All Quality forces a full rescan. Analyze new frames as they arrive scans frames that come by sync, peer pull, remote upload or auto-import a few minutes after they land. See Import Images.

Compare one capture session. These stored grades are Rejected; the scores still show the differences between frames.
Compare one capture session. These stored grades are Rejected; the scores still show the differences between frames.

Sequence shows coverage badges, causes, a solved-center scatter, a session view, and a stack comparison across all sessions for each filter. When the analysis finds a cause, the same cause and its evidence appear on the Sequence card, the grid card and the image detail's Quality analysis panel. For a local finding, that panel offers Show affected regions: the 8×6 scan cells behind the finding, with a legend. A whole-frame finding, such as a thin veil, has no region to draw.

The panels beside the frame fold away: click a panel's title to fold or open it. Folded, Quality analysis keeps one line with the score and any reject reason, and each panel stays as you left it from image to image.

Open a frame to inspect its pixels, quality findings and solved sky context.
Open a frame to inspect its pixels, quality findings and solved sky context.

In Images, Flag narrows the grid to frames with any of the causes you tick. The grid scores one target, project or database at a time and never compares frames from unrelated targets. It reads stored metadata and cached evidence and does not start a scan, It also shows how many visible frames remain unscored because they lack a comparable sequence or enough evidence.

To reject in bulk, choose a rule under Select in Sequence, then click Review rejection. Nothing is written until you confirm in the review. See Select frames by rule.

CLI / NAS
Screen folders without a database, or regrade one.

Add --regrade-db for target-aware checks and grade proposals.

CLI reference →
# Screen a night of lights (no database needed)
psf-guard screen-fits "/path/to/2026-06-30/LIGHT"

# Render an annotated diagnostic PNG for every WARN/REJECT frame
psf-guard screen-fits "/path/to/LIGHT" --annotate /tmp/diagnostics

# Add target-aware astrometry and propose/write supported [Auto] rejections
# (dry-run first; frames matched by filename AND capture timestamp)
psf-guard screen-fits "/path/to/LIGHT" --regrade-db my-db-slug --dry-run
psf-guard screen-fits "/path/to/LIGHT" --regrade-db my-db-slug

# Then archive the rejected files out of your stacking tree
psf-guard move-rejects --db my-db-slug

CLI screening reports OK, WARN and REJECT verdicts. A scan you start from the app may download the orbital elements it needs for satellite checks; opening Sequence and CLI regrades use the cache only. See Satellite Tracks.

Work in Sequence

Sequence, Images and the Calibration page share one compact toolbar: filter pills, the thumbnail size slider and the tools, with display settings under View and rarely used tools under ⋯. In Sequence it includes Cutoff, Scoring and Select, and once frames are selected, the row below it offers Review rejection.

Images and Sequence mark where frames cross into another night or hour, with the night's date before its first frame. Nights split at each rig's local noon, not at midnight. Marks in the View panel, or Night and hour marks in Settings › Review, shows nights and hours, nights only, or no marks. Library & Grader covers the toolbar and the marks.

Each filter's All sessions tab starts its row, with a bold label, bar, tint and date-range icon in the filter's color. Click anywhere on a toolbar pill with a list, including its label or chevron, to open the list.

The summary and score chart stay below the toolbar as you scroll through frames. An open suspect list overlays the chart and scrolls independently, so opening or closing it does not move the page. PSF Guard keeps the current frame visible below the toolbar and open list. On short windows, such as a phone in landscape, the summary and chart scroll with the page to leave room for frames.

Find a frame from its solved position

Solved pointing plots solved frame centers around the target and marks the current frame with a ring. Click a point, or focus it and press Enter, to move to that frame without changing your selection. Arrow-key navigation continues from that frame. Click the chart heading to collapse or expand it. The collapsed heading shows counts for solved frames and pointing issues. PSF Guard remembers the collapsed state in the current browser.

Find frames with a specific issue

Click a suspect pill in the Sequence summary—cloud events, focus drift, tracking issues, off target or unsolved—to list its frames in strip order, with their times and scores. Click a frame to move to it in the strip without changing your selection. Click the pill again or press Escape to close the list.

Golf of Mexico G all-sessions chart with seven likely-cloud frames, the 02:09 AM frame highlighted, and zero selected.
Open an issue to find its frames without changing your selection. The highlighted frame scores 65 across the 612 G frames.

Score chart

The chart draws one bar per frame, in capture order from left to right, even when View › Sort › Newest first turns the strip around. A dot under each bar gives the frame's grade: green for accepted, red for rejected, faint grey for pending. A bar's tooltip starts with the grade and the reject reason. The dots change as you grade, undo and redo.

Cutoff

Cutoff measures Score, Stars or HFR. The chart's bars, its dashed line, the slider, the marked cards and the cutoff rule under Select follow the measure chosen. The score cutoff reads 0 to 100, as the chips do. A lower score and fewer stars fall below the cutoff; a larger HFR falls above it.

The Stars and HFR sliders use the values shown on the current session's cards. Each starts at the point where its part of the score reaches zero. With Star loss at 100%, that means 40% fewer stars than the session's 90th percentile. With HFR rise at 100%, it means HFR 30% above the session's 10th percentile.

PSF Guard stores the cutoff as a fraction of that session reference, so switching sessions or filters keeps the same relative threshold. The URL stores the selected measure as cutoffBy and remembers each cutoff separately: cutoff, starCutoff or hfrCutoff. Switching back restores the cutoff you last used for that measure.

Golf of Mexico H-alpha session with an HFR cutoff of 1.84 and three Soft Stars frames above the line.
The first three frames have HFR values of 6.62, 6.28 and 5.99, above the 1.84 cutoff. The red dots show their stored Rejected grades; changing the cutoff does not grade frames.

Select frames by rule

Use Select to select frames by a rule. Each option describes its criteria and shows the number of matching frames in the current view.

RuleSelects
Below the cutoffFrames past the cutoff. With Cutoff on Stars or HFR it reads Fewer stars than the cutoff or HFR above the cutoff.
Clouds or obstructionFrames in which a detector found clouds or an obstruction.
Off targetFrames off target, or with a pointing jump, drift or rotation skew.
Failed plate solveFrames that failed to solve and show image-quality evidence.
Recommended rejectsFrames the analysis recommends rejecting.
Poor calibrationLights with Poor calibration findings. Until the calibration check catches up with recent changes, it reads Poor calibration (updating) and cannot be chosen. See Calibration Libraries.

The rule stays active as you adjust the cutoff, change its measure, rescore or switch sessions. PSF Guard updates the selection automatically while preserving frames you selected or deselected manually. The row below the toolbar counts those manual changes. The URL stores the rule as selectRule. Click × beside the control to disable the rule and keep the selection, or Clear to disable the rule and clear the selection.

Review rejection lists each selected frame with its evidence. Nothing is written until you confirm. See Astrometry Quality.

After you confirm a rejection, the rule stays active with nothing selected. Rules exclude already rejected frames, so their counts show what remains to reject. Undo restores those frames to the counts, but does not select them again.

After rejection, Below the cutoff stays active with no matching frames selected. This example uses a disposable catalog with staged metadata.
After rejection, Below the cutoff stays active with no matching frames selected. This example uses a disposable catalog with staged metadata.
Recommended rejects stays active even when no frames match. These session frames already have Rejected grades.
Recommended rejects stays active even when no frames match. These session frames already have Rejected grades.

Why star count and HFR are not enough

Star count and HFR barely move when part of a frame is ruined. On a real session where a tree line slowly covered the field:

The scan answers with signals that are local (per grid cell), photometric (flux ratios, not counts) and temporal (each cell against its own history), with baselines that do not absorb a slow-growing fault.

Detection signals

SignalCatchesHow
Dead cellsOcclusion (trees, dome, dew shield) Share of the 8×6 grid cells whose star density collapsed against the frame's median cell.
TransparencyThin uniform veils Median flux ratio of stars matched against a reference catalog for the sequence. 0.7 means the whole frame is about 0.4 mag dimmer.
Localized extinctionSmall clouds Flux ratio per cell divided by global transparency. A passing cloud shows as a dip in one patch of stars.
Star-share dropsSmall opaque clouds Each cell's share of the frame's stars against that cell's own median over time, allowing for Poisson noise.
Background riseStray light (headlights, flashlights) Background per cell against the cell's own history, after removing the frame's gradient with a robust plane fit.
Background fallDark occluders, cloud shadow The same, downward: something blocking skyglow reads darker, not milky.
Static glowCorner haze, lit occluder edges Cells brighter than the frame's own gradient model. Catches faults present from a session's first frame. A fresh solve excuses cells covered by large cataloged emission nebulae.
SNRHaze, dew, a brighter sky Flux promised by the frame's Gaia zero point divided by its sky noise. See SNR.
Fresh plate solutionOff-target frames, pointing jumps and drift, rotator slips, failed solves Seiza solves the current pixels. Solved centers and rotations are compared with the target, stable framing clusters, and drift within a segment. See Astrometry Quality.
Satellite prediction and pixel alignmentBright satellite trails Cached orbital elements are projected through the solved field for the exposure, then the nearby pixels are searched for a matching trail. See Satellite Tracks.

Scores and causes

Each frame gets two scores from 0 to 1:

Both are relative ranks, not verdicts. Star count, HFR, eccentricity, SNR and background are compared with a robust good reference, and normal variation costs nothing. A scan adds spatial, photometric and plate-solve evidence. Missing evidence gets no weight: the score renormalizes over what was measured, so a frame is never marked down because an optional scan has not run. When a fresh solve puts a large emission nebula in the field, raw background gets no weight, since lower background can mean lost target signal.

Cards say Catalog-relative score until a scan adds pixel evidence, then Pixel-assisted score.

A low score alone gives no cause and recommends nothing. A frame gets a cause only when its detector has enough evidence, and reject recommendations follow causes, not scores:

KindCauses
Sky and opticsLikely Clouds, Possible Obstruction, Sky Brightening, Focus Drift, Soft Stars
Mount and rotatorTracking Error, Wind Shake, Off Target, Stable Offset, Pointing Jump, Pointing Drift, Rotation Skew, Plate Solve Failed
EventsSatellite Trail Detected
Absolute checksNo Stars Detected, HFR Above Limit, Star Count Below Limit, Sensor Temperature
OtherUnknown Degradation

One absolute rule: a frame measured with zero stars is capped at a failing score with a No Stars Detected cause, even with no other frames to compare. Zero stars in a light frame is direct evidence of clouds, trailing or a blocked aperture. A frame with no star measurement at all is never capped. When the scan finds no stars where the capture software counted 20 or more, the scan failed: its star count, HFR and dead cells are dropped for that frame, and the score renormalizes around them. The same holds the other way round.

Sessions split at a Target Scheduler session change, a capture-profile change, or a 60-minute gap. Frames measured from calibrated pixels (a light catalogued from its calibrated copy, or measured from one) are scored only against each other, in sessions and stack comparisons of their own. Their background, flux and star counts differ from raw frames of the same sky, so they are no longer marked down beside them.

Several rigs in one catalog

Where one target and filter hold frames from two or more N.I.N.A. profiles, scoring compares each profile with itself: each forms sessions and stack comparisons of its own, so two rigs merged into one catalog are not scored against each other. The profile stands for the rig because catalog rows do not record the camera or telescope, so one rig kept under two profiles scores as two. A catalog with one profile scores as before, including older rows that name no profile. The statistical grader behind psf-guard regrade groups frames the same way; see CLI Reference.

SNR from the Gaia zero point

Capture software rarely records an SNR, so the quality scan measures one. It finds the frame's photometric zero point, the catalog magnitude of a star that gives one ADU per second, and divides the flux that zero point promises by the pixel-to-pixel sky noise.

  1. Measure up to 80 of the brightest unsaturated stars in a wide aperture: five times the frame's HFR, with a sky annulus from six to eight. Saturation is judged on the raw pixels, since a deep frame clips hundreds of its brightest stars.
  2. After the plate solve, place Gaia stars with the frame's own solution and match them to the measured stars.
  3. Take the median of magnitude + 2.5·log10(flux per second) as the zero point.

Cloud, haze and dew lower the zero point, and a brighter sky raises the noise, so SNR falls with either. A frame dimmed by haze or shot under a brighter sky scores lower than frames of the same exposure from any night. Soft focus does not move SNR: the wide aperture holds a star's light whatever its size, and HFR already scores focus. The zero point needs no reference frame, so nights and both sides of a meridian flip compare directly; scoring still compares it only between frames of the same exposure and settings.

SNR needs a fresh plate solve and a Gaia star catalog. A Tycho-2 catalog mixes two bands and is not used. An SNR already in the image metadata is used as recorded.

Frames scanned by an earlier version have no SNR. Run Rescan All Quality under Settings → Databases, or send force: true to the quality-scan API, to measure it.

Soft stars

HFR is judged against the whole target, not the night. PSF Guard compares a frame's HFR with the best of its target and filter across every night: the 10th percentile, once a capture profile has ten measured frames. Against its own night, a whole night of poor seeing or lost focus looks normal, and as one part of eight in the score, an HFR twice the best still left a frame near 0.8.

HFR against the target's bestEffect
Up to 1.5×None
Over 1.5×Score capped, with a Soft Stars cause. The cap falls from 1.0 at 1.5× to the reject level (0.25) at 2×.
From 1.75×[Auto] reject recommendation; stacks leave the frame out.
2× and beyondCapped at the reject level.
[Auto] Soft stars - HFR 4.10 px, 1.8× the target's best 2.28 px

On one rig's catalog, 96.7% of frames sat within 1.3× of their best, and 1.5% beyond 1.5×.

The first three frames have fewer stars and much higher HFR than the next two.
The first three frames have fewer stars and much higher HFR than the next two.

One star count per target

The quality scan and the capture software count stars on different scales. HocusFocus and N.I.N.A.'s own detector differ several-fold, and a rig's settings can change between nights. Mixing the two dragged down whole nights on rigs where they differ, so a target's frames are compared on one source per filter:

Max HFR, Min stars and the zero-star cap still judge each frame on its own measurement: PSF Guard uses scan measurements when available, or measurements from the capture software otherwise.

Guards against false zero-star records

Penalties and reject limits

The Scoring control in the Sequence toolbar sets how hard evidence hits the score, and optional fixed reject limits like N.I.N.A.'s subframe selection.

SettingBuilt inEffect
Satellite trails100%Score hit for a pixel-confirmed trail. At 0%, trails neither lower the score nor drive reject recommendations, but a confirmed trail still shows as a warning. Useful when stacking removes trails.
Pointing100%Score hit for off-target, pointing-jump, pointing-drift and corroborated solve-failure evidence. At 0% it also stops driving reject recommendations.
Temporal anomalies100%Score hit when a frame suddenly departs from its neighbours, such as a sudden drop in stars or jump in HFR.
HFR rise100%How hard a frame is marked down for an HFR above the sequence's sharpest frames (its 10th percentile). At 100% the hit starts 5% over, and the HFR term reaches zero at 30% over.
Star loss100%How hard a frame is marked down for fewer stars than the sequence's best frames (its 90th percentile). At 100% the hit starts 10% under, and the star term reaches zero at 40% under.
Max HFROffReject any frame whose measured HFR (pixels) is over the limit. Above 0 and up to 100.
Min starsOffReject any frame with fewer detected stars than the limit. A whole number from 1 to 1,000,000.

Penalties run from 0% (ignore the evidence) to 200% (double the hit), in steps of 10%. For HFR rise and Star loss the penalty divides both ends of the band: at 200% a frame loses score from 2.5% more HFR and the term reaches zero at 15%, at 50% the band doubles, and at 0% standing behind the good frames costs nothing. These keep the score graded and relative to the sequence.

Max HFR and Min stars reject only past a fixed line. A frame past a limit is capped and gets an [Auto] reject recommendation, whatever the rest of the sequence looks like. A frame missing the measurement is exempt. An empty limit is off. A value outside the ranges above is refused and shown, never quietly changed.

One limit is always on: Sensor Temperature. A frame whose sensor ran more than 10 °C warmer than the median of its session, or more than 20 °C above the cooler's set point, is capped and recommended for rejection. Dark current and hot pixels climb steeply with temperature, and no dark shot at the set point removes them. Colder never flags, and a frame with no temperature reading is exempt.

The zero-star cap does not scale. The CLI takes --ignore-satellites, --max-hfr and --min-stars; API callers pass penalty_satellite, penalty_pointing, penalty_temporal, penalty_hfr_rise, penalty_star_loss, hfr_reject_above, star_count_reject_below or sensor_temp_tolerance_c.

Scoring popover with HFR rise at 150 percent and Star loss at 50 percent, marked Changed for this view.
HFR rise and Star loss have changed for this view. Save as default would apply them to future views; Reset to default restores the saved settings.

Defaults and the current view

Every view starts from your scoring defaults, set in Settings › Review › Sequence scoring. Each field shows its built-in value. Save defaults stores your changes, and Reset to built-in defaults brings back the calibrated scoring: every penalty at 100% and no limits.

Adjust Sequence scoring defaults and optional HFR and star-count limits.
Adjust Sequence scoring defaults and optional HFR and star-count limits.

A change in the toolbar applies to that view only. The control then reads Scoring (changed), and its popover offers Save as default, which makes the view's values your defaults, and Reset to default, which returns the view to them. For an editor, Edit defaults in the popover opens Settings.

Once a value differs from your defaults, the URL stores all scoring values: penaltySatellite, penaltyPointing, penaltyTemporal, penaltyHfrRise, penaltyStarLoss (1 is 100%), maxHfr and minStars, with off for a limit turned off. A link therefore scores the same for whoever opens it. A reload, the project's other targets, Images, the image detail and Stacks keep the view's scoring, so a frame scores the same everywhere in the project. Those views show Scoring (changed) with Reset, and Stacks shows the values used for the build beside Build. Another project or database starts from your defaults.

Signed in to a server with user accounts, your defaults follow you to any browser, like your other view choices; otherwise the browser keeps them. The values an earlier version's Scoring control remembered become your defaults. See Server Accounts.

Read the annotated diagnostics

--annotate renders each flagged frame with the analysis grid on top. Cells are marked by the signal that fired, and the caption strip gives the verdict, score, frame metrics and the classifier's explanation.

MarkingMeaning
Red fillDead cell: star density collapsed (occlusion).
Orange fillLocalized extinction: stars dimmed by a small cloud, labelled with the cell's flux ratio.
Magenta fillSudden drop in the cell's share of stars.
Yellow borderBackground rise against the cell's history (stray light).
Blue borderBackground fall against the cell's history (dark occluder, cloud shadow).
Cyan fillStatic glow above the frame's own gradient model.

Occlusion arriving

Occlusion onset: red cells trace the tree line
A quarter of the cells have lost their stars, and the red region traces the out-of-focus tree line. Transparency is 1.01: the rest of the field is photometrically normal, which is why global metrics miss frames like this.

Heavy occlusion with a lit edge

Heavy occlusion with a yellow-bordered stray-lit cell
Half the field is dead. A yellow border marks a cell whose background rose above its own history, where the occluder's lit edge reaches a live cell.

The occluder's edge

Blue cells darker than history, yellow lit fringe
Later in the same session, blue borders mark cells darker than their history, where the occluder blocks skyglow. Yellow marks its lit fringe.

Thin cloud veil

Clean frame: 2973 stars, transparency 1.05
Clean frame: 2,973 stars, transparency 1.05.
Veiled frame: 1417 stars, transparency 0.63, REJECT
The same field 13 minutes later: 1,417 stars, transparency 0.63, about 0.5 mag of uniform extinction. REJECT.

No cell is marked, because nothing is wrong locally. Only the matched-star flux ratios see the veil. Conventional grading accepted this frame.

Static corner glow

Cyan cells sitting on corner haze at 4.7% above the gradient plane
Haze present from the session's first frame, so every temporal detector misses it. Static glow compares each cell with the frame's gradient model instead: the cyan cells sit on the haze, 4.7% above the plane.

Real nebulae can make the same stable shape. When a fresh solve projects a large emission nebula across a bright cell, PSF Guard treats that cell as explained and keeps any bright cells outside it. Only solved geometry does this; a target name or FITS header does not silence the detector.

Tune the detectors

Defaults were calibrated against measured clean-frame envelopes: 42 frames and more, four nights, several filters.

KnobDefaultNotes
--min-score0.35Composite score below which a frame is rejected.
--dead-cell-rise0.08Occlusion sensitivity. Clean-frame jitter is 0.04 or less, so 0.08 leaves a 2× margin.
--session-gap60 minGap that splits a sequence into sessions.
--max-hfrOffReject any frame whose HFR (pixels) is over this.
--min-starsOffReject any frame with fewer detected stars than this.
--ignore-satellitesOffIgnore satellite-trail evidence in scores and rejections. Trails still show as warnings.
Glow threshold2.5% of sky and >30 ADUThe ADU floor ignores weak structure; fresh solved geometry handles bright, large nebulae. True haze measured 48–103 ADU. Rig-specific: tune glow_min_adu for your camera and exposures.
Transparency threshold0.80Global veil rejection level.

Safety rules

Limitations

Full technical notes: docs/SCREENING.md.

More projects from theatr.us