Skip to main content

Astropornography tool โ€” one command from raw subs to a finished astrophoto

Project description

aPornTool

One command from raw sub-exposures to a finished, share-ready astrophoto.

PyPI Python

๐Ÿ“ฆ Install: pip install aporn-tool โ€” releases ยท changelog.

aPornTool takes a folder of raw astrophotography subs and drives them through the full linearโ†’nonlinear editing pipeline โ€” stacking, photometric colour calibration, gradient and noise removal, colour-preserving stretch, and star management โ€” leaving only the deliverables in your output folder and every scratch file tucked into a hidden working directory.

It's built for the ZWO Seestar workflow (internal calibration โ†’ no darks/flats/bias) but works with any OSC .fit subs, and runs natively on Windows, macOS (incl. Apple Silicon), and Linux.

Design goal โ€” processing parity: on the same data, aim to match what a skilled processor would get, so the only remaining variable is capture (aperture, integration hours, sky darkness). The tool can't invent detail that isn't in the data โ€” the final crop, curves, and watermark are yours to do from the 16-bit TIFF (Canva/Photoshop).


Contents


How it works

raw .fit subs โ”€โ”€โ–บ stage โ”€โ”€โ–บ SIRIL: calibrate โ”€โ–บ register โ”€โ–บ stack โ”€โ–บ [SPCC] โ”€โ–บ golden linear stack
                                                                                       โ”‚
   deliverables โ—„โ”€โ”€ finish โ—„โ”€โ”€ [StarNet] โ—„โ”€โ”€ [GraXpert BGE + denoise] โ—„โ”€โ”€ [auto-crop] โ—„โ”˜
   (.tif/.png/.jpg/.fits)
  • Each stage is checkpointed. The golden linear stack (_work/<target>/02_linear/) is the immutable re-processing anchor โ€” re-finishing never re-stacks.
  • The pipeline is parameterised per mode, not one-size-fits-all: registration, gradient tool, SPCC placement, and star handling differ (see the table below).
Mode Best for Registration Gradient Stars
dso-mosaic galaxies & multi-panel โ€” M31, M33, M51, M101, NGC7000 WCS plate-solve (framing=max) GraXpert BGE StarNet2, blend some back
dso-emission-nebula Hฮฑ HII / SNRs โ€” M8, M20, M42, M16, Veil star-based 2-pass SIRIL subsky keep all (rich field)
dso-reflection-nebula blue scattered light โ€” VdB106, M78 star-based 2-pass GraXpert BGE dual-layer screen blend
dso-star-cluster globulars & open clusters โ€” M13, M22, M45, M44 2-pass (+FWHM cull) SIRIL subsky keep all โ€” stars are the subject

Planetary (video โ†’ AutoStakkert โ†’ finish) is planned; it requires a manual GUI stacking step.


Prerequisites

Tool Role Get it
Python 3.10+ orchestrator python.org / your package manager
Siril 1.4+ (siril-cli) stack, register, plate-solve, SPCC, StarNet https://siril.org/download/
GraXpert 3.x background extraction + AI denoise (mosaic & reflection) https://github.com/Steffenhir/GraXpert/releases
StarNet2 star removal https://www.starnetastro.com/
ffmpeg / ffprobe planetary + final polish ffmpeg.org / package manager

Every DSO tool is natively cross-platform (incl. Apple Silicon). The tool locates each one on PATH, then in the standard install locations per OS, then from aporntool.config.json โ€” you never hard-code paths.

Where the tools usually live per OS
Windows macOS Linux
siril-cli C:\Program Files\Siril\bin\siril-cli.exe /Applications/Siril.app/Contents/MacOS/siril-cli /usr/bin/siril-cli
GraXpert %LOCALAPPDATA%\Programs\GraXpert\GraXpert.exe /Applications/GraXpert.app/Contents/MacOS/GraXpert package / AppImage
StarNet2 (set in SIRIL) /usr/local/bin/starnet2 /usr/local/bin/starnet2
GraXpert AI models %LOCALAPPDATA%\GraXpert\GraXpert\{bge,denoise}-ai-models\ ~/Library/Application Support/GraXpert/{bge,denoise}-ai-models/ ~/.local/share/GraXpert/โ€ฆ
SIRIL config %LOCALAPPDATA%\siril\ ~/Library/Application Support/org.siril.Siril/siril/ ~/.config/siril/

Installation

Already have Python 3.10+? Install from PyPI:

pip install aporn-tool

That gives you the aporn-tool command. python -m aporntool also works as a module fallback (the Python module keeps the one-word name โ€” module names can't contain hyphens), and an aporntool alias command is installed too, so either spelling runs.

Or install from source (for development / latest main)
git clone https://github.com/christiantroyandrada/aporn-tool.git
cd aporn-tool
python3 -m venv .venv
.venv/bin/python -m pip install -e .
# Windows: .venv\Scripts\python -m pip install -e .

Installing the Python package does not install Siril/GraXpert/StarNet โ€” those are separate apps (see Prerequisites). Run aporn-tool config --check to confirm they're found.


First-time setup

Run the discovery check โ€” it prints where each tool was found and writes a starter config:

aporn-tool config --check

Then complete the three one-time setup steps (the tool's preflight checks the ones it can):

  1. GraXpert AI models (mosaic & reflection) โ€” open GraXpert once and run Background Extraction and Denoise on any image so it downloads the model files. Preflight verifies they exist before stacking, so a missing model fails in seconds, not after a 30-minute stack.
  2. StarNet inside SIRIL (mosaic) โ€” SIRIL's built-in starnet command runs the executable set in SIRIL โ†’ Preferences โ†’ External Programs. Being on PATH is not enough for mosaic mode. (Reflection mode calls the StarNet CLI directly, so it only needs it discoverable.)
  3. Local Gaia catalogs in SIRIL (SPCC colour calibration) โ€” online VizieR is retired. Install the sky region matching your target: Milky Way for galactic nebulae/low-latitude clusters, Galaxy Season for high-latitude galaxies. The wrong region โ†’ SPCC reports "no stars".

Validate everything without processing:

aporn-tool dso-mosaic --in "/path/to/subs" --out /path/to/out --target M31 --preflight-only

Usage โ€” from simplest to advanced

1. The simplest run

Point it at a folder of subs and pick the mode โ€” that's all. The object name and coordinates are read from the subs' FITS header, and the results land in a folder named after the target, right beside your subs:

aporn-tool dso-mosaic --in "/path/to/M31 subs"

Produces M31_final.tif (16-bit โ€” the real deliverable), .png, .jpg (quick-look), and .fits next to the input; everything else lives under _work/.

Override either default when you want to: --target for a custom name, --out for a custom location.

โš ๏ธ The output path must not contain spaces (a SIRIL limitation). The default output inherits the subs' parent folder; if that path has spaces, pass a space-free --out. The --in path and sub filenames may contain spaces.

2. Other modes

aporn-tool dso-emission-nebula   --in "/data/M8"
aporn-tool dso-reflection-nebula --in "/data/M78"
aporn-tool dso-star-cluster      --in "/data/M13"

3. Combine multiple nights (more integration = the #1 quality lever)

--in is repeatable; all .fit from every source are staged and stacked together:

aporn-tool dso-mosaic \
  --in "/data/M31/2026-07-04" \
  --in "/data/M31/2026-07-05" \
  --out /data/out --target M31

4. A target not in the built-in catalog

Nothing special needed โ€” the coordinates come from your subs' FITS header, so unlisted targets (VdB 106, Sh2-155, โ€ฆ) just work. Pass --target only when you want a custom output name:

aporn-tool dso-reflection-nebula --in "/data/vdb106"
aporn-tool dso-emission-nebula   --in "/data/sh2-155" --target Sh2-155

5. Control the crop

Auto-crop (default) trims empty registration/mosaic borders. Override it:

# keep the full frame (no crop)
aporn-tool dso-mosaic --in "/data/M31" --out /data/out --target M31 --no-crop

# explicit SIRIL crop box: X Y W H (x from left, y from top)
aporn-tool dso-mosaic --in "/data/M31" --out /data/out --target M31 --crop "162 108 2310 4378"

6. Check status and resume

Re-running the same command auto-resumes at the first unfinished stage โ€” nothing done is repeated. Inspect the ledger any time:

aporn-tool status --out /data/out --target M31
dso-mosaic / M31  (fingerprint 8cd20ff7d100564d)
  calibrate  done
  register   done
  stack      done
  spcc       done
  bge        done
  denoise    done
  finish     failed
Resume at: finish

7. Re-run specific stages (cheap, from the golden anchor)

# redo colour calibration and everything after it (e.g. once the right Gaia region is installed)
aporn-tool dso-mosaic --in "/data/M31" --out /data/out --target M31 --redo spcc

# restart at a named stage
aporn-tool dso-mosaic --in "/data/M31" --out /data/out --target M31 --from finish

# ignore all checkpoints and re-run everything
aporn-tool dso-mosaic --in "/data/M31" --out /data/out --target M31 --force

8. The advanced, fully-specified run

aporn-tool dso-mosaic \
  --in "/data/M31/2026-07-04" --in "/data/M31/2026-07-05" \
  --out /data/out \
  --target M31 \
  --crop "162 108 2310 4378" \
  --star-reduce 0.35 \
  --config /data/my-aporntool.config.json \
  --redo spcc
  • --star-reduce 0.35 โ€” after StarNet removes stars (mosaic), blend 35% of them back (lower = fewer/dimmer stars; default 0.5).
  • --config โ€” use a specific config file (tool paths, catalogs, Seestar defaults).
  • --redo spcc โ€” recompute from the spcc stage onward, reusing the stack.

Command reference

aporn-tool <command> [options]
Command Purpose
dso-mosaic, dso-emission-nebula, dso-reflection-nebula, dso-star-cluster process a target
config --check [--config PATH] show tool discovery; write a starter config
status --out PATH --target NAME print the resume ledger
--version print the version

Options for the processing modes:

Option Description
--in PATH subs folder โ€” required, repeatable for multi-night
--out PATH output root โ€” optional; defaults to a <TARGET> folder beside the subs; must be space-free
--target NAME object name โ€” optional; auto-detected from the subs' FITS OBJECT header
--crop "X Y W H" explicit SIRIL crop box (default: auto-crop)
--no-crop disable auto-crop; keep the full frame
--star-reduce F mosaic star blend-back fraction (default 0.5)
--clean on success, delete working files except the golden anchor (reclaims disk)
--from STAGE restart at this stage
--redo STAGE re-run this stage + everything downstream
--force re-run all stages, ignore checkpoints
--preflight-only validate the environment, then stop
--config PATH config file (default aporntool.config.json)

Catalogued targets get canonical coordinates: M3 M4 M5 M6 M7 M8 M11 M13 M15 M16 M20 M22 M31 M33 M42 M44 M45 M51 M81 M92 M101 NGC869 NGC6960 NGC7000. Anything else uses the RA/DEC from your subs' FITS header automatically.


Stages & resume

Stage names are per-mode โ€” run aporn-tool status to see yours. Current orders:

Mode Stages (what --from / --redo accept)
dso-mosaic calibrate โ†’ register โ†’ stack โ†’ spcc โ†’ bge โ†’ denoise โ†’ finish
dso-reflection-nebula calibrate โ†’ register โ†’ stack โ†’ spcc โ†’ bge โ†’ denoise โ†’ finish
dso-emission-nebula calibrate โ†’ register โ†’ stack โ†’ mirrorx โ†’ finish
dso-star-cluster calibrate โ†’ register โ†’ stack โ†’ mirrorx โ†’ finish

A stage is only marked done after its output is verified (exists, non-empty, right type). A crash or a raising stage is marked failed and reported with the log tail โ€” re-run to resume. Changing a parameter re-runs that stage and everything downstream, nothing upstream.


Output layout

<OUT>/                       โ† DELIVERABLES ONLY
โ”œโ”€ M31_final.tif             โ† 16-bit, the real deliverable
โ”œโ”€ M31_final.png
โ”œโ”€ M31_final.jpg             โ† quick-look
โ”œโ”€ M31_final.fits
โ””โ”€ _work/                    โ† everything scratch, hidden here
   โ””โ”€ M31/
      โ”œโ”€ 00_lights/          hardlinked .fit subs
      โ”œโ”€ 01_process/         SIRIL sequences + frames
      โ”œโ”€ 02_linear/          M31_Linear.fit  โ† GOLDEN ANCHOR (never deleted)
      โ”œโ”€ 03_graxpert/        BGE / denoise intermediates
      โ”œโ”€ 05_finish/          finish scratch
      โ”œโ”€ logs/               generated .ssf + per-stage stdout
      โ””โ”€ aporntool.json      run manifest / resume state

Multiple targets can share one --out โ€” each gets its own _work/<target>/ and deliverables at the root.


Configuration file

aporn-tool config --check writes aporntool.config.json. Edit it to pin tool paths or set the local Gaia catalogs:

{
  "tool_paths": {
    "siril": "/Applications/Siril.app/Contents/MacOS/siril-cli",
    "graxpert": "/Applications/GraXpert.app/Contents/MacOS/GraXpert",
    "starnet2": "/usr/local/bin/starnet2",
    "ffmpeg": "/opt/homebrew/bin/ffmpeg"
  },
  "seestar_focal_mm": 150.0,
  "seestar_pixel_um": 2.9,
  "catalog_astro": null,
  "catalog_photo": null
}

Resolution order for each tool: explicit config path โ†’ PATH โ†’ known install locations.


FAQ

Do I need darks/flats/bias? No โ€” the Seestar calibrates internally. For other rigs, calibrate your subs beforehand (the tool ingests already-calibrated .fit).

How many subs do I need? More integration is the biggest quality lever. Combine nights with repeated --in. There's no hard minimum, but a handful of subs won't stack meaningfully.

Will it delete my raw data? No. Subs are hardlinked into _work/00_lights/; the golden linear stack and your originals are never overwritten.

Can I re-process without re-stacking? Yes โ€” that's the point of the golden anchor. Tweak a finishing parameter and re-run; only finish (or the changed stage onward) recomputes.

It didn't crop the mosaic tightly. Auto-crop trims the black/near-empty borders, but it thresholds on brightness rather than per-pixel coverage, so a noisy low-coverage band can survive on mosaics (those edge pixels are normalized to near the sky level). Pass an explicit --crop "X Y W H", or do the final crop by hand in Canva/Photoshop. Tighter mosaic cropping is on the roadmap.

Which mode for the Pleiades (M45)? It's an open cluster in blue reflection nebulosity โ€” use dso-reflection-nebula, not the plain cluster finish.

Does it need a GPU? No. GraXpert uses the GPU when available and falls back to CPU.


Troubleshooting

Symptom Fix
no StarNet executable set (mosaic) Set StarNet in SIRIL โ†’ Preferences โ†’ External Programs. PATH alone isn't enough for mosaic.
Preflight: GraXpert models missing (but installed) Open GraXpert, run BGE + Denoise once so it downloads the model files.
SPCC "no stars" / imprecise Install the Gaia region matching the target (Milky Way vs Galaxy Season).
--out path must not contain spaces Choose a space-free output folder (SIRIL limitation).
golden anchor not found on --from/--redo Run the full pipeline first (drop --from/--redo) so preprocess produces the anchor.
Plate-solving fails on a mosaic Ensure SIRIL's astrometry catalog is installed; the tool verifies solves by frame count, not exit code.
Noisy/ragged band left after auto-crop Known mosaic limitation (brightness-based crop misses low-coverage edges) โ€” pass --crop "X Y W H", or crop in post.

Every stage saves its SIRIL script and stdout under _work/<target>/logs/ โ€” check <stage>.log for the exact tool error.


Limitations

  • Deconvolution / wavelets are skipped for undersampled Seestar data (they amplify noise without adding real detail).
  • The last 5% โ€” final crop, curves, watermark โ€” is done by hand from the 16-bit TIFF.
  • Planetary needs a manual AutoStakkert stacking step (no usable CLI) and is not yet shipped.
  • Auto-crop trims black borders but can leave a noisy low-coverage band on mosaics (it crops by brightness, not coverage) โ€” tighten with --crop or in post; a coverage-aware crop is planned.

Development

.venv/bin/python -m pip install -e . pytest pytest-timeout
.venv/bin/python -m pytest -q          # unit suite; external tools are mocked

Tests mock Siril/GraXpert/StarNet, so they run anywhere. Integration runs need the real tools and real subs. See REQUIREMENTS.md for the full design, the per-mode pipeline contract, and the load-bearing SIRIL/GraXpert/StarNet gotchas.

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

aporn_tool-0.3.1.tar.gz (48.7 kB view details)

Uploaded Source

Built Distribution

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

aporn_tool-0.3.1-py3-none-any.whl (45.6 kB view details)

Uploaded Python 3

File details

Details for the file aporn_tool-0.3.1.tar.gz.

File metadata

  • Download URL: aporn_tool-0.3.1.tar.gz
  • Upload date:
  • Size: 48.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for aporn_tool-0.3.1.tar.gz
Algorithm Hash digest
SHA256 3131734e77f43c54b5672070eeddbdfc761f468007f611cc06ff0f91f9aa9abc
MD5 89138c2c810d2f4e989386b318f3c37f
BLAKE2b-256 f63de340dec4c0a9e61fece09ea5685183963cb725250639e30c0377162e442d

See more details on using hashes here.

Provenance

The following attestation bundles were made for aporn_tool-0.3.1.tar.gz:

Publisher: workflow.yml on christiantroyandrada/aporn-tool

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file aporn_tool-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: aporn_tool-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 45.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for aporn_tool-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 41377780e5406c1247536ddacff49ddbc7358c2f030106e123b6b5ed615fb3d1
MD5 1a7e5c050ac4d26900bb0550cff814f0
BLAKE2b-256 f20a2bc8748ae15fdd02fdde396e38481d2ca8af4b46118b76871aecf2504c9c

See more details on using hashes here.

Provenance

The following attestation bundles were made for aporn_tool-0.3.1-py3-none-any.whl:

Publisher: workflow.yml on christiantroyandrada/aporn-tool

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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