// tools · astro toolkit

Astro Toolkit — plan, review & arrange

A single-binary Qt6 desktop app that follows one imaging project end to end: a deep-sky target planner that scores what's worth shooting tonight from your location and gear, a FITS reviewer with a scored auto-quality check to cull bad subs, and a frame arranger that sorts a messy capture folder into a stacker-ready tree. Free and open source — built for my own KStars/Ekos rig.

Source & full docs: github.com/nirmaljangid/astrotools

The Astro Toolkit Plan tab: ranked deep-sky targets on the left, an altitude sky chart on the right
The Plan tab — tonight's targets, ranked and scored, beside the altitude sky-chart panel.

The idea: Plan → Review → Arrange

The app mirrors the real life-cycle of one project, left to right across the top tabs. You don't have to use all three — many nights you'll live in Review only — but the tabs follow the way a project actually flows.

Plan

What should I shoot tonight, and how? Pick a target, see its sky path, frame it to your sensor, get an AI imaging plan.

Review

Which of last night's subs are keepers? Flip through frames in four stretch modes; Auto Review scores and culls the junk.

Arrange

Sort this pile of FITS into a stacker-ready tree — lights grouped by target and filter, calibration frames auto-matched.

Build & launch

All dependencies are standard distro packages. On Ubuntu / Debian:

bash
sudo apt-get install qt6-base-dev libcurl4-openssl-dev libcfitsio-dev \
    nlohmann-json3-dev cmake pkg-config libgps-dev

Then build the single-binary app — one translation unit, so it compiles in ~10–15 s:

bash
git clone https://github.com/nirmaljangid/astrotools.git
cd astrotools
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)

Seed the object catalogue (the planner needs it), then run:

bash
mkdir -p ~/.astro_gui
cp data/catalog.sqlite ~/.astro_gui/catalog.sqlite   # bundled OpenNGC catalogue (~14k objects)
./build/astro_toolkit

On first launch the app writes ~/.astro_gui/config.json with defaults and detects your location (gpsd → IP geolocation). Arch, Fedora and Windows builds are covered in the README.

First, tell it about your gear

The most useful thing to do before planning is to create a gear profile. It drives the FOV indicator, the framing overlay, and the AI imaging-plan prompt. Open ⚙ Profiles in the toolbar and fill in your scope and camera:

The Equipment Profiles dialog with telescope, camera and filter fields
⚙ Profiles — saved profiles on the left; telescope, camera and filter fields on the right, with built-in presets via Load Preset.
FieldExample (a typical astrograph)
Scope type / focal length / apertureNewtonian · 1000 mm · 200 mm (f/5)
Camera / pixel sizeToupTek ATR533MM · 3.76 µm
Sensor width × height3008 × 3008 px
Filterstick LRGB / Hα / OIII / SII as owned

The FOV the app derives from those numbers is what the planner uses to filter out targets too big or too small for your rig — and to draw the framing rectangle later.

Plan — find tonight's target

Set Night of: (defaults to tonight), then Refresh Targets. For every candidate the planner computes an altitude-vs-time path across the dark window and keeps only objects that clear your minimum altitude for at least your minimum hours. The survivors are scored and ranked so the best things to shoot float to the top — rewarding high altitude, long time up, brightness, apparent size, and Messier / famous-object status, while penalising tiny obscure objects.

Inspect a target — three views

Click any object, then switch the right panel with the buttons at the bottom:

Sky Chart showing the selected object's altitude arc across the night
Sky Chart — NGC 6888 selected; its altitude arc is drawn across tonight's dark window, with the FOV-fit badge bottom-right.
Details panel: type, constellation, max altitude, visible window, size and FOV fill
Details — full readout: type, constellation, max altitude and time, visible window, size and FOV fill. The AI imaging plan slots in here when an OpenAI key is set.
Framing view: a DSS sky-survey image with the sensor footprint drawn to scale
Framing — the real DSS survey image of the field with your sensor rectangle drawn to scale: an instant "does it fit, or is it a mosaic?" check.

The Search sub-tab takes a catalogue ID or partial name (M42, NGC7000, IC1805). An OpenAI key in config.json unlocks the per-target imaging plan; without one, the rest of the app is unaffected.

Review — cull last night's subs

The Review tab is a FITS browser plus quality-control workbench. Browse… to a folder (scanned recursively) and the left list fills with every .fit/.fits/.fts. Click a file or use ◀ Prev / Next ▶ to load it.

The Review tab with a real FITS light frame loaded and the file list on the left
Review — a real Hα+OIII sub loaded (asinh stretch), with the file list, a header overlay, and a histogram strip along the bottom.

The Stretch combo cycles four display stretches; keyboard shortcuts work once the image canvas has focus (click it first):

KeyAction
l nNext file
h pPrevious file
sCycle stretch mode (linear → sqrt → log → asinh)
x DelDelete current file (with confirmation)

Auto Review — it finds the bad frames for you

⚡ Auto Review… scores every loaded light frame in a background thread. Calibration frames (IMAGETYP = bias/dark/flat) are skipped. On each light it detects stars (background + 5σ threshold, connected-blob labelling) and classifies every blob: a small round blob is a star, a long thin one (aspect ≥ 4.5) is a trail, a big round one (> 50 px) is out of focus.

Auto Review results dialog listing flagged frames with scores and reasons
Auto Review on a mixed set — flagged subs listed worst-first with score and reason ("star trails (moderate), slightly out of focus"). Red rows are pre-checked for deletion; you confirm with Delete Checked.

Each frame starts at 100 and loses points:

IssuePenalty
Star trails−20 each, capped at −65 (so 1–2 trails are survivable)
Slight defocus (blob 50–100 px)−20
Severe defocus (blob > 100 px)−45
Low star count (< 15, focus fine)−2 per missing star

Results are bucketed, worst-first:

ScoreMeaningIn the dialog
≥ 70Goodnot listed
50–69Tolerablegold, unchecked
< 50Delete suggestedred, pre-checked

You stay in control: uncheck anything you want to keep, then Delete Checked removes only the ticked files. A single minor trail or slight defocus typically lands at ~80, so it won't even appear — the tool is deliberately conservative about suggesting deletions.

Arrange — build a stacker-ready tree

Point Arrange at one messy capture folder (and, optionally, your bias/darks/flats folders) and it produces a clean tree you can hand straight to a stacker. Tick Dry run first to preview exactly what would be created — no bytes copied — then untick and run for real.

The Arrange tab with input folder, calibration folders and the Dry run / Split-by-exposure toggles
Arrange — input (messy) folder, optional bias/darks/flats folders, and the Dry-run / Split-by-exposure toggles above "Arrange FITS for Stacking".

Each light is read for its OBJECT and FILTER headers and copied (never moved) into:

text
arrange_<sourcefolder>/
  <Target>/
    <Filter>/
      [<exposure>s/]        # only if "split by exposure" is on
        lights/   ← your light subs
        darks/    ← matched dark frames (if provided)
        flats/    ← matched flat frames (if provided)
        bias/     ← matched bias frames (if provided)

Calibration frames are matched to each light group, not blindly copied: gain within 15%, exposure within 10% (for darks), and sensor dimensions must match exactly. Then open arrange_…/<Target>/<Filter>/ in Siril (or DSS / PixInsight) and stack. Arrange does the tedious sorting; it doesn't stack — that's intentional.

A complete worked example

  1. Plan ▸ confirm your gear profile is active → Refresh Targets → open Nebula (Ha/SHO); the top result is, say, the North America Nebula.
  2. Sky Chart confirms it's high for 5+ h; Framing shows it overflows the sensor → plan a 2-panel mosaic; Details gives the AI plan (300 s Hα subs, gain 100, dither every frame).
  3. Next morning: Review ▸ browse to the light folder, stretch asinh, delete the two satellite-streaked subs, then ⚡ Auto Review → keep the gold ones, Delete Checked.
  4. Arrange ▸ lights + your calibration library → Dry run to preview → Arrange → open the output in Siril and stack.

Configuration & a security note

Everything lives in ~/.astro_gui/: config.json (location thresholds, gear profiles, OpenAI key/model, catalogue path) and catalog.sqlite (the OpenNGC database). Useful keys — min_alt_deg, min_hours_above, page_size, openai_model — are documented in the README.

⚠️ The OpenAI key is stored in plaintext in config.json. Fine for a local single-user box, but never commit or share that file, and rotate the key immediately if it ever leaks. Leaving it empty only disables the AI-plan feature — nothing else.

New to the stack? Start with my Ubuntu setup guide, and once you're imaging for real, build a dark library.