phew, at least that’s not something with nind-denoise, which is like a blackbox to me since I have no idea how to tweak/fix it.
Do you have a particular reason to have the modules in a custom order (instead of sticking to the default v5.0 for RAW input)? The script doesn’t re-order the modules, so there might be color gamut clipping somewhere along the pipeline (I tested using the same XMP file you shared, so that’s probably not the cause).
If you want to be sure, load the NEF file in darktable, reset the module order to v5.0 for RAW input, compress history, write the sidecar file, then try the dt_nind_denoise script again.
This photo was originally edited in June 2021, so more than 4 years ago – it most likely used some old, modified module order. I’ll check it and edit this post with what I found out and tried.
EDIT:
I changed the module order, compressed the history stack and the DSC_0339_s1.tif looks pretty much the same. I interrupted the denoise as I didn’t think it was necessary.
I have some (hopefully constructive) feedback after having played with it for a few hours over the last couple days. You can see my work in my fork of the above.
Installation was dependency hell. I’ve tried to document how I hacked together some reproducibility, but YMMV and it’s super-rough dev stuff. Which brings me to:
You really ought to consider breaking out that megascript into a python library and packaging it on its own. There’s a lot of useful stuff in there that’s probably more generally applicable than just to this usecase.
nind_denoise could also be packaged. I’m noodling how best to do that, considering:
I think that an automated download of model weights should be considered a mandatory feature before this can really be called usable.
I haven’t really thought about or looked at the actual lua side of things, but I know there are some good examples out there that folks’ have written. Regardless, I’d straighten out, polish & package the python side before worrying about that.
The actual results are great! I think this is worth putting some effort into.
Sweet! I’ve only been using the script for my own simple needs, thus, asking for feedback to make the script more accessible (especially for Windows, as you can see the long back and forth chain.
I’m not good at packaging (and I don’t code in Python that often), so you’ll have to take over from here. I’ll update the first post pointing to your fork once you feel it’s stable enough.
No idea if it’s stable enough (so best assume not), but the real issue is I only made updates that will work with intel GPU equipped machines. Probably best to let me extend that to cuda/cpu machines before telling people to use mine over yours. I was planning on submitting a PR anyway.
I’ve tried your fork but it seems nothing changes for me.
I have an Intel GPU, this is what I get from clinfo:
Device Name Intel(R) Iris(R) Xe Graphics
Device Type GPU
I’m using Linux Mint 22.1
If I run the denoise script I have the same times of the standard versions, and all my CPU vcores works near 100%. I still have this output when running the script:
get_device: cuda not available
That sounds like you maybe didn’t checkout the darktable-cli-xpu branch? That may be my fault for omitting it in the readme’s first method. I’ll go fix that right quick
Ok,
I was using the old .ini file that pointed to the old venv.
Now the path is correct, and I receive this error:
Traceback (most recent call last):
File "/home/alessandro/Apps/nind_denoise_xpu-0.1.0/src/nind_denoise/denoise_image.py", line 20, in <module>
import torchvision
File "/home/alessandro/Apps/nind_denoise_xpu-0.1.0/.venv/lib/python3.13/site-packages/torchvision/__init__.py", line 5, in <module>
import torch
File "/home/alessandro/Apps/nind_denoise_xpu-0.1.0/.venv/lib/python3.13/site-packages/torch/__init__.py", line 405, in <module>
from torch._C import * # noqa: F403
^^^^^^^^^^^^^^^^^^^^^^
ImportError: /opt/intel/oneapi/compiler/2025.2/lib/libur_loader.so.0: version `LIBUR_LOADER_0.10' not found (required by /home/alessandro/Apps/nind_denoise_xpu-0.1.0/.venv/lib/python3.13/site-packages/torch/lib/../../../../libsycl.so.8)
Error: denoised image not found: /tmp/20250816_0288_s1_denoised.tiff
Maybe my driver version is incompatible with thorch version… I have to try different versions.
May I ask which version of the Intel Driver do you have? I have the latest one: 2025.2.1-41
I believe I have the latest one. If I were you I’d try to nuke the venv and try again.
Or wait a day or two for me to clean up and push a slightly more heavy-handed approach to portability. That near-future update will support cpu/gpu/xpu on both windows and linux, although I haven’t made any improvements to debrittle the install process or package it better. It’ll still be a prototype, but hopefully a prototype that runs on a wider range of machines
I’ve also looked into ML-driven denoise for darktable for some time now.
I’m more involved into direct denoising of raw data, so I don’t have much hands-on experience with natural image denoising (yet ).
I’ll try your nind-workflow as soon as possible. Thanks!
I have some thoughts and a little bit of experience with the darktable denoising workflow:
Have you considered going the route like Lightroom etc? Many programs have the ai denoise as a separate feature that creates a denoised dng which is grouped with the original image.
In darktable, this would mean you’d have a button in lighttable to denoise the selected images. Then, for each image, a denoised and demosaiced dng which is still in Sensor RGB color space is created and grouped. As it is in the camera color space, applying/copying the history from the raw to the dng produces the same result (apart from modules working on mosaiced data, of course).
This has the advantage that you compute the denoised image once and you can also work with the denoised images in darkroom in realtime, which is important for high iso where color casts from the noise may yield unexpected results when editing a noisy image and then doing denoise on export.
There is, however, the drawback of additional dng image files that are created.
As nind is trained on demosaiced and white balanced images, I guess the pipeline for denoising an image would be like demosaic → chromatic adaption → sensor rgb to some rgb color space → denoise → backtransform color space and chromatic adaption to raw color → save rgb
I’m currently working on a simple lua script calling a python backend for denoising for my own experiments. Happy to share when it works!
This is how dt’s HDR merge works, so it could be sensible and easy to reuse this DNG writing code.
There might be more drawbacks - IIRC there was problem applying some lens corrections to a DNG while it worked on the original raw, and similar gotchas…
There might be more drawbacks - IIRC there was problem applying some lens corrections to a DNG while it worked on the original raw, and similar gotchas…
Yes, that could be. I create the DNG in python and then copy the Exif via exiftool from the RAW to the DNG (despite some fields that need some transformation according to dng standard like the color matrix).
I noticed that in particular the lens correction with embedded parameters seems not to work - like in the issue - but I haven’t investigated whether this is caused by incomplete exif copy or the handling by darktable.
There are definitely better and more sophisticated ways of doing this, both from a workflow perspective and on the ML side, where synthetic noise pipelines & unsupervised learning seem to be becoming the way to go (IMO anyway). I’d love to try and pivot to that stuff - but! - not yet. To my knowledge, there does not exist any OSS solution that does what this does as well as it does, even if we look beyond darktable. So I figure its probably worth putting some time massaging what @sillyxone has scripted up into something actually portable and broadly usable.
So yeah - I’m doing my best not to get distracted from the immediate goal of having a python tool that can do denoising inference on real photos that real people have on their real competers. (…and associated lua plugin tagged on as bonus deliverable) I’d love to get some discussion and ideas going about what to do after that, because the way I see it most any direction will merit some heavy thinking/planning upfront.
(Also I am painfully aware that I am not a real expert, and thus attend with measured anticipation the hope that someone with some real understanding will lay down some Knowledge)
As an addendum - you surmise correctly that the way the models in nind_denoise were trained somewhat necessitates the current overly-complex-and-brittle workflow. I very much want to get away from that, and see at least two options: either pick up where the author left off and retrain on a modified dataset that works on RAW images, or try and pull in something more SotA to accomplish the same.
Either way will likely precipitate a rewrite to make the whole thing properly structured. I’d like to abstract away enough that you can just drop in a new model at whim, and I’d really like to be able to deploy this as a service so I can take my laptop out of the freezer.