Hi, this is my first post on the forum. I’d like to ask the RT developers if there is any interest in adding a feature to RT, to facilitate the task of DIY “scanning” of color film negatives using a digital camera.
The traditional methods described in the RawPedia “Negative” page, have some annoying drawbacks (inverted control sliders, need for manual tweaking to get the colors right, etc). After some tinkering with the RT source code, i found a simple solution that looks promising.
This method is different from the one used in Darktable’s “invert” and digiKam’s “film negative” modules, and seems to give better results (see below for details). My idea is to work directly with the raw values from the sensor, upstream of white balance, and to add a “Film Negative” tool panel in the Raw page, where the user can select the film type, or manually enter the necessary parameters for the formula.
So, what do you think? Should i go on and try to implement this? Would it be a desireable feature in RT? Or do you think it would just increase software bloat, for a functionality that is rarely used? I realize that diy film scanning is a very niche problem, so i don’t know if such a feature really belongs in RT.
Maybe it would be better to do that in an external “pre-processor” program, creating an intermediate file? That would be closer to the unix philosophy… in this case, see the end of the post for a ready-to-use gmic command line that already works pretty well.
In any case, i’d like to hear some opinions. Thanks
== Details ==
The approach i found is nothing new, actually i took it word by word from Wikipedia:
this article contains the following sentence:
[…] the transmission coefficient of the developed film is proportional to a power of the reciprocal of the brightness of the original exposure."
This is different from what happens when we apply the negative HaldCLUT, for example: in that case, we’re doing MAX - v
(where MAX
is the maximum value, and v
is the current value for a channel).
Instead, the article suggests we should be doing k*(1/v)^p
, which is much different.
In fact, lurking around in the forum i’ve also found an old discussion pointing out this exact issue:
Then, i had a look at the Darktable and digiKam source code (both have a film negative module), and to my surprise i discovered that both seem to use inversion (MAX - v
).
Darktable:
digiKam:
So, i modified the RT source code in RawImageSource::scaleColors
with a quick and dirty patch in order to compute the formula. For now, i read the exponents and coefficients from a text file, just to try things out (no GUI or integration with settings data).
Then i created a LibreOffice spreadsheet to calculate the parameters based on known values sampled from a test picture.
The most annoying thing to do with the traditional “inversion” methods, in my opinion, is getting white balance right: most of the time i pick a light gray spot for WB and all seems ok, but then i notice that another darker gray spot has become somewhat red. So i pick that one, and the previous brighter spot becomes blue-ish. So i adjust the RGB Curves and after some tweaking, i finally get perfectly balanced grays all across the range, BUT… i am now bound to that exact brightness level; if i make a slight change in exposure comp., brightness, contrast, tone curves or whatever, the histogram moves along the X axis in the RGB Curves, and the balance is gone. I can only use Lab controls from this point on.
The same applies when i process another negative: if i change the light source or exposure slightly, the RGB Curves created before need to be retouched.
So i decided to concentrate on this white balance problem; to make a cheap test, i took a picture of a color checker displayed on my PC monitor (i don’t have a real one; at least the screen is factory calibrated ) with a Kodak ColorPlus 200 film roll.
Then i digitized the developed film, using a Sony A7 and a speedlight as a light source (xenon).
In the attached spreadsheet you can find the channel values from the 6 gray patches in the bottom row of the checker. These were obtained by reading the channel values inside RawImageSource::scaleColors (so they are normalized 0…65535), and averaging an area of 32x32 pixels.
negativeCalc_curve.ods (25.5 KB)
The “p” and “k” values are the exponent and coefficient, respectively, for each channel. The B channel was used as the reference. These parameters are calculated based just on the first and last patch values, not taking into account intermediate vaues. In the graph on the right, you can see the results: the curves are not perfectly overlapped, but not too bad, either.
At this point i fed the parameters in the formula in RT (multiplying by a global factor to re-normalize the output in the rage 0…65535), and the test chart looked pretty good. If i change exposure comp. or white balance, or brigthness/contrast, now everything remains stable.
I had a couple of color patches that were definitely off, but to my surprise, those were easily fixed by using my camera DCP profile, and enabling the look table. I thought that those corrections would not work after mangling the channel values… anyway, this doesn’t matter: i could also have fixed those patches via Lab hue equalizer.
The final result was not bad. I’ve also tried digitizing the same checker negative using my smartphone (which produces raw DNG) and, with the same parameters, the output was good (using the DNG-embedded camera profile here, too).
Then i’ve tried some other negatives (also from previous rolls of the same type), and the results seem quite stable.
Here you can see two examples showing the difference between inverting the tonce curve and using the formula described above.
As you can see, the light gray patch has a blue cast, while the dark gray tends towards red. Impossible to white balance without touching the RGB curves.
This instead is using the formula with the parameters calculated in the spreadsheet, as it appears “out of the box”, with just white balance and exposure comp. The WB is much more constant across the entire gray range.
Here are other 2 examples from a different roll of the same type, processed using the same parameters calculated from the checker above. No tweaking, just WB, exposure and contrast.
As a bonus, below you can find a G’MIC command line that implements the same formula, with the same parameters from the spreadsheet. For example, try to download the CR2 raw file from this tutorial
http://www.frogymandias.org/imagery/camera-scanning-dcr.html
(download link on top of the page). Get a linear tiff from the raw file using dcraw:
dcraw -T -4 -r 1 1 1 1 -o 0 -h /tmp/60D_11930_negative.cr2
and finally, run this G’MIC pipeline:
gmic /tmp/60D_11930_negative.tiff \
-fill '[(R^-1.57969792927765)*149.305039862836,(G^-1.15851358827476)*3.91704903038636, B^-1 ]' \
-fill '[R*1.3,G/1.3,B/3.2]' \
-cut 0,{ic*4} \
-apply_gamma 2.2 \
-adjust_colors 0,30
The first “fill” command contains the formula. Here i used negative exponents instead of doing 1/n
, it’s the same.
The second “fill” command does white balance, those coefficients were just eyeballed.
The “cut” command limits the maximum value to something not too far from the median value of the picture. Then gamma and contrast to taste
Note that the same parameters calculated for the ColorPlus 200, also work fine with the Kodak Gold 200 used in the tutorial, and with a different camera used to perform the “scanning”.
That’s all. Hope this is useful to somebody
Sorry for the long post, and my terrible english
alberto