- Rust 71.2%
- Python 20.6%
- R 4.2%
- Shell 1.2%
- Makefile 1%
- Other 1.8%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| .cargo | ||
| assets | ||
| crates | ||
| siril | ||
| testdata/samples | ||
| tools | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
astrosharp-rs
A Rust port of AstroSharp's image processing. The original is an R/Shiny app packaged with Electron. This port covers its models:
- PSF (sharpen), AstroClean (denoise) and Hybrid (PSF then AstroClean).
- Dual PSF, from the app's
DualPSFbranch: one PSF model for the stars and another for the rest of the image (the deep-sky object), mixed through a feathered star mask. - Star Mask, which outputs that mask, for tuning it or for use elsewhere.
The legacy "First Beta" and "Second Beta" models are not ported, nor is the DualPSF branch's experimental linear-data PSF, which that app doesn't offer.
It reads TIFF and FITS (Siril) images and saves TIFF, FITS, PNG or JPEG.
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.
AstroSharp was originally created by Mark Lowry (Deep Sky Detail), who kindly agreed to this open-source port. If you find it useful, consider buying him a coffee.
Downloads
Installers are on the releases page. They aren't signed with a paid certificate, so expect a warning the first time.
- macOS (Apple Silicon, macOS 11 or later): unzip
AstroSharp-<version>-macos-arm64.zipand moveAstroSharp.appto Applications.- The first time you open it, macOS says it can't check the app for malware. Go to System Settings > Privacy & Security and click Open Anyway; this is only needed once.
- The CLI is inside the app, at
AstroSharp.app/Contents/MacOS/astrosharp-cli.
- Windows 10 and 11 (x64 or ARM64): run
AstroSharp-<version>-setup.exe; see Windows for what it installs.- SmartScreen may show "Windows protected your PC". Click More info, then Run anyway.
- Linux: build and install from source with
make install-linux; see Linux. - Siril:
AstroSharp.pyruns AstroSharp from inside Siril; see Siril script.
Recommended workflow
AstroSharp is meant as a final touch-up on a stretched (non-linear) image. The models were trained on stretched data, so stretch first (in Siril, for example) and run AstroSharp last.
Images that look linear trigger a note in the GUI and on the CLI's stderr: the warning fires when 99% of pixels are darker than 0.15. Linear stacks typically sit at or below 0.04, and stretched images at 0.5 or above. Processing still runs, and linear images also look nearly black in the GUI.
Layout
| Path | Contents |
|---|---|
crates/core |
Library: MLP inference, 9x9 feature windows, pipeline, star mask (ports of CImg's recursive blur, Hessian and labelling), sRGB↔Luv, TIFF/FITS I/O, plate-solution (WCS) coordinates, embedded weights |
crates/cli |
astrosharp command-line tool |
crates/gui |
astrosharp-gui desktop app (egui/eframe) |
crates/telemetry |
Tracing setup shared by the CLI and GUI: stderr logging and OpenTelemetry export |
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/package_windows.ps1, tools/windows/ |
Builds the Windows (ARM64) installer with Inno Setup |
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 (macOS), AppIcon.ico (Windows) and icon-512.png (window/Dock icon) |
siril/ |
Siril script (AstroSharp.py) that runs the CLI on Siril's open image, with its tests |
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 install-linux # Linux: install the GUI, CLI and a desktop launcher in ~/.local
make check # rustfmt check + clippy + tests
make icon # re-render assets/icon.svg into AppIcon.icns, AppIcon.ico + icon-512.png (commit the results)
make golden # regenerate R reference outputs (R_APP=... if not ../AstroSharp/resources/app)
make siril-install # copy the Siril script to ~/.siril/scripts
make siril-test # test the Siril script against a fresh CLI build (needs Python 3)
The app bundle also contains the CLI, at /Applications/AstroSharp.app/Contents/MacOS/astrosharp-cli
after make install (the Siril script uses it from there).
CLI example: astrosharp in.fit out.fit --model hybrid --psf 3 --aggressiveness 0.66.
The input can be TIFF or FITS (.fit/.fits/.fts).
Options:
--model dual-psf|hybrid|psf|astroclean|star-mask(defaultdual-psf)--psf <1..8 step 0.25>: the PSF model; fordual-psf, the one used away from stars--star-psf <1..8 step 0.25>: the PSF model for the stars (dual-psf)--aggressiveness <0..1>--mode seamless|parity(see Modes)--chunk-size <n>(Hybrid and Dual PSF in parity mode only)- Star mask (
dual-psf,star-mask), with the R app's defaults:--sensitivity <0..100>(98): percentile of the star response above which pixels count as stars.--fix-mask <n>(2): leaves out the regions numbered up ton, counted down each column from the left. Region 0 is normally the background.--feathering <sigma>(5): blur of the mask's edges, in pixels.--blend <a>(9) and--blend2 <b>(100): shape of the beta curve that turns the feathered mask into weights.
- Output format follows the file extension:
.tif/.tiff,.fit/.fits/.fts,.pngor.jpg/.jpeg --depth <8|16|32>:- TIFF: 8, 16 (default) or 32 (float).
- FITS: 16 or 32. The default is the input FITS's depth, otherwise 32.
- PNG: 8 or 16 (default).
- JPEG: 8 only.
--quality <1..100>(JPEG only, default 90)--progress: print progress to stdout while processing, asprogress <fraction>lines from 0 to 1, for scripts such as the Siril one
GUI (Dual PSF is the default model):
-
Processing starts with "Process image"; opening a file never processes it. A progress bar with Cancel shows while it runs.
- The buttons are colour-coded by what they do: blue processes, amber discards the result, red discards the result and the settings.
-
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.
- Changing only Aggressiveness reuses the last run's neural-network results, so the update takes a fraction of a second (about 0.1 s at 20 MP, compared with 1.7 s for a full Hybrid run). The result is identical to processing from scratch.
- With Dual PSF and Star Mask, the star mask settings (and for Dual PSF the mode and chunk size) don't need the networks rerun either. The image's star response, the costly part of the mask, is also kept, so a mask change takes about 0.3 s at 19 MP, compared with 2.2 s for a full Dual PSF run.
- A change made while the first run is still going waits for it to finish, rather than starting over.
- The reused results take memory, so they're only kept when the original, the result and the results fit in half the installed RAM. For example, on an 8 GB machine an 89 MP colour image goes without, and every update reprocesses. The star response takes 8 bytes per pixel.
-
Navigation: drag to pan, scroll or pinch to zoom, double-click to fit. Hold Space to show the original.
-
Cursor readout (bottom left): the pixel under the cursor, counted from the top-left like Siril, and the zoom.
- For a plate-solved FITS file it also shows the sky coordinates, e.g.
α 23h59m47s δ +66°42'41", matching Siril's readout. The status line says "plate-solved" for such files. - See Plate solutions for which solutions are supported.
- For a plate-solved FITS file it also shows the sky coordinates, e.g.
-
Dual PSF has two PSF sliders: DSO PSF for the image as a whole and Star PSF for the stars. Star Mask shows the mask that Dual PSF uses; tune it there, then switch to Dual PSF. Both have a Star mask section with the five mask settings (see the CLI options above) and a Defaults button.
-
Histogram (below the save options): the displayed result's histogram, as in the R app. For Dual PSF and Star Mask, the red line is the Blend / Blend 2 beta curve; it maps the feathered mask to weights.
-
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.
-
Open image… (or drop a file on the window) accepts TIFF and FITS.
-
Reset image and Reset all sit under the processing buttons. Both discard the processed result, cancelling any processing in progress, and reload the image from disk, for example after you've changed it in another program. If the file can no longer be read, the image as first loaded is shown.
- Reset image keeps the model settings. The zoom and preview region are kept too, unless the image's size changed.
- Reset all also restores the default model settings (Dual PSF, DSO and star PSF 3, Aggressiveness 0.66, Seamless, and the star mask defaults) and a fresh view.
- Both keep the view options and the Save as choice. With Live update on, neither reprocesses until you change a setting.
-
Save as picks the output format:
- TIFF (default): 16-bit, or 32-bit float for further processing.
- FITS: 32-bit float or 16-bit. This is selected automatically, at the source's depth, when you open a FITS file.
- 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.
Linux
- Installing:
make install-linux(ortools/install_linux.sh) builds a release and installs AstroSharp for the current user, with no root needed.- The GUI goes in as
~/.local/bin/astrosharp-guiand the CLI as~/.local/bin/astrosharp-cli, the same name as on macOS and Windows. - It adds an AstroSharp launcher with the app icon to
~/.local/share, so the app appears in the desktop's app grid and its window gets the right icon in the dock. make uninstall-linuxremoves it all again.BINDIRandXDG_DATA_HOMEchange where the files go.
- The GUI goes in as
- Building only:
cargo build --release -p astrosharp-gui -p astrosharp-clibuilds without installing. - Wayland desktops (e.g. GNOME): the GUI runs through XWayland, because that's the only way files dropped from the file manager reach it.
ASTROSHARP_WAYLAND=1runs it as a native Wayland client instead. That's sharper with fractional scaling, but files can't be dropped on it.- If the X server isn't reachable, it falls back to Wayland by itself and logs a warning.
Windows
tools/package_windows.ps1 builds one installer for both 64-bit Windows architectures, ARM64 and x64; it installs the native build on each machine. Build it on Windows on ARM (for example Windows 11 under Parallels on Apple Silicon), where the ARM64 toolchain also cross-compiles the x64 build. Run it from the repository in PowerShell:
powershell -ExecutionPolicy Bypass -File tools\package_windows.ps1
- Output:
target\release\bundle\windows\AstroSharp-<version>-setup.exe. - Prerequisites:
- Rust's native ARM64 toolchain, with the x64 target added:
rustup toolchain install stable-aarch64-pc-windows-msvc, thenrustup target add x86_64-pc-windows-msvc --toolchain stable-aarch64-pc-windows-msvc. It needn't be your default; an x64 default runs under emulation and is noticeably slower. - Visual Studio 2022 Build Tools with MSVC v143 – VS 2022 C++ ARM64/ARM64EC build tools, MSVC v143 – VS 2022 C++ x64/x86 build tools and a Windows SDK.
- Inno Setup 6:
winget install --id JRSoftware.InnoSetup -e.
- Rust's native ARM64 toolchain, with the x64 target added:
- The installer:
- Installs for the current user only, with no administrator rights needed, into
%LOCALAPPDATA%\Programs\AstroSharp. - Picks the build that matches the machine: ARM64 on Windows on ARM, x64 on Intel and AMD PCs.
- Installs
AstroSharp.exe(the GUI) andastrosharp-cli.exe(the CLI), adds a Start menu shortcut, and registers an uninstaller in Settings > Apps. - Offers two unticked options: a desktop shortcut, and adding the CLI to your PATH.
- Installs for the current user only, with no administrator rights needed, into
- The executables carry the AstroSharp icon and version details, need no Visual C++ Redistributable, and the GUI opens without a console window.
- Signing: the installer isn't code-signed. Windows SmartScreen only warns about it when it was downloaded from the internet.
Siril script
siril/AstroSharp.py runs AstroSharp on the image open in Siril (1.4 or later):
- Every model, with the same settings as the app.
- A preview with zoom, pan and a before/after divider, and a progress bar while it processes.
- Send to Siril applies the result with an undo point and records the settings in the FITS HISTORY.
- It also runs from Siril scripts (
.ssf), for examplepyscript AstroSharp.py -model dual-psf -starpsf 2.
To install it, put AstroSharp.py from a release in a folder on Siril's script path (listed under Preferences → Scripts); from a checkout, make siril-install copies it to ~/.siril/scripts. It uses the AstroSharp CLI from the app's install location. siril/README.md has the details.
FITS (Siril)
-
Supported files: uncompressed FITS with the image in the primary HDU, grey or RGB (three planes). Samples can be 8/16/32/64-bit integer or 32/64-bit float, which covers what Siril writes.
-
Not supported: compressed FITS (
.fz) and images stored only in extensions. -
Values: integer data is scaled by its type's range (after
BZERO/BSCALE). Float data is used as stored, since Siril keeps it in 0–1; float data clearly outside that range is scaled down and restored on save. Blank (NaN) pixels become 0. -
Row order: follows
ROWORDER, defaulting to FITS's bottom-up. Images are processed top row first, like TIFFs, and written back in the source's row order. -
Header: saving as FITS from a FITS source keeps every header card verbatim and in order, except for the following:
- Structural keywords (
SIMPLE,BITPIX,NAXISn,EXTEND,BZERO,BSCALE) are regenerated. - Values made stale by processing (
CHECKSUM,DATASUM,DATAMIN,DATAMAX,BLANK) are dropped. DATEis refreshed.- A
HISTORY AstroSharp <version>: <settings>line is appended.
Plate solutions (WCS/SIP), observation details and history are therefore kept, and any HDUs after the image are copied unchanged.
- Structural keywords (
-
Plate solutions: the GUI reads the WCS keywords that Siril, ASTAP or astrometry.net write.
- Supported: the TAN projection, with or without SIP distortion, and a CD, PC + CDELT or CROTA2 + CDELT matrix.
- Coordinates are in the solution's own frame, normally J2000. Images without a usable solution, including TIFFs and unsolved stacks with only the pointing RA/DEC, show pixel coordinates only.
-
Linear data: see Recommended workflow.
Tracing (OpenTelemetry)
The CLI and GUI can send traces of what they do to an OpenTelemetry endpoint such as VictoriaTraces. Nothing is sent unless an endpoint is configured.
-
Configuration: set the standard variables in the environment, or in
~/.config/astrosharp/otel.env(under$XDG_CONFIG_HOMEif that's set;%APPDATA%\astrosharp\otel.envon Windows).- Apps launched from Finder don't see shell variables, so use the file for AstroSharp.app, and for the bundled CLI when Siril runs it.
- An endpoint in the environment overrides the file's.
# ~/.config/astrosharp/otel.env (KEY=value lines; # starts a comment) OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:10428/insert/opentelemetry -
Settings:
OTEL_EXPORTER_OTLP_ENDPOINTis a base URL;/v1/tracesis appended.OTEL_EXPORTER_OTLP_TRACES_ENDPOINTis a full URL, used as is.OTEL_EXPORTER_OTLP_HEADERS(key=value,key=value) andOTEL_EXPORTER_OTLP_TIMEOUT(milliseconds, default 5000).OTEL_SDK_DISABLED=trueturns export off.OTEL_SERVICE_NAMEandOTEL_RESOURCE_ATTRIBUTESwork from the environment only.
-
Transport: OTLP over plain
http://, protobuf-encoded. HTTPS and gRPC aren't built in. -
Services:
astrosharp-cliandastrosharp-gui, tagged withservice.version. -
Spans cover each operation and processing stage:
- The CLI's
runspan hasread_image,processandsave_imageas children. - In the GUI,
open_image,process_job(full image or preview, with anoutcomeof ok, cancelled or failed),save_jobandreset(image or all) each start their own trace. - Under
process:to_luvandfrom_luv(colour only),psf_passandastroclean_pass, orhybrid_parityin R parity mode. - For Dual PSF and Star Mask:
star_response,star_mask(with the threshold and number of regions),psf_passwithwhich=dsoorstars, anddual_parity_masksin R parity mode. - Previews have a
regionfield onprocess. - Failures mark the top span as an error, with the message.
- The CLI's
-
Detail:
ASTROSHARP_TRACEfilters what is exported, usingEnvFiltersyntax (defaultastrosharp=info).ASTROSHARP_TRACE=astrosharp=debugadds a span per parity-mode chunk and FITS header details.- It can also go in
otel.env.
-
Logging: warnings and errors, including failed exports, go to stderr;
RUST_LOGchanges the level (defaultwarn). -
Privacy: traces include the full paths of the files you open and save.
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, ~50 s
cargo test --release
The reference app is the DualPSF branch of AstroSharp; the Dual PSF and Star Mask references need the imager (tested with 1.0.8), magrittr and dplyr packages. If testdata/golden is missing, the R-comparison tests print SKIPPED and pass. The tests cover:
- Processed values: PSF, AstroClean and Hybrid match R within 2.4e-15 (f64 rounding noise), and Dual PSF and Star Mask within 2e-13. The cases cover grey and colour images, several chunk sizes, preview crops and non-default mask settings.
- Star mask: the ports of CImg's blur and Hessian match a plain-arithmetic transcription in R bit for bit, and imager itself within 6e-13. imager may be compiled with fused multiply-adds, which explains the difference. Thresholds, region labels and the thresholded pixels are identical.
pbeta(a port of the Cephes incomplete beta) matches R within 3e-13. - Colour output: matches R exactly.
- 16-bit TIFFs: identical to the R app's
writeTIFFoutput, sample for sample. - Building blocks:
readTIFFscaling, R'sround(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
-
parityreproduces the R app exactly:- Hybrid is processed in chunks, including faint seams at chunk boundaries: stage 2 sees unsharpened pixels at each chunk's rim.
- Dual PSF builds a separate star mask for each chunk, so its result depends on the chunk size.
- Star Mask of a colour image is grey RGB.
-
seamless(default) processes the whole image at once instead:- Hybrid runs in two whole-image passes.
- Dual PSF uses one star mask for the whole image, the one Star Mask shows.
- Colour output keeps full precision. R rounds it to 5 decimals, which would cost precision in 32-bit linear data.
- Star Mask outputs a single grey channel.
For grey PSF, AstroClean and Star Mask, 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 gives exactly the full-image result there (except Hybrid in parity mode). Models that look at nearby pixels process the region with an 8 px margin; the star mask comes from the whole image. The R app processed a fixed 10% crop as a standalone image.
- Histogram bins are a fixed 1000 over 0–1; R's
histpicks its breaks from the data. - Star mask in the R app's Windows build comes from an older imager release, which may treat Feathering below 0.5 differently; the references come from imager 1.0.8.
- Out-of-range values saturate when written to 16-bit; R's
writeTIFFwraps them. - Alpha channels are dropped instead of failing.
- TIFF tags. Output files carry a
Predictor=1tag. 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 |
| Dual PSF, grey / RGB | — | 2.5 s / 2.7 s (same in parity mode) |
| Star Mask, grey / RGB | — | 0.45 s / 0.5 s |
Memory: images are held in double precision, which is 8 bytes per channel per pixel. An 89 MP colour image therefore takes 2.1 GB.
- CLI: peaks at about 2.3 times that, roughly 5 GB.
- GUI: also holds the result. While reprocessing, it frees the old result's full-resolution copy and keeps only what's on screen.
License
MIT; see LICENSE. The original AstroSharp, including the trained models embedded here, is by Mark Lowry (Deep Sky Detail) and is also MIT-licensed.