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.2.tar.gz (911.2 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.2-py3-none-any.whl (922.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: astro_resolver-0.4.2.tar.gz
  • Upload date:
  • Size: 911.2 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.2.tar.gz
Algorithm Hash digest
SHA256 fc71350efc014956bb2fee21d9b03314e408b5ad61b20c6534b9d4bec44da39d
MD5 b24aecd8ddf8430352ee69a8e771549e
BLAKE2b-256 30c5bb056c348ccd2315c6f1be695b503d32592f93156722f1b0807a828dc910

See more details on using hashes here.

File details

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

File metadata

  • Download URL: astro_resolver-0.4.2-py3-none-any.whl
  • Upload date:
  • Size: 922.8 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.2-py3-none-any.whl
Algorithm Hash digest
SHA256 04d18ea1adce577f99d19950bac0e8874a4bbc85a002b11efaf5630cdbe8f250
MD5 57e16c3348fd01781ec592b0189cd5e1
BLAKE2b-256 fa504ee6f49be3a44e550ff5caad85a17c396693ad8ecbaef562263082ca3a68

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