Exporting/importing photos in full 32-bit representation (to train a neural network for image denoising)

What kind of error were you getting? If it’s the bash looping then something like the following seems to work:

mkdir out
cd in
cd ..
for i in ${IMGNAMES[@]}; do
python3 denoise_image.py --cs 256 --ucs 192 --model_path "models/4/model_192.pth" -i in/${i} -o out/$i

Worked like a charm! Thank you! The issue I had was that it named the output file to *.tif.

Noisy photo at ISO 12800 from my 6D.

NR in darktable, default settings

NR in NIMD. Much better, but colours are changed.

ISO 12800 in a dark forrest.
A bit soft in the white area under the head.


i’m really motivated to make this fast because i like the results… so i downloaded some of these images and indeed they are LDR jpg, 8-bit and black point subtracted, complete with gamma and everything as non linear as you could imagine. you mentioned you still have the raws… i’d be really interested in these :slight_smile:

other than that… i’d really feed the rawest possible data to the optimisation. pre-black point subtraction, linear camera rgb (maybe demosaiced + aligned if necessary). i suppose in such a linear/true to expectation fashion you could do noise2noise training and use many high iso shots instead of noisy/clean pairs. i think dcraw -r 1 1 1 1 -M -o 0 -6 would come close, unfortunately there only seems to be -D to force output before black subtraction… which also does not do any demosaicing.

oh and another thing i’d be interested in after looking at these images for a while: what does it look like in animation? say you denoise a timelapse. looking closely i did notice some low frequency pulsing in a still image, would that show in image sequences?


I guess one (e.g., you) could modify dcraw to suit the need.

The raws are now posted on https://nc.trougnouf.com/index.php/s/5HH8okM6rQBnFAo however that’s extremely slow (it’s on my home internet since I currently don’t have a host with this much storage) and disorganized at the moment. I will get around to organizing these, probably when I redevelop them into the right format (16-bit tiff with less processing.)

Linear processing should indeed greatly simplify the required network, and will probably improve the results too. I’m still not entirely clear about how to properly output images pre black point subtraction. Is it the “passthrough” “raw/white black point” in darktable? This module is applied before demosaic, is that not problematic if we want to add “nn denoising” in the pipeline? Most importantly, would this produce significantly different results for each sensor and hurt generalization? Could you share a xmp file with the ideal amount of processing applied? I think that would be demosaic, matched white balance (I guess it would be best to leave it at reference / 6502K? that matches the new color calibration module too), and matched exposure (I used darktable’s auto exposure with a % value, because it varies between shots even though the camera EV setting remains the same, though that should be pretty easy to do with any other tool/library).

In my experience many noisy shots did not result in the same level of detail as one base-ISO shot, but maybe I did not experiment enough with this method.

I’ve attached a couple of processing candidates; minimal with/without(_01) raw black/white point passthrough, reference 6502K white balance, auto exposure set to match the baseline image, and Linear Rec. 2020 output color profile.

baseline (raw): DSCF7745.RAF (32.2 MB)
exported w/ passthrough raw black/white point: DSCF7745.RAF.xmp (16.5 KB) , DSCF7745.tif (58.3 MB)
exported with std raw black/white point: DSCF7745_01.RAF.xmp (16.5 KB) DSCF7745_01.tif (70.9 MB)
matching ISO6400 raw file: DSCF7748.RAF (32.2 MB)

rawproc will let you save to 16-bit TIFF with no processing, other than the round-trip from libraw’s 16-bit → rawproc internal 0.0 -1.0 floating point → 16-bit TIFF export. If you don’t even like that, you can use either libraw’s unprocessed_raw.cpp sample or raw2tiff.cpp in my rawdata github repo (which uses libraw to get the 16-bit image array from the raw file).

Edit: Oh, in rawproc, you can add any combination of operators in any order, so per your need you could open a raw, add a demosaic to the toolchain, and save that to 16-bit TIFF.

1 Like

I’ve added your images to the dataset on Natural Image Noise Dataset - Wikimedia Commons (and the download script listed on that page) :slight_smile:

I tried to do minimal processing; demosaic, exposure and color calibration matching, filmic rgb, and alignment. That makes them a bit darker than usual but I’m adding data augmentation in the training to multiply the pixels by a chosen random range (default: [0.9, 1.1]).

All the images seemed valid, I just cropped the right side of Metalldel because the baseline had a slightly different lighting, and only kept up to ISO3200 from Vaxt-i-trad because the right side of the plant moved slightly (alternatively I could probably have kept all of them and cropped the right side there too but plants seem to move in unexpected ways so this seems safer).

I’m hoping to start training tonight, then I can push the updated training code (with built-in validation, MS-SSIM loss, and possibly better defaults) once I can validate that the model performs at least as well :slight_smile: MS-SSIM seems to require a minimum crop size of 161 px, so I’m pre-cropping the dataset to 256 with a stride of 192, dynamically cropping to 220 px (which should work well for U-Net) at train time, and doing the loss center crop at 161 px.

Can you guys that have managed to get this to work try denoising this image?

2020-12-14-X-T3-DSCF2168.RAF (28.2 MB)
2020-12-14-X-T3-DSCF2168.RAF.xmp (13.4 KB)

darktable 3.4.1 didn’t accept your xmp file, but I did give your picture a try anyway. Hard parts are the dark area bottom right and some parts of the sky.

1 Like

I’m not getting great results with this, probably because there is such a heavy use of sharpening / local contrast in the final processing (after the denoising). This seems to show the need for early denoising (train on unprocessed image and include early in the pipeline) to accommodate wide ranges of processing.

output of the neural network which received the given xmp processed image minus local contrast, contrast equalizer, and sharpening:
1.tif (20.6 MB)
reapply local contrast on the above:
1_01.tif (90.8 MB)

edit: slight but noticeable improvement with 16-bit output, but those output files are too large to upload here. I can at least upload the JPEG with local contrast and contrast equalizer:

The model I used here is still training. (250th epoch)


Updated code posted on GitHub - trougnouf/nind-denoise: Image denoising using the Natural Image Noise Dataset :tada:

I hope I didn’t forget anything or make it unstable. I’ve been training a U-Net and a UtNet for a few days with this code and @Peter 's images. No final model available yet but they are promising :slight_smile:

UtNet is a U-Net-like model I wrote where the decoder’s convolutions are replaced with transposed convolutions, so both sides can be symmetric and the processing footprint is at least 25% less (I can train with 1/3 bigger batches) because there is no need for padding and cropping. Moreover the denoising performance is better so far. It doesn’t quite solve the complexity requirements pointed by @hanatos but it’s a good start.

If you can’t wait for one of the latest models, then you can find the latest UtNet which I started training last night on my nextcloud, https://nc.trougnouf.com/index.php/s/T9xPGEGL7H2mCjx , but it’s even slower than usual because my ISP started throttling me and files might even disappear before the download finishes because the training loop cleans up non-best models (the very last is likely to be cleaned up next). I will upload the final models to something faster.

For the next steps I should investigate lighter architectures, and I will need to reprocess the dataset to better match the darktable pipeline (for that I would still like some insight).


Your denoise dataset is very promising. Keep on. Hope to see it some day as a module of darktable. For some of us with cameras with ISO 1600 and up is like Christmas.


Here is 2021-05-23T10:16_nn_train.py_--config_configs-train_conf_unet.yaml_--debug_options_output_val_images_keep_all_output_images_--test_interval_0_--epochs_1000_--reduce_lr_factor_0.95_--patience_3/generator_734.pt 's take on it :slight_smile:

results can be reproduced with pytorch denoise_image.py --network UNet --model_path <path_to_generator_734.pt> --input <input_image.tif> (I made the other arguments autodetected)
and the model should be downloadable on denoise_models – Google Drive . Note that this is not yet the more efficient UtNet which is still training.

I just rewrote denoise_image.py’s data loader to take in (and spit out) 16-bit images so performance might be improved slightly (in further processing like sharpening?) since new models are trained with some 16-bit inputs.

@KristijanZic what is the license on your image?

1 Like

The Google drive link is not public.

Oops. Fixed it, thank you.

1 Like

Any clue what’s wrong?

Yes, you need the configargparse python package. It allows mixing command line arguments, config files, and default config files so things can be a bit less messy.

I’ve also added python-opencv as a dependency to handle 16 bit images input/output.

1 Like

Had to install:
pip install ConfigArgParse
pip install opencv-python
pip install pyyaml
pip install piqa

Got stuck with
python denoise_image.py --input in/.tif --output out/.tif --model_path …/…/models/4/generator_734.pt --network UNet --cs 660 --ucs 470
Traceback (most recent call last):
File “denoise_image.py”, line 29, in
from _ftdi1 import NONE
ModuleNotFoundError: No module named ‘_ftdi1’

Temporarly removed from ftdi1 import NONE from your code just to try to get further, got

1 Like