Port of R-based AstroSharp tool to Rust
  • Rust 89.2%
  • R 7.3%
  • Makefile 2.1%
  • Shell 1.4%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Damien Stuart d4e16f8825 Add PNG and JPEG export; bump version to 0.2.0
- Core: save_image() writes TIFF (8/16-bit or 32-bit float), PNG (8/16-bit)
  and JPEG (quality 1-100, no chroma subsampling); 16-bit is the default
  where the format allows it.
- GUI: "Save as" format picker with per-format options; saving runs in
  the background.
- CLI: output format follows the file extension; --depth replaces --float,
  --quality sets JPEG quality.
- Round-trip tests for every format and depth.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:07:45 -04:00
assets Add app icon, draggable compare divider and live-update toggle 2026-10-11 15:42:29 -04:00
crates Add PNG and JPEG export; bump version to 0.2.0 2026-10-11 17:07:45 -04:00
testdata/samples Initial Commit 2026-10-11 14:36:44 -04:00
tools Add app icon, draggable compare divider and live-update toggle 2026-10-11 15:42:29 -04:00
.gitignore Initial Commit 2026-10-11 14:36:44 -04:00
Cargo.lock Add PNG and JPEG export; bump version to 0.2.0 2026-10-11 17:07:45 -04:00
Cargo.toml Add PNG and JPEG export; bump version to 0.2.0 2026-10-11 17:07:45 -04:00
Makefile Add app icon, draggable compare divider and live-update toggle 2026-10-11 15:42:29 -04:00
README.md Add PNG and JPEG export; bump version to 0.2.0 2026-10-11 17:07:45 -04:00

astrosharp-rs

A Rust port of AstroSharp's image processing. The original is an R/Shiny app packaged with Electron. This port covers the PSF (sharpen), AstroClean (denoise) and Hybrid (PSF then AstroClean) models. The legacy "First Beta" and "Second Beta" models are not ported.

The trained neuralnet weights are exported from the original .RDS files and embedded in the binaries, so nothing else is needed at runtime: no R, no Electron.

The upstream repository has no license covering its code or model weights. This port is for personal use; get the author's permission before redistributing it.

Layout

Path Contents
crates/core Library: MLP inference, 9x9 feature windows, pipeline, sRGB↔Luv, TIFF I/O, embedded weights
crates/cli astrosharp command-line tool
crates/gui astrosharp-gui desktop app (egui/eframe)
tools/export_weights.R Converts the .RDS models to crates/core/weights/*.bin
tools/make_golden.R Runs the original R functions headless to produce reference outputs
tools/bundle_macos.sh Builds an unsigned AstroSharp.app
tools/icon Standalone helper (uses resvg) that renders the icon SVG for make icon
assets/ App icon: icon.svg (source), plus the generated AppIcon.icns and icon-512.png (window/Dock icon)
testdata/samples The sample TIFFs shipped with the R app

Usage

make lists the common tasks:

make run [IMAGE=image.tif]   # desktop app
make release                 # build target/release/astrosharp and astrosharp-gui
make app                     # target/release/bundle/AstroSharp.app (unsigned)
make install                 # ...and copy it to /Applications (APP_DIR=... to change)
make check                   # rustfmt check + clippy + tests
make icon                    # re-render assets/icon.svg into AppIcon.icns + icon-512.png (commit the results)
make golden                  # regenerate R reference outputs (R_APP=... if not ../AstroSharp/resources/app)

CLI example: astrosharp in.tif out.tif --model hybrid --psf 3 --aggressiveness 0.66. Options:

  • --model hybrid|psf|astroclean (default hybrid)
  • --psf <1..8 step 0.25>
  • --aggressiveness <0..1>
  • --mode seamless|parity
  • --chunk-size <n> (Hybrid in parity mode only)
  • Output format follows the file extension: .tif/.tiff, .png or .jpg/.jpeg
  • --depth <8|16|32>: TIFF 8, 16 (default) or 32 (float); PNG 8 or 16 (default); JPEG 8 only
  • --quality <1..100> (JPEG only, default 90)

GUI (Hybrid is the default model):

  • Processing starts with "Process image"; opening a file never processes it. A progress bar with Cancel shows while it runs.

  • Live update (off by default) reprocesses about 0.25 s after the last settings change. With it off, nothing is processed until you press a button.

  • Navigation: drag to pan, scroll or pinch to zoom, double-click to fit. Hold Space to show the original.

  • Compare before/after (off by default) splits the view into original | processed. Drag the divider's handle (or the line) to move it.

  • Preview region only (off by default) processes just a region while you adjust settings. Choose it with Shift-drag or right-drag, and process the whole image with "Process full image". "Update preview" refreshes the region; with Live update on it also refreshes automatically.

  • Save as picks the output format:

    • TIFF (default): 16-bit, or 32-bit float for further processing.
    • PNG: lossless, 16-bit (default) or 8-bit.
    • JPEG: quality 50–100 (default 90), written without chroma subsampling to keep small coloured stars crisp.

    Saving runs in the background.

  • Quit closes the app.

Fidelity to the R app

cargo test --release checks the port against reference outputs generated by the R code:

Rscript tools/make_golden.R ../AstroSharp/resources/app testdata/golden   # once, ~25 s
cargo test --release

If testdata/golden is missing, the R-comparison tests print SKIPPED and pass. The tests cover:

  • Processed values: match R within 2.4e-15 (f64 rounding noise) for every model, both grey and colour, several chunk sizes and preview crops.
  • Colour output: matches R exactly.
  • 16-bit TIFFs: identical to the R app's writeTIFF output, sample for sample.
  • Building blocks: readTIFF scaling, R's round(x, 5) and the sRGB↔Luv conversion are bit-identical.

Behaviours deliberately reproduced:

  • Unprocessed border. Only pixels 5..n-5 (1-based) are processed; a 4 px border at the start and 5 px at the end keep their input values.
  • Feature order. The 9x9 features use getmatrix9's irregular column order, which the models were trained on.
  • Colour. Colour images go through R's sRGB↔Luv (R's own D65 white point), only L is processed, and the output is rounded to 5 decimals.

Modes:

  • parity reproduces the R app's chunked Hybrid processing, including faint seams at chunk boundaries: stage 2 sees unsharpened pixels at each chunk's rim.
  • seamless (default) processes the whole image in two passes instead. For PSF and AstroClean, both modes give identical output.

Intentional differences from the R app:

  • Colour vs grey is detected from the file. The R app needed the correct radio button and failed otherwise.
  • Preview uses any region you choose and processes it with an 8 px margin, so it matches full-image output. The R app processed a fixed 10% crop as a standalone image.
  • Out-of-range values saturate when written to 16-bit; R's writeTIFF wraps them.
  • Alpha channels are dropped instead of failing.
  • TIFF tags. Output files carry a Predictor=1 tag. libtiff in R logs a harmless "unknown field 317" warning when reading them.

Performance

Apple M5 Max, 6000x4000 (24 MP) image:

R app (single core) Rust
PSF, grey 110 s 0.95 s
Hybrid, grey not run at 24 MP (34.5 s at 4 MP) 2.0 s (2.9 s parity; 0.32 s at 4 MP)
PSF / Hybrid, RGB — 1.2 s / 2.2 s