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.1.tar.gz (911.1 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.1-py3-none-any.whl (922.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: astro_resolver-0.4.1.tar.gz
  • Upload date:
  • Size: 911.1 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.1.tar.gz
Algorithm Hash digest
SHA256 0da6a4be9a8a5f5393e2d370fb41ec3de6b0283d785f23e74e95e2e86b8eebeb
MD5 1e550c0fa6d231049a5e9451e2ccba85
BLAKE2b-256 5686f5aae6e708a118c9383c0df86c6149d3645217891e6235e1d4afd30e28db

See more details on using hashes here.

File details

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

File metadata

  • Download URL: astro_resolver-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 922.7 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 13e2b29cfa4529d75a608824ac59d22c4c207f0d59d65b068bb77ac68923a920
MD5 b7eec7d4ab79f7c29c43effb07af5c4c
BLAKE2b-256 23467eb8c601c86670089c443ae9baa1a06406429243a59710a767815a50f750

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