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.5.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.5-py3-none-any.whl (922.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: astro_resolver-0.4.5.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.5.tar.gz
Algorithm Hash digest
SHA256 e6a05914126df8ddaea1bb016883cc69f542bb06bc8f4add2837c0fa6c00cb39
MD5 634d6d0e23f5b4408b3f6f55478c14ae
BLAKE2b-256 f6184dd7a90ccc98132fb6ceb0f4e6e9d02ee7dec53c3f16ac3546ba89acb22c

See more details on using hashes here.

File details

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

File metadata

  • Download URL: astro_resolver-0.4.5-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.5-py3-none-any.whl
Algorithm Hash digest
SHA256 d9a25a3978a44ec041f27158ddcff5976ba4cdf33f55c8f4af3a2f785c88e0fc
MD5 7e5f328c586940060d728f957f1ac516
BLAKE2b-256 fc714f8c6292ec7ee4b9242fa81ec377c0b5106a1bdedeeb34e0b3f2c21cd6b7

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