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
- Solar System (local)
- Caldwell (local)
- Custom aliases (local)
- OpenNGC offline (~14k NGC/IC objects)
- Sharpless catalog (Sh 2-xxx HII regions)
- Barnard catalog (dark nebulae)
- SIMBAD by name (online)
- SIMBAD by coordinates (online)
- 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
be3f825f0b256513eed258739306294abbf39c02241ac0351bd2fae8333dd15b
|
|
| MD5 |
bdfa747b8eceac3843b0914ac753dc1f
|
|
| BLAKE2b-256 |
6549f0c6ada308e99c295d80b50a02f522179991c535a8f4f9fce7df8829d819
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a5eab6b962925f9404f8076839dd3626478eb04e10b902891d44ac47f5604913
|
|
| MD5 |
89deb38128f33573e2d97eee5fe15587
|
|
| BLAKE2b-256 |
5fca5e0ba7e70256d5ef663f99b1caf5f60f7125dbf5a429b397ae7ff5b60130
|