seiza 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
seiza-0.1.0/Cargo.toml ADDED
@@ -0,0 +1,43 @@
1
+ [workspace]
2
+ resolver = "3"
3
+ members = ["seiza", "seiza-cli", "seiza-download", "seiza-fits", "seiza-sources"]
4
+
5
+ [workspace.package]
6
+ version = "0.7.0"
7
+ edition = "2024"
8
+ license = "Apache-2.0"
9
+ repository = "https://github.com/theatrus/seiza"
10
+ authors = ["Yann Ramin <github@theatr.us>"]
11
+
12
+ [workspace.dependencies]
13
+ seiza = { path = "seiza", version = "0.7.0" }
14
+ seiza-download = { path = "seiza-download", version = "0.3.0" }
15
+ seiza-fits = { path = "seiza-fits", version = "0.1.6" }
16
+ seiza-sources = { path = "seiza-sources", version = "0.2.0" }
17
+ image = { version = "0.25", default-features = false, features = ["png", "jpeg"] }
18
+ thiserror = "2"
19
+ anyhow = "1"
20
+ async-compression = { version = "0.4.42", features = ["tokio", "zstd"] }
21
+ clap = { version = "4", features = ["derive"] }
22
+ imageproc = "0.27"
23
+ flate2 = "1"
24
+ tar = "0.4"
25
+ fs2 = "0.4"
26
+ futures-util = "0.3"
27
+ directories = "6"
28
+ reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "stream", "json"] }
29
+ serde = { version = "1", features = ["derive"] }
30
+ ureq = { version = "3", features = ["json", "multipart"] }
31
+ serde_json = "1"
32
+ csv = "1"
33
+ toml = "1"
34
+ postcard = { version = "1", features = ["use-std"] }
35
+ memmap2 = "0.9"
36
+ sha2 = "0.11"
37
+ tokio = { version = "1", features = ["fs", "io-util", "macros", "rt", "time"] }
38
+ tokio-util = { version = "0.7.18", features = ["io"] }
39
+ zstd = "0.13.3"
40
+ rayon = "1"
41
+ rustc-hash = { version = "2" }
42
+ wide = "1.5"
43
+ multiversion = "0.8"
seiza-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,106 @@
1
+ Metadata-Version: 2.4
2
+ Name: seiza
3
+ Version: 0.1.0
4
+ Classifier: Development Status :: 4 - Beta
5
+ Classifier: Intended Audience :: Science/Research
6
+ Classifier: License :: OSI Approved :: Apache Software License
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Rust
9
+ Classifier: Topic :: Scientific/Engineering :: Astronomy
10
+ Requires-Dist: numpy>=1.21
11
+ Summary: Star detection, WCS fitting, and hinted/blind plate solving for astrophotography
12
+ Keywords: astronomy,astrophotography,plate-solving,wcs,astrometry
13
+ Author-email: Yann Ramin <github@theatr.us>
14
+ License: Apache-2.0
15
+ Requires-Python: >=3.9
16
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
17
+ Project-URL: Homepage, https://seiza.fyi
18
+ Project-URL: Repository, https://github.com/theatrus/seiza
19
+
20
+ # seiza (Python)
21
+
22
+ Python bindings for [seiza](https://github.com/theatrus/seiza): star
23
+ detection, WCS fitting, and hinted/blind plate solving for astrophotography,
24
+ implemented in Rust. Solves typical frames in a fraction of a second.
25
+
26
+ ```
27
+ pip install seiza
28
+ ```
29
+
30
+ Binary wheels cover Linux (x86_64, aarch64), macOS (universal2), and
31
+ Windows (x64); each is a single abi3 wheel for every CPython from 3.9 up.
32
+ Type stubs are included, and solving releases the GIL.
33
+
34
+ ## Solve an image
35
+
36
+ ```python
37
+ import numpy as np
38
+ import seiza
39
+
40
+ # One-time: download the verified solver catalogs into the shared cache.
41
+ paths = seiza.fetch_catalogs() # lightweight Tycho-2 set
42
+ catalog = seiza.StarCatalog.open(paths["stars-lite-tycho2.bin"])
43
+
44
+ # Detect stars in a 2D float32 (or uint8) luma array.
45
+ stars = seiza.detect(image_array)
46
+
47
+ # Hinted solve: approximate center and pixel scale. sip_order=3 also fits
48
+ # SIP distortion polynomials when enough matched stars support them.
49
+ solution = seiza.solve(
50
+ stars, catalog, width, height,
51
+ ra=150.1, dec=35.2, scale_arcsec_px=2.5, sip_order=3,
52
+ )
53
+ print(solution) # center, scale, matches, RMS
54
+ print(solution.rotation_deg, solution.flipped)
55
+ ra, dec = solution.wcs.pixel_to_world(100.0, 200.0)
56
+ ```
57
+
58
+ Stars can also be plain `(x, y, flux)` tuples from any other detector — the
59
+ solver only needs positions and relative brightness:
60
+
61
+ ```python
62
+ solution = seiza.solve([(x1, y1, f1), (x2, y2, f2), ...], catalog, w, h,
63
+ ra=..., dec=..., scale_arcsec_px=...)
64
+ ```
65
+
66
+ ## Blind solve
67
+
68
+ No position hint, only a plausible scale range. Uses the prebuilt whole-sky
69
+ pattern index and the deep Gaia catalog:
70
+
71
+ ```python
72
+ paths = seiza.fetch_catalogs(["stars-deep-gaia17.bin", "blind-gaia16.idx"])
73
+ catalog = seiza.StarCatalog.open(paths["stars-deep-gaia17.bin"])
74
+ index = seiza.BlindIndex.open(paths["blind-gaia16.idx"])
75
+ solution = seiza.solve_blind(stars, catalog, index, width, height,
76
+ min_scale_arcsec_px=0.5, max_scale_arcsec_px=15.0)
77
+ ```
78
+
79
+ ## FITS WCS output
80
+
81
+ Solutions convert directly to FITS WCS keywords (1-indexed `CRPIX`, TAN or
82
+ TAN-SIP projection, CD matrix, and the complete `A_p_q`/`B_p_q`/`AP_p_q`/
83
+ `BP_p_q` set when distortion was fitted):
84
+
85
+ ```python
86
+ cards = solution.fits_header_cards() # dict of keyword -> value
87
+ text = solution.fits_header_text() # 80-column cards ending with END
88
+ ```
89
+
90
+ The header text form is suitable for header-injection APIs — for example
91
+ Siril's `sirilpy` scripting interface (`set_image_header`), which makes a
92
+ seiza solve usable from a Siril Python script.
93
+
94
+ ## Notes
95
+
96
+ - Solving and detection release the GIL; other Python threads keep running.
97
+ - Catalog files are memory-mapped and SHA-256 verified at download time;
98
+ `fetch_catalogs` caches under the platform cache directory (override with
99
+ `cache_dir=` or `SEIZA_CACHE_DIR`).
100
+ - `seiza.StarCatalog.from_stars([...])` builds a small in-memory catalog for
101
+ tests and synthetic fields.
102
+
103
+ ## License
104
+
105
+ Apache-2.0
106
+
seiza-0.1.0/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # seiza (Python)
2
+
3
+ Python bindings for [seiza](https://github.com/theatrus/seiza): star
4
+ detection, WCS fitting, and hinted/blind plate solving for astrophotography,
5
+ implemented in Rust. Solves typical frames in a fraction of a second.
6
+
7
+ ```
8
+ pip install seiza
9
+ ```
10
+
11
+ Binary wheels cover Linux (x86_64, aarch64), macOS (universal2), and
12
+ Windows (x64); each is a single abi3 wheel for every CPython from 3.9 up.
13
+ Type stubs are included, and solving releases the GIL.
14
+
15
+ ## Solve an image
16
+
17
+ ```python
18
+ import numpy as np
19
+ import seiza
20
+
21
+ # One-time: download the verified solver catalogs into the shared cache.
22
+ paths = seiza.fetch_catalogs() # lightweight Tycho-2 set
23
+ catalog = seiza.StarCatalog.open(paths["stars-lite-tycho2.bin"])
24
+
25
+ # Detect stars in a 2D float32 (or uint8) luma array.
26
+ stars = seiza.detect(image_array)
27
+
28
+ # Hinted solve: approximate center and pixel scale. sip_order=3 also fits
29
+ # SIP distortion polynomials when enough matched stars support them.
30
+ solution = seiza.solve(
31
+ stars, catalog, width, height,
32
+ ra=150.1, dec=35.2, scale_arcsec_px=2.5, sip_order=3,
33
+ )
34
+ print(solution) # center, scale, matches, RMS
35
+ print(solution.rotation_deg, solution.flipped)
36
+ ra, dec = solution.wcs.pixel_to_world(100.0, 200.0)
37
+ ```
38
+
39
+ Stars can also be plain `(x, y, flux)` tuples from any other detector — the
40
+ solver only needs positions and relative brightness:
41
+
42
+ ```python
43
+ solution = seiza.solve([(x1, y1, f1), (x2, y2, f2), ...], catalog, w, h,
44
+ ra=..., dec=..., scale_arcsec_px=...)
45
+ ```
46
+
47
+ ## Blind solve
48
+
49
+ No position hint, only a plausible scale range. Uses the prebuilt whole-sky
50
+ pattern index and the deep Gaia catalog:
51
+
52
+ ```python
53
+ paths = seiza.fetch_catalogs(["stars-deep-gaia17.bin", "blind-gaia16.idx"])
54
+ catalog = seiza.StarCatalog.open(paths["stars-deep-gaia17.bin"])
55
+ index = seiza.BlindIndex.open(paths["blind-gaia16.idx"])
56
+ solution = seiza.solve_blind(stars, catalog, index, width, height,
57
+ min_scale_arcsec_px=0.5, max_scale_arcsec_px=15.0)
58
+ ```
59
+
60
+ ## FITS WCS output
61
+
62
+ Solutions convert directly to FITS WCS keywords (1-indexed `CRPIX`, TAN or
63
+ TAN-SIP projection, CD matrix, and the complete `A_p_q`/`B_p_q`/`AP_p_q`/
64
+ `BP_p_q` set when distortion was fitted):
65
+
66
+ ```python
67
+ cards = solution.fits_header_cards() # dict of keyword -> value
68
+ text = solution.fits_header_text() # 80-column cards ending with END
69
+ ```
70
+
71
+ The header text form is suitable for header-injection APIs — for example
72
+ Siril's `sirilpy` scripting interface (`set_image_header`), which makes a
73
+ seiza solve usable from a Siril Python script.
74
+
75
+ ## Notes
76
+
77
+ - Solving and detection release the GIL; other Python threads keep running.
78
+ - Catalog files are memory-mapped and SHA-256 verified at download time;
79
+ `fetch_catalogs` caches under the platform cache directory (override with
80
+ `cache_dir=` or `SEIZA_CACHE_DIR`).
81
+ - `seiza.StarCatalog.from_stars([...])` builds a small in-memory catalog for
82
+ tests and synthetic fields.
83
+
84
+ ## License
85
+
86
+ Apache-2.0
@@ -0,0 +1,31 @@
1
+ [build-system]
2
+ requires = ["maturin>=1.7,<2.0"]
3
+ build-backend = "maturin"
4
+
5
+ [project]
6
+ name = "seiza"
7
+ description = "Star detection, WCS fitting, and hinted/blind plate solving for astrophotography"
8
+ readme = "README.md"
9
+ license = { text = "Apache-2.0" }
10
+ authors = [{ name = "Yann Ramin", email = "github@theatr.us" }]
11
+ requires-python = ">=3.9"
12
+ keywords = ["astronomy", "astrophotography", "plate-solving", "wcs", "astrometry"]
13
+ classifiers = [
14
+ "Development Status :: 4 - Beta",
15
+ "Intended Audience :: Science/Research",
16
+ "License :: OSI Approved :: Apache Software License",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Rust",
19
+ "Topic :: Scientific/Engineering :: Astronomy",
20
+ ]
21
+ dependencies = ["numpy>=1.21"]
22
+ dynamic = ["version"]
23
+
24
+ [project.urls]
25
+ Repository = "https://github.com/theatrus/seiza"
26
+ Homepage = "https://seiza.fyi"
27
+
28
+ [tool.maturin]
29
+ features = ["extension-module"]
30
+ module-name = "seiza"
31
+ manifest-path = "seiza-py/Cargo.toml"
@@ -0,0 +1,31 @@
1
+ [package]
2
+ name = "seiza"
3
+ description = "Star detection, WCS fitting, and near-field plate solving for astrophotography"
4
+ version.workspace = true
5
+ edition.workspace = true
6
+ license.workspace = true
7
+ repository.workspace = true
8
+ authors.workspace = true
9
+ readme = "README.md"
10
+ keywords = ["astronomy", "astrophotography", "plate-solving", "wcs", "astrometry"]
11
+ categories = ["science", "multimedia::images"]
12
+
13
+ [features]
14
+ downloads = ["dep:seiza-download"]
15
+
16
+ [dependencies]
17
+ image.workspace = true
18
+ thiserror.workspace = true
19
+ seiza-download = { workspace = true, optional = true }
20
+ memmap2.workspace = true
21
+ rayon.workspace = true
22
+ rustc-hash.workspace = true
23
+ wide.workspace = true
24
+ multiversion.workspace = true
25
+ serde.workspace = true
26
+ serde_json.workspace = true
27
+ postcard.workspace = true
28
+ sha2.workspace = true
29
+
30
+ [dev-dependencies]
31
+ tempfile = "3"
@@ -0,0 +1,50 @@
1
+ # seiza (星座)
2
+
3
+ Star detection, WCS fitting, and plate solving — hinted and blind — for
4
+ astrophotography, in Rust.
5
+
6
+ - **Star detection** — tile-based background/noise estimation (median +
7
+ MAD), sigma thresholding, connected components, flux-weighted sub-pixel
8
+ centroids. `DetectConfig::backend` selects automatic, u8, or f32 sampling;
9
+ the shared pipeline is statically dispatched over the sample type.
10
+ - **WCS** — TAN (gnomonic) projection with a CD matrix: pixel ↔ world
11
+ transforms, scale/footprint helpers.
12
+ - **Hinted plate solving** — triangle matching over FOV-sized windows,
13
+ affine candidate voting, iterative least-squares refinement, seeded by an
14
+ approximate center and pixel scale. Solves real telescope images in tens
15
+ of milliseconds with sub-arcsecond RMS. Optionally fits SIP distortion
16
+ polynomials (orders 2-5, forward and inverse) when they improve the
17
+ residual.
18
+ - **Blind plate solving** — no position needed, only a plausible
19
+ pixel-scale range. A disc-anchored 4-star pattern index over the whole
20
+ sky is matched against quads of the brightest detections; hypotheses are
21
+ voted on, smoothed, and verified in parallel by the hinted solver.
22
+ Under 2 seconds per wide-field image including building the whole-sky
23
+ index from a 2.5M-star catalog; a 61 MP FITS frame goes from file open
24
+ to hinted solution in 0.7 s.
25
+ - **Star catalogs** — compact memory-mappable tile formats with cone
26
+ search; builders for Tycho-2, Gaia DR3 (via TAP), and ASTAP databases.
27
+ - **Object catalogs** — NGC/IC/Messier, Sharpless, Barnard, UGC, LDN, LBN,
28
+ Cederblad, vdB, PGC, named/HD stars, and live transient (supernova/nova)
29
+ lists built into an extensible, memory-mapped sectioned container with
30
+ stable source IDs, aliases, hierarchy, and provenance; query known sky
31
+ cones and convex footprints without plate solving, or project objects into
32
+ solved images with full ellipse geometry. Cold detail sections keep every
33
+ contributing upstream record, typed relations, preferred facet selections,
34
+ and source-qualified geometry (ellipses and outline contours) behind
35
+ `object_details`, `catalog_records`, `geometries`, `relations`, and
36
+ `capabilities`, without touching normal query paths. Legacy `SEIZAOB1` and
37
+ `SEIZAOB3` files remain readable.
38
+ - **Optional catalog downloads** — enable the non-default `downloads` feature
39
+ for `seiza::downloads`, an async, verified shared cache of published catalog
40
+ bundles. Normal catalog opens never access the network.
41
+
42
+ See the [`seiza-cli`](https://crates.io/crates/seiza-cli) crate for the
43
+ command-line tool, and [`seiza-fits`](https://crates.io/crates/seiza-fits)
44
+ for dependency-free FITS reading and autostretch. Raw catalog-building source
45
+ acquisition is separately available from
46
+ [`seiza-sources`](https://crates.io/crates/seiza-sources).
47
+
48
+ ## License
49
+
50
+ Apache-2.0
@@ -0,0 +1,18 @@
1
+ //! Print a named minor body's geocentric position at a JD.
2
+ use seiza::minor_bodies::MinorBodyCatalog;
3
+
4
+ fn main() {
5
+ let args: Vec<String> = std::env::args().collect();
6
+ let catalog = MinorBodyCatalog::open(std::path::Path::new(&args[1])).unwrap();
7
+ let jd: f64 = args[3].parse().unwrap();
8
+ for body in catalog.bodies() {
9
+ if body.name.contains(args[2].as_str())
10
+ && let Some((ra, dec, mag, delta)) = MinorBodyCatalog::position_at(body, jd)
11
+ {
12
+ println!(
13
+ "{}: RA {:.5} Dec {:+.5} V~{:.1} delta {:.3} AU",
14
+ body.name, ra, dec, mag, delta
15
+ );
16
+ }
17
+ }
18
+ }