Skip to main content

Astrophotography toolkit: object name resolution, FITS subframe quality analysis.

Project description

astro-resolver

Astrophotography toolkit for FITS workflows and imaging pipelines. Two independent packages, one library:

Package Purpose
astro_resolver Turns messy OBJECT headers into clean folder names
astro_quality Analyses FITS subframes for stacking quality

Installation

pip install astro-resolver

# With star detection / FWHM support (recommended):
pip install "astro-resolver[quality]"

astro_resolver — Object name resolution

Resolves FITS OBJECT header values like "M 81", "sh2-101" or "barnard 33" into filesystem-safe folder names such as "M81_BodesGalaxy" or "B33_HorseheadNebula".

Features

  • Local-first — SIMBAD only as a last resort
  • Solar System, Caldwell, custom aliases, OpenNGC (~14k objects), Sharpless and Barnard catalogs bundled offline
  • Stellar catalog IDs (HD, HIP, SAO, TYC, …) skip the SIMBAD name round-trip and go straight to coordinate lookup
  • Coordinate fallback via SIMBAD when name lookup fails
  • Output is always filesystem-safe (no spaces, special chars)

Resolution priority

  1. Solar System (local)
  2. Caldwell (local)
  3. Custom aliases (local)
  4. OpenNGC offline (~14k NGC/IC objects)
  5. Sharpless catalog (Sh 2-xxx HII regions)
  6. Barnard catalog (dark nebulae)
  7. SIMBAD by name (online)
  8. SIMBAD by coordinates (online)
  9. Sanitized header string as fallback

Usage

from astro_resolver import resolve_object_name

resolve_object_name("M 81")           # → "M81_BodesGalaxy"
resolve_object_name("sh2-101")        # → "Sh2-101_TulipNebula"
resolve_object_name("barnard 33")     # → "B33_HorseheadNebula"

# Stellar catalog ID with coordinates → SIMBAD coord lookup
resolve_object_name("HD 1", ra="00 05 09", dec="+67 50 24")

The resolver accepts an optional log callable so it can be plugged into Siril scripts (log=siril.log) or any other host environment.


astro_quality — Subframe quality analysis

Analyses FITS light frames for stacking quality. Supports any camera (DSLR, ZWO ASI, QHY, DWARF, …) — Bayer RAW and mono alike. Calibration frames (Flats, Darks, Bias) are detected and skipped automatically via filename patterns and the IMAGETYP FITS header.

Metrics per subframe

Metric Description Direction
background_noise Sky background σ (ADU, sigma-clipped) lower = better
snr_proxy Signal/noise ratio proxy higher = better
gradient Spatial background variation (light pollution gradient) lower = better
saturation_pct Fraction of saturated pixels (%) lower = better
star_count Number of detected stars (transparency proxy) higher = better
fwhm_median Median star width in luminance pixels (focus/seeing) lower = better
eccentricity Median star roundness 0=round 1=line (tracking quality) lower = better

Star count, FWHM and eccentricity require photutils (pip install "astrolib[quality]").

Scoring

Each subframe receives a relative quality score 0–100 within its session. Scores are relative: a score of 90 in a poor night may be worse in absolute terms than 70 in an excellent night. Use raw metric values for cross-session comparison.

Grade Score Meaning
A 85–100 Excellent
B 70–84 Good
C 50–69 Average
D 30–49 Poor
F 0–29 Reject

Usage

Analyse a single frame:

from pathlib import Path
from astro_quality import analyze_fits, score_sub, grade, compute_session_stats

result = analyze_fits(Path("IC443_0042.fits"))
if not result["error"]:
    m = result["metrics"]
    print(f"Noise: {m['background_noise']:.1f} ADU")
    print(f"SNR:   {m['snr_proxy']:.1f}")
    print(f"Stars: {m['star_count']}")   # -1 if photutils not installed

Score a session (relative quality):

from astro_quality import analyze_fits, compute_session_stats, score_sub, grade

results = [analyze_fits(f) for f in session_fits_files]
stats   = compute_session_stats(results)

for r in results:
    s = score_sub(r["metrics"], stats)
    print(f"{grade(s)} ({s:.1f})  {r['filename']}")

Scan an archive and build a quality report:

from pathlib import Path
from astro_quality import build_report_data
from astro_quality.archive import iter_sessions, iter_fits
from astro_quality.cache import load_cache, save_cache

ARCHIVE = Path("z:/AstroArchiv/Objects")
CACHE   = Path("quality_cache.json")

cache = load_cache(CACHE)

for obj, sess, sess_path in iter_sessions(ARCHIVE):
    for f in iter_fits(sess_path):          # skips Flats/Darks automatically
        if str(f) not in cache:
            result = analyze_fits(f)
            result["object"]  = obj
            result["session"] = sess
            cache[str(f)] = result

save_cache(cache, CACHE)

report = build_report_data(cache, obj_filter="IC443")
for sess, data in report["IC443_GemA"].items():
    print(f"{sess}: {data['score_mean']:.1f} ({data['grade']})  "
          f"noise={data['stats']['noise_med']:.1f}")

Calibration frame detection:

from astro_quality.archive import is_calib_frame
from pathlib import Path

is_calib_frame(Path("Flat_30s_ISO800_0001.fit"))   # True
is_calib_frame(Path("Light_M51_120s_0001.fit"))    # False

Archive layout expected by iter_sessions / iter_fits

<root>/
├── IC443_GemA/
│   ├── 2026-01-19_DWARF_3/
│   │   ├── IC 443_60s60_..._0001.fits   ← light frames
│   │   └── Flat_200ms_..._0001.fits     ← skipped automatically
│   └── 2026-04-01_DWARF_3/
│       └── ...
└── M51_WhirlpoolGalaxy/
    ├── 2026-04-25_ZWO_ASI585MC_Pro/
    │   └── Light_M51_120s_..._0001.fit
    └── presets/                          ← skipped (non-session dir)

Non-session subdirectories (presets, flats, calibration, masters, …) are skipped automatically.


Data sources

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

astro_resolver-0.4.0.tar.gz (911.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

astro_resolver-0.4.0-py3-none-any.whl (922.5 kB view details)

Uploaded Python 3

File details

Details for the file astro_resolver-0.4.0.tar.gz.

File metadata

  • Download URL: astro_resolver-0.4.0.tar.gz
  • Upload date:
  • Size: 911.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for astro_resolver-0.4.0.tar.gz
Algorithm Hash digest
SHA256 be3f825f0b256513eed258739306294abbf39c02241ac0351bd2fae8333dd15b
MD5 bdfa747b8eceac3843b0914ac753dc1f
BLAKE2b-256 6549f0c6ada308e99c295d80b50a02f522179991c535a8f4f9fce7df8829d819

See more details on using hashes here.

File details

Details for the file astro_resolver-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: astro_resolver-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 922.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for astro_resolver-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a5eab6b962925f9404f8076839dd3626478eb04e10b902891d44ac47f5604913
MD5 89deb38128f33573e2d97eee5fe15587
BLAKE2b-256 5fca5e0ba7e70256d5ef663f99b1caf5f60f7125dbf5a429b397ae7ff5b60130

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page