GALOSH — a blind, training-free denoiser for raw files (free, Apache-2.0, drag-and-drop Windows builds + builds from source on Linux)

Sharing a denoiser I’ve been working on that might interest raw shooters here. GALOSH is classical (no AI, no training data) and fully blind — it estimates the noise model from your file, so there are no profiles to pick and it doesn’t care what camera you use.

Quality-wise it consistently beats the BM3D/NLM family on the public benchmarks (SIDD, RawNIND) at much lower runtime, especially on perceptual metrics — there’s a side-by-side viewer with every benchmark image if you want to pixel-peep: GALOSH — synchronized image comparison

For trying it on your own files there are Windows standalone builds — drag a DNG onto the exe, get name_GALOSH_l1_c1.dng next to it with all metadata copied (denoised DNGs open normally in darktable/RawTherapee): Releases · luxgrain/GALOSH · GitHub

On Linux it builds from source in seconds — it’s plain C99 + OpenMP, no dependencies (cd standalone && make all; the OpenCL GPU path just needs the OpenCL headers/ICD). The drag-and-drop bundles are Windows-only so far — happy to help anyone who wants to script it against their raws.

Everything is Apache-2.0 and the algorithm is documented to reimplementation level. A native darktable integration is a direction I’m actively working on (the code was written darktable-idiomatic from the start — the core entry point literally takes a dt_iop_roi_t), targeting the raw-domain denoise stage before demosaic. Feedback from this community on where it helps and where it falls short would be really valuable — high-ISO chroma blotches were the original motivation.

17 Likes

nice! welcome to the forum and congrats on this project. always nice to see simple/effective denoising. also appreciate your vulkan/subgroup optimised implementation :slight_smile: looks really interesting, i might try your code in my vulkan command buffers too see how it compares against other approaches. quite a lot of compute shaders there! are these variants or do we require all of these for one evaluation?

2 Likes

Wow, thanks — I honestly didn’t expect the vkdt author to show up in my thread. A little starstruck here :slight_smile:

Good question about the shader count — it looks scarier than it is. One raw frame in the default quality mode uses about 30 of the 53 kernels (a few of them run at several pyramid scales). The rest aren’t needed at the same time: speed-mode variants (--wht=4 / fast upsample), a classic fallback twin of the subgroup pass12 for devices without subgroup-size control, FP16-storage variants of a few kernels (same math, just different bindings at the storage points — compute is FP32 everywhere), some debug-dump-only kernels, and a separate small set for the YUV pipeline.

I did try to write down everything needed for re-hosting in standalone/vk/HOST_BLUEPRINT.md (dispatch order, bindings, push constants, workgroup sizes) — though I have no idea how readable it is to anyone but me, so if anything is unclear I’m happy to explain or fix the docs. One gotcha that cost me a few days: I round the f16 stores explicitly in-shader, because AMD’s hardware f32→f16 conversion turned out to round toward zero. And two of the heavy kernels can run long enough on slow iGPUs to upset the Windows watchdog — I split those into banded submissions, but I’d guess vkdt’s scheduler has its own way of dealing with that.

Would be really cool to see this compared inside vkdt — happy to help however I can.

2 Likes

Welcome to the forum and thanks for sharing!

1 Like

Welcome to pixls!

1 Like

Welcome, @luxgrain, and many thanks for your powerful contribution.

I downloaded to my Windows 11 laptop, and it runs without problems. Denoising takes about 20 seconds for 7378x4924 images from my Nikon D800.

For non-noisy images, it simply removes high-frequency detail. (This is not surprising.)

For noisy images, I consider the noise removal to be good, without looking artificial. There is the usual trade-off between removing noise and retaining detail. For example, a photo with stage (LED) lighting, ISO 6400, f/2.8, 1/320s.

Here are crops from the same image, converted from DNG to JPG, with crop, using ImageMagick, eg:

magick x_GALOSH_l0.6_c0.6.dng -crop 543x840+1254+2342 +repage x_l0.6_c0.6.jpg

Input noisy DNG. Notice the red stitches.

Galosh output, default parameters. No noise, but also no red stitches.

Galosh output, l 0.6, c 1. Slightly noisier; red stitches just visible.

Galosh output, l 0.6, c 0.6. Noisier, but better stitches.

As always, the “best” tradeoff is a matter of personal taste.

3 Likes

Oh wow, thanks for actually putting it through its paces! The D800 shots and going back and forth on l/c like that — really cool to see.

A few random thoughts on what you’re seeing:

The red stitches going soft at the default is kinda on purpose, honestly. GALOSH leans pretty hard on smoothing the high-frequency color stuff — that’s basically how it wipes out those high-ISO color blotches — so a tiny detail that’s mostly color (like red stitching) ends up getting smeared at c1. So you kind of found the fix yourself: turning c down is exactly the right lever for that, and l does the same thing for the luma side. “Best is personal taste” is honestly the real answer here, that’s what the two sliders are for.

And a nice side effect of doing it before demosaic: the noise is already gone by the time you interpolate, so even a punchy demosaicer like AMaZE shouldn’t turn leftover raw noise into extra speckle or those maze artifacts — there’s just not much left to amplify. No idea which one you used, but should be fine either way.

Anyway, thanks a ton for the writeup! If you ever hit a shot where no l/c combo does it for you, throw it my way — I’d love to take a look

First: thank you for sharing!
I wanted to give it a try…
On Windows I had to convert the raw file (Canon R6M3) to dng, because denoising cr3 resulted in a colour cast - but with the dng it worked well.

But my main OS is Linux, so I downloaded the sources, compiled it (no error messages), and I got these results:

./galosh_raw_cpu.exe pic.dng pic_d.dng 6974 4646 galosh
Raw Denoiser Standalone v6 (GALOSH)
Input: pic.dng (6974x4646)
Method: galosh
Params: luma=0.50 chroma=1.00
Read 21641137 floats, expected 32401204

If i enter 6 and 4 as width and height:
./galosh_raw_cpu.exe pic.dng pic_d.dng 6 4 galosh
Raw Denoiser Standalone v6 (GALOSH)
Input: pic.dng (6x4)
Method: galosh
Params: luma=0.50 chroma=1.00
Elapsed: 0.00 seconds
Output: pic_d.dng

OK, pic_d.dng has 96bytes, not really usable :wink: