While converting a film negative in Darktable I noticed a couple issues related to negative pixels values. I don’t think these are actual bugs, but maybe this will be helpful to anyone else who encounters the same thing…
As documented in the release notes, the input to negadoctor should not contain negative pixel values. A negative pixel value appears to cause negadoctor to output the pixel value 1.0. Normally this wouldn’t be noticeable if negadoctor is set up with reasonable settings, because pixels with values near 0 are being transformed to values near 1 anyway. But it does confuse the D max color picker, which sets the extreme value 6dB for D max when the negative pixels are present. This setting makes all the non-negative pixels dark so the negative pixels turned to 1.0 show up clearly in the output.
The other issue is with the default lanczos3 interpolation - it has a tendency to sometimes push pixel values close to 0 to negative values. Maybe some sort of ringing or overshoot? It seems like it’s a lot more likely to do this then the other interpolation methods. But it only happens at specific pixels in the image at a specific scale, so when you zoom in to investigate, the negative pixels change or may go away entirely.
I started with a reasonably well exposed b&w scan with the “none” pixel workflow:
At this point I probably should have noticed some pixels at the left side of the histogram and adjusted black level in exposure, but I had turned on monochrome (which comes after negadoctor) and so the histogram looked perfect:
Enable negadoctor and select the film base for D min:
Now use the color picker for D max. This is where it sees the negative pixels to D max and sets the D max to 6.00dB. The negative pixels show up bright here, because they are output as 1.0 regardless of the D max setting:
Zooming in, the pattern of negative pixels from lanczos3 changes:
Zooming in further, the negative pixels go away:
After adjusting the black level in exposure to get rid of the negative pixels, the D max picker now sets D max correctly: