arcsec-core 0.2.0

Plate-solving library behind the arcsec CLI: star detection, quad matching, blind solving and WCS fitting
Documentation

arcsec-core

crates.io docs.rs License: MIT

The solving library behind arcsec, an astrometric plate solver: given the pixels of an astronomical image and a rough idea of where it points, it finds the exact position, scale and rotation as a WCS solution.

Most people want the command-line tool instead, which reads FITS, XISF and ASDF files, installs star catalogues, writes ASTAP-compatible output files and is a drop-in replacement for astap_cli:

cargo install arcsec

This crate is for Rust programs that want to solve in-process. It does not read image files: you supply the pixels.

What is in it

  • pipeline::solve_image — the catalogue solve. Detects stars, builds ASTAP-style four-star quads, and searches outwards from the hint position in a spiral, matching against an ASTAP star database (.1476, .290 or .001 files). Returns a WcsSolution.
  • blind_solve with load_anet_index — a position estimate with no hint, from an Astrometry.net index file. Returns an approximate RA/Dec to pass to solve_image as its hint.
  • catalog — readers for the ASTAP star databases (read_catalog_stars, detect_layout) and the Astrometry.net index format (load_anet_index, peek_anet_scale).
  • types — ImageBuffer (row-major f32 greyscale pixels), WcsSolution, and the star and quad types used between stages.
  • set_max_threads — one process-wide limit on worker threads for every stage; 1 makes a solve single-threaded.

The lower-level modules (detection, quads, math, wcs) are public too, but are shaped by the pipeline's needs rather than designed as a general-purpose API.

Angles are radians in the parameters and in the solution's centre (ra0, dec0); only the FITS-style terms of WcsSolution (CD matrix, CDELT, CROTA2) are in degrees, as they are written to a header. Star databases come from ASTAP; the arcsec CLI can install them (arcsec catalog install d50), or use an existing ASTAP directory.

Example

use arcsec_core::ImageBuffer;
use arcsec_core::pipeline::{SolveMethod, SolveParams, solve_image};

fn main() -> arcsec_core::Result<()> {
    // Greyscale pixels, row by row from the top-left: data[y * width + x].
    let (data, width, height) = load_pixels();
    let mut img = ImageBuffer { data, width, height };
    // Rescales float data in physical units into the range detection expects;
    // leaves 16-bit camera data alone.
    img.normalize_for_detection();

    let params = SolveParams {
        ra_hint: 83.8_f64.to_radians(),
        dec_hint: (-5.4_f64).to_radians(),
        fov: 1.5_f64.to_radians(),          // image height
        search_radius: 10.0_f64.to_radians(),
        quad_tolerance: 0.007,
        hfd_min: 1.5,                       // minimum star size, in pixels
        max_stars: 500,
        db_path: "/path/to/star_databases".into(),
        db_name: "d50".into(),
        binning: 1,
        method: SolveMethod::Quads,
        threads: 0,                         // one per core
    };

    let wcs = solve_image(&img, &params)?;
    println!(
        "centre RA {:.5}°, Dec {:.5}°, {:.3}\"/px",
        wcs.ra0.to_degrees(),
        wcs.dec0.to_degrees(),
        wcs.cdelt2.abs() * 3600.0,
    );
    Ok(())
}

fn load_pixels() -> (Vec<f32>, usize, usize) {
    todo!("read the image with a FITS or other image library")
}

The WcsSolution carries the reference point (ra0, dec0, crpix1, crpix2), the CD matrix, cdelt1/cdelt2 and crota2, in the original image's pixels even when the image was binned, plus the fit statistics. Errors are ArcsecError; the CLI maps them to ASTAP's exit codes.

Status

The API follows the needs of the arcsec CLI and may change between 0.x releases; see the changelog. How the solver works is described in docs/plate-solving.md.

The approach is ASTAP's, by Han Kleijn; see the arcsec README for credit.

License

MIT.