The Backlight

All of that was great, @PM490. You always find the most interesting references! (The pinned comment on the sodium light prism video contains some fun historical anecdotes.)

I only had one tiny note:

I would amend that with “Every pixel will have its current visible color.” By giving up the full spectrum you’d lose some ability to shift things around to try and combat dye fading or dye shift. But otherwise, yes, you’d have the most directly-specified representation of the current pixel color.

(Maybe a workaround for not having an XYZ whole-image sensor available would be to do something like confocal laser imaging where you capture the image a single pixel at a time, raster-scan style. Although, there may never have been another sentence on this forum that inflated a budget as quickly as that one.) :sweat_smile:

1 Like

Thanks for the kind words. Updated the posting with your suggestion.

The old RankCintel did raster-scan style with a CRT flying spot, I serviced one of those many decades back. Using lasers would be a nice update :slight_smile: , slightly out of my budget as you mentioned.

Agree that figure provides interesting conclusions. It would be great to see the comparison (if you get the time).

Ok, here’s some quick (but warning! lengthy) examination of the differences between the usual broadband camera filters and narrowband filters. We explicitly do only treat here the case of three independent color channels. Multi-spectral methods usually employ much more channels, utilizing them to get an estimate of the complete spectrum. We will not be concerned with this later use case.

As already pointed out for example by @PM490 (“XYZ sensor”), an ideal camera for photographic use would be one which mimics the filter curves of a human observer as best as possible. Technically, this is not really possible, mainly because the filters one can manufacture are limited in performance. The general approach taken here is to make the filter curves as close as possible, and correct the error with a (possibly scene-adapted) color matrix (ccm) which transforms the camera’s raw RGB values into XYZ values. This matrix is usually the result of an optimization procedure. So, in a sense, every camera sensor combined with the appropriate ccm is actually at least an approximation to @PM490’s ideal “XYZ sensor”.

Now, it’s been some time since I waded through the muddy waters of color science and there might be some error hidden in the following, but I invite you to follow along anyway. The question is: what gives me a lower color error when scanning an arbitrary film frame - a three-channel sensor with broad spectral bands, or a three-channel sensor with three narrow bands?

Since I do not have access to original dye filter curves, but I do have to the spectral distributions of classical color checkers, I recast the intended simulation to a slightly different problem: what performs better, a camera with broad color channels (specifically, I do use the IMX477, the HQ camera sensor, as a test bed) working under standard illumination (D65), or the same camera with the scene illuminated only by three narrow RGB-LEDs. Both situations should be equivalent.

As the test scene, I selected a standard color checker. If this color checker would be viewed by the ideal XYZ sensor, we would obtain the following image:

I now ran three different simulations on this virtual color checker:

  • a reference simulation establishing how good the IMX477 sensor is able to record the virtual color checker above when illuminated by standard D65 illumination.
  • a first simulation where the color checker is only illuminated by a set of three narrow-band LEDs, with the center frequencies taken from this paper.
  • a second simulation where the three LED center frequencies have been tuned manually to improve the residual color error.

All simulations were done the same way: the initial raw camera values were first whitebalanced, so that any neutral patch in the scene (patches 18 to 23 above) has equal amplitudes. Than, an optimized ccm was calculated aiming at mapping the raw camera values to the correct XYZ values the patch colors should have. This mapping, being constrained to matrix, is the limiting factor in the whole processing chain. In any case, the XYZ colors obtained are mapped into sRGB for display purposes and the color error (\Delta E_{ab}) is calculated for the full set of patches.

Before continuing to the final result, let’s have a closer look at the sensitivity curves in question.

The curves labeled “red”,“green” and “blue” are the filter curves of the IMX477 sensor with the standard IR-blockfilter of the HQ camera applied. The “3 LEDs Swiss” is the first set of the narrow band LED configuration I have tested. The center frequencies are at 447 nm, 544 nm and 672 nm and were taken directly out of the paper I referenced above. Since I do not have data on the width of a single band, I arbitrarily have chosen this value to be 20 nm for all. Note that while the green LED channel is close to the maximum of the green IMX477 channel, the blue LED channel is shifted towards the UV range in comparison to the IMX477. The shift of the red LED channel is even larger - it ends up in touching the near-IR region. As a result, note further that nearly the whole frequency range of the red channel of the IMX477 is not represented by the “3 LEDs Swiss” setup. The yellow curve in the above diagram (“3 LEDs aligned”) is finally a setup I came up with where I manually tuned the center frequencies of the narrow bands to improve the overall color error.

Ok. Now it’s time to have a look at the results. In the following image, the center portion of each patch displays what an ideal observer/camera should see - these are our reference colors. The left half of each patch displays what the IMX477 sensor with its broadband filter curves was able to make out of the data. On the bottom-right of each patch, the reults of the “3 LEDs Swiss” configuration is displayed, and finally, top-right the results of a manually tuned “3 LEDs aligned” setup can be found:

The most interesting numbers on the display are the “\Delta E mean” values. Anything above 2.0 is an error which is deemed to be noticeable by a human observer. So the broadband filters of the IMX477 do perform quite well, with an average error of 1.1. The maximum error occurs at patch 14 (“red”, with a value of 2.6. Overall, this is quite a good performance.

Looking now at the “3 LEDs Swiss” setup, we discover what I already hinted at in this thread: narrow-band filters are no good if you are working with only three channels. Indeed, the mean error ramps up to 3.8! In terms of error measures, the worst performing patch is patch 12 (“blue”), but visually, patch 09 “purple” has also some punch.

I tried to manually shift a lit bit the center frequencies of the “3 LEDs Swiss” setup in order to improve performance. Especially, I shifted the red channel more towards green, in order to reduce the gap in coverage visible in the above response curve diagrams. This resulted indeed in a reduction of the mean color error from 3.8 down to 2.1. Interestingly, the worst patch turned now out to be patch 17 “cyan” (which is, by the way, out of the color gamut sRGB can display - see plots below).

Wrapping up this quick and dirty expedition into color science, here is a plot displaying the colors the IMX477 with its broadband filters came up with in xy-space. The real values are always indicated by black/white circles nearby the color points, the sRGB display space by the red triangle:

This is in fact, as already indicated by the low mean color error above, an excellent performance.

Let’s look at the “3 LEDs Swiss” case:

Clearly, the computed colors do not match the actual colors that well. Especially the colors in the blue and red region suffer.

As mentioned above, I tried to check whether one can do better by adapting the LED’s center frequencies to the material to be scanned. Here’s result of such a manual optimization:

It performs better, especially in the orange-red part. But still, the match of colors is noticeably better when using the broadband filters.

Finalizing this post: again, the results above were obtained by an application of old software I haven’t touched for more than a year. I can not rule out some stupid mistakes. Leaving that aside, I think the above simulations underscore my claim that generally, you are better off by using a whitelight source and classical, broadly tuned camera filters. Here are my main points against a narrowband 3 LED setup:

  • with broadband filters, there is a chance of wavelengths falling into ranges were a narrowband system just has dead zones.
  • the placement of the centers of narrowband filters influences the achieveable color quality noticeably. The optimal placement probably depends also heavily on the material scanned. If so, the LEDs will need to be adapted/changed once another film stock is scanned. That is impractical in a practical application.

Clearly, if you have anyway a multi-spectral camera with lots of channels (we’ve learned that one should at least consider 8 channels), the impact of the two points noted above gets weaker.


Thank you @cpixip for taking your valuable time to perform this test/simulation. It is a striking visual summary of thread.

For LED3 Swiss, while I expected the errors on mixed patches, the magnitude of error on the primary ones was significantly more than I would have thought. The cyanish color cast of the LED3 Swiss on the grays is also quite noticeable.

Great stuff, thanks again.

Why are we constrained to a matrix? Every modern video editing app uses look-up tables (often 17³, 33³, or 65³ points with tetrahedral interpolation) to convert incoming Log (or otherwise) color space footage.

Of course the weaker, matrix-only tools demonstrated in this shoot-out will favor the entry that is most linearly similar to the target.

It’s an interesting analysis that looks like it took some effort to run the numbers through, but I think the only conclusion we can draw is that there was a good reason the industry moved on to more powerful correction methods than plain matrix transforms.

… probably because it is not so necessary? Most cameras work fine within this approach. Most .dng-files feature only two matrices for your raw development software, for the extreme ends of the color temperature range. The real matrix is interpolated based on the real color temperature of the shot. Ideally, the matrix would be scene-specific, as it was in the case in the simulations reported above.

In fact, I was a little bit imprecise in my remark above. The limited variation of possible filter responses curves might be more limiting factor.

With respect to LUTs, I have seen quite some nonsense floating around. And as long as people “develop” log formats by adjusting gain, lift and gamma, the ccm matrix can stay, I would say. :innocent:

I actually started with narrowband LEDs after reading the paper @friolator loves so much, where this approach was advocated. Only to discover that the colors were not great and differences in the film material got accentuated. All issues reduced since I switched to whitelight ilumination and capturing raw… And no, the main reason narrowband fails is most probably the limited range which can be sampled by only three narrowband channels. As I already remarked, sampling with 10 or so closely spaced channels is superior to a three channel broadband approach. The overall coverage of the full spectrum seems to be the important point.

Narrowband cameras aren’t “most cameras”. These tools exist specifically for this type of situation.

The following is all real-world data:

Last September I meticulously scanned a 35mm Ektachrome Wolf Faust calibration target (manufactured in 2016) using the same light, lens, and exposure setup that I plan to use with real film (which, incidentally, my backlog is ~50% Ektachrome so I won’t have to worry as much about metameric failure on that half).

This is from a monochrome Sony IMX429 sensor (the Lucid Triton 2.8 MP, model TRI028S-MC).

I just used an ASEQ Instruments LR1 spectrometer to measure the light spectra from my narrowband integration sphere. Placing the spectrometer probe right at the exit pupil of the sphere and lighting each channel in turn, I obtained the following. (Y-axis is arbitrary):

The spectrometer’s software can try to fit a gaussian to a peak. The numbers in parenthesis in the legend are the estimated width of each peak. The measured peaks seem to be pulled off to the side a little by the edge “tilt” of the frequency spike:

Color Part no. stated measured
White Yuji D50 High CRI LED D50
IR Luminus_SST-10-IRD-B90H-S940 940 nm 915.3 nm
Red Luminus SST-10-DR-B90-H660 660 nm 659.5 nm
Green Cree XPCGRN-L1-0000-00702 525 nm 528.2 nm
Blue Luminus SST-10-B-B90-P450 450 nm 452.4 nm

Using the latest (3.2.0) version of the free Argyll CMS tools, you can grab the averaged RGB triples from a 16-bit TIFF of an IT8 target and pair it with its reference XYZ colorimetric data using the scanin app, which outputs a .ti3 file.

With the boiled-down .ti3 file (288 pairs of XYZ and RGB triples) you can generate all sorts of ICC color profiles using the colprof tool.

Finally, they were so kind to include profcheck which runs exactly this Delta E analysis against the original image using the newly generated ICC profile.

So, using a single TIFF I was able to generate three different ICC profiles (using the “high” quality mode out of { low, medium, high, ultra }) containing:

  1. 3x3 matrix-only.
  2. 3x3 matrix + “shaper” (which is a 1D gamma LUT for each channel)
  3. XYZ cLUT

I believe the first matrix-only profile corresponds most closely of the three to your “3 LEDs Swiss” simulation above.

Running profcheck gave the following Delta E results against the original TIFF:

Max error Avg error RMS
Matrix-only (high) 27.940950 5.451902 7.405225
Matrix+shaper (high) 26.187890 4.564698 6.461728
XYZ cLUT (high) 3.879810 0.312821 0.604227
XYZ cLUT (ultra) 2.921067 0.271423 0.517082

The middle column is the interesting one. The XYZ cLUT profile gives better than a full order of magnitude improved error over a profile with just a matrix!

(You can squeeze a little more out by using the “ultra” quality preset, but over-fitting is going to happen and it takes 30+ minutes to generate. I included that row only anecdotally.)

On top of the summary, profcheck can give you the full list of color patches with the Delta E for each ordered from bad-to-good. Out of 288 patches, only a single red square (L17) from the cLUT profile was >3.0 and only another six patches had an error between 2.0 and 3.0.

Here, the matrix-only result is shown in wireframe-3D. The filled volume is sRGB. A matrix only linearly stretches the color space:

With a LUT you can arbitrarily re-shape it:

Here is the raw data with the list of command-line steps used to generate the profiles if you’d like to experiment with it: TIFF and reference data. Just drop the contents in Argyll’s “bin” folder and follow the instructions in the “argyll steps” text file.

Of course these numbers aren’t directly comparable to your simulation. I believe the under-the-hood illuminant is D50, there is a bunch of grain noise in the real slide, the sensor response is different, the sensor is monochrome, my LEDs are wider than 20nm and peak at different wavelengths, the IT8 target was already ~8 years old before I scanned it so it may have already begun to fade slightly, etc. It’s apples and oranges for sure.

I also can’t make a direct comparison to broadband cameras with this monochrome sensor without re-scanning the IT8 target while manually swapping in the separate R, G, and B Wratten color reproduction filters (as seen in my profile picture) between exposures… which would be something like 6 hours of effort to capture the many sections of the 35mm calibration slide using only my 8mm viewport. :grimacing:

But with any luck this demonstration buries the notion that you don’t need the LUT. It’s the LUT that makes narrowband scanning reasonable. It’s such a powerful and accessible technique that it should be used with broadband film scanning, too. It should never not be used. :rofl:


@npiegdon - what an amazing work! (I actually also own a few Wolfgang Faust calibration targets and at one point was planning to go the same route as you did. Never found the impetus to approach it…)

The three ICC profiles you derived from your measurements:

reflect a a transition from simple to more complex color transformations. And yes, my tests above were done with a 3x3 matrix only. (And: in bashing LUTs in my post above, I was referring to LUTs created manually, according to taste - not LUTs coming out of a calibration procedure.)

Of course, with a more complex transformation, the optimization becomes more challenging, and with bad measurements, optimization can become numerically unstable. So things can easily screw up. The results of your color error table indicate that your measurements were spot on - with all the experimental challenges you noted… wow.

I did not go along that path because of three things. First, it was experimentally challenging - you mentioned how long it took you to take the calibration images. Second, for my favorite film stock, Kodachrome, I could not find a suitable target. Thirdly, I have quite a lot of other film stock to scan (various Agfa stock, Fuij, etc.) and it is unclear, how good a calibration obtained with one film stock would work on another type of film.

Coming back to the current question - is 3 channel narrowband scanning better or worse than scanning with three broadband filters? It was claimed in the Distor paper that selecting the narrowbands carefully, you can increase color separation in case of severly faded film stock. I think that is without dispute. You certainly can improve the signal quality with respect to color separation that way. But for this approach to work perfectly, it requires you to take care of the specific film stock you are scanning.

I think you did not select the set of narrowband LEDs in such a way that it optimizes signal separation in your raw data. In any case, the influence of an optimal set is probably rather minor, considering the usually broad spectral densities of film layers (cmp. for example bottom-left part of fig. 2 of the paper cited above).

Furthermore, by utilizing a 3D LUT as primary transformation tool, you can increase if necessary color separation even locally, in specfic areas of your color space - a much easier approach than optimizing LED sets (there will be a larger quantization error in case of LUT-corrected data, but that should not be noticable).

I think the question of narrowband vs. broadband is still unresolved. It probably depends heavily on the context you are asking this question. Certainly, for a specific film stock, you can potentially calibrate quite a good LUT out of a set of carefully taken calibration shots. But calibration is tedious work and can fail for a lot of reasons (mostly: small errors when taking the calibration images). On the other hand, we have the broadband approach which uses the generic filters/transformations the camera manufacturer came up with (or: in my case, by utilizing the HQ camera sensor, the one I came up with :innocent:). While this will always be inferior to a film-specific calibrated approach, it might just work ok for many of the other film stocks one encounters.

For my use case, namely digitizing a fairly diverse selection of different film materials, I’ll stick with broadband and a single raw shot per image - simply for convenience.


If only they made the test targets in 8mm “slides” instead of 35mm, it would take a single button click in my software! :sweat_smile:

I did just notice the “Extras” section near the bottom of the coloraid targets page where he mentions custom/variable size targets. I wonder if Wolf could make the same “K3” chart from the list but print the chart on the slide much smaller? It would be more susceptible to film grain noise with the color patches being so much smaller, but it would be so much more convenient!

This is definitely a barrier, especially given how different Kodachrome is just from simple observation (dye density, IR response, vibrancy, etc.) when compared to most other film stocks. I’m going to see how far I can get with my existing calibration but it’s going to suffer from metamerism.

We are lucky to have good, free tools. While there is so much more going on under the hood (case 1 took less than one second to generate; case 3 took longer than 5 minutes of computation), from my own perspective it only took a single character change on the command-line to employ a dramatically more complex calibration process. It doesn’t get much better than that!

My LED selection was motivated by a combination of Figure 7 from the Diastor paper (and the text on the following page: “… being positioned at around 460, 520 and 680 nm”) combined with what I was able to find readily, commercially available from the various parts websites at a reasonable cost.

I had purchased those parts two years before the “Digital Unfading” paper was published, unfortunately. Now that I’m maybe tossing around the idea of hyper-spectral scanning, I might revisit my part selection.

Ah ha, this might be where we’ve been differing. I am building my scanner exclusively for 45-year-old Kodachrome and 45-year-old Ektachrome, some of which is pretty badly faded. My goal has been to optimize for exactly those cases so having to maintain a maximum of two calibrations has been more manageable and seems to have led me down slightly different paths.

1 Like

@cpixip @npiegdon thanks for sharing this discussion. My math and color space understanding are quite shallow compared to the depth that you both command.

Without a full and deep understanding of the above, I have a question for both.
I follow -most- of the above but not sure how the quantization at the sensor (12 bit on the HQ sensor) is considered, particularly in regard to determining the minimum errors.

A float single value would provide the location of the target(s) in the color space. In an ideal world, the sensor would provide continuous float values and the above is well understood.
In the real world, the output of the sensor, due to its quantization at say 12 or 16 bit, is not continuous.

So the continuous surface represented in the color spaces would be more like a fractal mosaic (forgive my lack of math terminology) than a continuous one.

Wouldn’t that affect and be part of the minimum error even with a lookup table?
How would it compare for the discrete possible values against the surface/volume of the color space? Would the delta error be greater at any discrete value between the targets than at the discrete values of the targets?

Maybe it is consider for the errors at the targets, since it was ran against the original TIFF.
It considered in the wireframe representation?

Well, that is an interesting question. Upfront, my simulations (most) always use floating point - so the the effect of quantization is not considered. In contrast, most cameras and image processing pipelines use some kind of integer-based calculations. A notable exception is DaVinci, with it’s internal 32-bit floating pipeline.

In fact, I have a long personal history with this subject. In the late '80 (DOS area) I developed my own image format able to store data as floating point numbers (that was a bit before OpenEXR and the like came to life); later, in the 90’s, I lectured university student on the numerical problems even 64bit or 80bit long floats still can cause (this course was called “Physics by Computer Simulation”) and 10 years later I implement an image processing pipeline in Matlab where you could specify the bit-depth of individual data paths between processing units (this implementation was used to optimize FPGA-code which calculated a depth map from stereo images - you want to spend as less hardware resources as possible in an FPGA).

From my personal experience over these years, I can say that sometimes you can get by with just 3-bit data depth. But generally: 8 bit is not enough for most purposes. Digitizing color-reversal film, you’d want to work with at least 12-13bit; so 14 bit (which modern cameras can supply) is usually quite sufficient. Both of these bit depths (12bit and 14bit) have normally enough head room for quite some fancy post-processing. In my cine scanner project, paths between different processing stages are typically 16bit or 32bit floats.

All of the above is assuming linear coding. If you employ log-encoding, things change dramatically. Here, even 8 bit encoding can give you something ok to work with. You loose some fidelity, but normally only in areas where the human visual does not care anyway about it.

The optization routines @npiegdon praised above are all working in the floating point domain. For a specific reason: it is actually quite challenging to optimize things in an integer space. Besides, such optimizations would heavily depend on the bit widths of the input and output channels as well as on the fractional integer format chosen to store and use the matrix elements. So I guess analyzing quantization effects in this image processing pipeline not something anyone in their right mind would want to try… (But: maybe someone has - I am not aware of.)

Besides, the color error used above is only a hint to when deviations from the perfect imaging might be noticably by a human observer - frankly, I sometimes encountered deviations quite noticable for me, but featuring a low color error and vice versa. There are other color error measures available; the entry " CIE76" on the wikipedia page was used by my optimization routine to calculate the ccms. There are better ones (scroll down the wiki-page) but I was too lazy to implement these (so far).

Specific to the HQ camera - for the jpg accompanying the raw capture, the ccm is encoded as floating point in the tuning files. Whether the underlying libcamera actually works with floating points or recasts this as a convienently (matching the hardware) chosen fraction integer is unknown to me. Same goes for the computations ongoing in RawTherapee or DaVinci.

Summarizing, I would not be too concerned about quantization effects. There is a high probability that this is irrelevant to our discussion.

In fact, the optimizations @npiegdon detailed above are prone to little mistakes when capturing the reference images - the more complicated the transformation is, the more likely the optimization routines are to fall into little traps caused for example by uneven illuminations of the test target or unnoticed lens flares or false measurements of color temperature, just to name a few.

While we arrive somewhat at a general discussion - LUTs are traps for precision by their very own design. For example, I would never use a LUT in DaVinci to transform from one color space into another one. The reason: a color space transformation in DaVinici is using their 32bit floating point calculation engine with the analytically defined transfer functions (usually a matrix and a gamma-curve). A LUT on the other hand is constrained to a rather low count of sample points in color space. While the LUT is correct at these sparse sample points, all other color samples are interpolated from values of the nearest sample points. Given, the error introduced by this process is usually not noticable by human observers, but its there. A color space transformation (CST in DaVinci speak) is way more precise.

Are these things relevant anyway? Probably not. Two points with this respect. The first one I mentioned already in this thread somewhere. Imagine you have calibrated your scanner perfectly for Kodachrome. You get a scan like this (well, this example is certainly not from a calibrated sensor, but it will do :wink:)

Now two seconds later in this film, you get instead this here (with the whole processing pipeline untouched, cmp the color and brightness of the sprocket area):

The footage was shot within less than an hour apart. What happened here? The most probable explanation is the following: remember that Super-8 was shot on 15m rolls. Both scans probably come from two different rolls and the second one was just a little bit mistreated in the lab. I have noticed this issue occuring also in other longer films. So any calibration done with a reference film stock might not help you too much with the actual film stock you are scanning. And while Kodachrome does not fade too much over time - Ektachrome film stock introduces certainly an additional temporal component into this problem.

Now, for an archival digital copy of this film, the greenish color cast is actually the thing you want to store in your archive. But of course, in a presentation copy you might opt to adapt the greenish colors of the second scene during color grading to the rest of the footage. But once you got ahead with color grading, you are leaving the realm of a perfect scan of the film footage and entering the muddy area of personal taste. Will you grade like Paul Simon so perfectly summarized in one of his songs (“Kodachrome - they give us those nice bright colors”) to intense Kodachrome colors? Or will you rather grade to come closer to more natural looking colors for a given scene?

Finally, the second point: remember that Super-8 color reversal film was optimized for Tungsten illumination, using an appropriate in-camera filter when shooting daylight scenes. That is: only two color temperatures were available in the old days. Of course, mother nature does not care too much about this. So generally, you had an mismatch between the actual color temperature of the scene and one of two color temperature you decided to work with while shooting. When flourescent illumination was present, this resulted in a nice green color cast. Again, you could opt to ignore it, or correct it in post. Same procedure: if you opt to do color corrections in post, you have a manual, taste-driven process. Not exact color science.


Thank you @cpixip, appreciate your perspective and explanation.

I am definitely not the one to try :slight_smile:

Perhaps I can distill my question a bit. My concern is the scope of making the claim of the calculated error via matrix or via @npiegdon calibration.

To simplify greatly, the processing pipeline of the HQ would be:

  • Quantization to a 12 bit integer.
  • Conversion of the 12 bit integer to the float. Library color space conversion. I would call it discrete-float, since it would not have an infinite combination of floating numbers, only those corresponding to integer-float x library conversion (scientific file).
  • Packaging as DNG.
  • Davinci imports the DNG with the discrete-float representation.

For my limited understanding, the @cpixip matrix makes the determination of what the error is at the patches. Would some color not represented by the patches have a larger error? I think that may be the case, but again it may also not be relevant or visually significant.

The part I have some concerns in regards to quantization the conclusions of @npiegdon

In the described pipeline, is that improve order of magnitude error only on the sampled patches or in the entire color space? In the case of the later the discrete-float source points for the patches would certainly have the reported errors.
But I am not so sure that the order of magnitude claim is applicable to the errors of the colors in between those patches?

Again, that may not be relevant or visually significant.

After all, in both cases, it will all be adjusted by the Davinci Resolve corrections to make the best image suitable to the scene. Only trying to establish the scope of the improvement claim.

Thanks again for sharing your perspective and knowledge in the subject, which I certainly lack.

Ok… - this is going to get quite technical…

First, in reality, not even every patch used in a calibration has the same error. See my color chart above, where certain patches have larger errors than others. The same is true for the @npiegdon results. Furthermore, there is no guarantee at all on the error of patches of color not contained in the sample set. Counterintuatively, those patches not contained in the sample set could have much larger error in @npiegdon’s “XYZ clut (ultra) fit” (average error of the sample set: 0.3) than on his “Matrix-only (high)” fit (color error: 5.4). Let me try to explain…

Every optimization we are concerned with here is only looking at the selected colors. That have been 288 color patches in the case of @npiegdon and only 24 in my case. Now, with any optimization, overfitting can occur: that is, the given sample set is matched perfectly, but intermediate data points (colors in our case) differ widely from their expected value (by the way - a classical issue in AI as well). That is why all optimizations usually employ some kind of regularization. That can be one or several smoothness constraints (often introduced by Lagrange Multipliers) or the use of simpler transfer models vs more complex ones. For example, if you use a matrix, all values will be mapped necessarily by linear functions only (keeping the variations of color values between the color patches used for optimization in bound) whereas a general 3D LUT might be equivalent to higher order polynomials, opening the door to larger deviations of colors not contained in the set. (A practical example everyone can do is using Excel to visualize the problem: generate a table with a few (x,y) data points which are placed randomly in a more or less straight line, draw them in a diagram and than select first the linear trendline option, than a polynomial trendline ranging from 2 to 4 degrees)

To formulate the above to the point: A low error of a fit can indicate overfitting, rendering the use of the transform for generic colors not contained in the sample set substandard. One way to check this is actually quite simple: for the optimization, only a subset of the available color patches are used. Another subset is used in a further processing step to check if the quality measurement is ok with colors not used in the optimization as well (this is by the way, also a standard trick in AI).

Good optimization is an art. Keeping with our example (color mapping): people who primarily are taking portraits might put more emphasis on skin tones, whereas landscape photographers might be more concerned with green tones. So you would weight the different areas of a color space differently, depending on your main subject area. Camera manufacturers actually do this kind of stuff to create a personal look for their line of cameras. Some open-source software available for computing color transforms have this kind of feature as well. But, here already Pandora’s box is slightly opening, giving to much room for personal preferences…

As Jack Hogan puts this nicely on his blog, “When first learning to develop captured raw data into a pleasing rendered image, the typical photographer soon discovers that the easiest way to kill a perfectly good picture is to mess with sliders that directly affect color. Such sliders have names like r, g, b,*a, *b, hue, saturation, etc.”. Besides that very true quote, I can recommend his " Strolls with my Dog" blog warmly if you ever want to learn more about how cameras work.

So yes: all this does not matter much if you are doing color grading after scanning. Which you probably will need in order to create something viewable from old Super-8 stock. That was one of my points in the post above.

One additional point here: starting from raw image data to something that you will show the consumer of your products, you are anyway at the mercy of many black boxes along your processing path. Here’s a rather old paper (the DaVinic version analyzed is 14.2)

where different raw converters are compared on how they are able to work with raw images of Canon 5D Mark3 cameras. If you read this paper, you will be surprised how much the outcome of different converters differ from each other. And if you compare the graphs of the paper with the CIE-diagram I posted above for the HQ camera (Label: “Broadband”), you will notice that the HQ camera is not too bad with respect to color reproduction.


A good thing to remember is that there isn’t anything magical about floating point numbers. Unless you’re doing your calculations using a special “BigNumber” library or maybe keeping things as rational pairs, there is no such thing as an “infinite combination of floating numbers”.

For a regular 32-bit “float”, you get 23 bits of mantissa. For a “double” you get 52 bits of mantissa. And they will suffer from their own flavor of quantization errors. The classic example is the number “0.1”. Even with a 64-bit double, you can’t represent 0.1 exactly. If you try, you’ll end up with 0.1000000000000000056 instead. That is effectively quantization error. They’re already discrete. There are even functions in C where you can ask for the floating point number with the next ULP, which means you can count them discretely. This page is a good place to start to learn more of these horrors.

It is always safe to map 32-bit integers to 64-bit doubles. This is lossless because “double” contains enough bits and can represent all 4.2B integer values exactly. But when you start to actually do something with those numbers afterward, you’ll incur the same sorts of quantization errors as above.

Integer, floating-point, and fixed-point arithmetic are just tools. Each have their own strengths and weaknesses. But there isn’t any free lunch; they are ultimately limited by the number of bits used to represent the number.

Yep, like @cpixip said, you have to be careful about overfitting. This is why the “ultra” result in my test is probably worse than just the “high” LUT despite showing better average Delta E across the 288 test patches.

That said, you can limit some of the impact and higher-order polynomial problem if the samples in your calibration chart cover a representative sample of the full color space. There is obviously a limit to how many of these little squares you can fit in an image but 288 patches is a better place to start than 24. The more samples you have (assuming the colors have been picked well), the better coverage you’ll get and the less “weird” your result is going to end up for any in-gamut colors that were farthest from any test patch.

To answer your original question directly: yes, quantization errors (whether integer or floating point) will introduce additional error in the final result. But–unless we’re talking about some pathological case where you’re dealing with 3-bit color or something–it will always be completely overwhelmed by just about any other source of noise anywhere in your process. So it’s probably not anything to worry about.

The danger with quantization errors comes in when you have to “round-trip” things over and over. The small errors begin to compound and you have to start reading papers and books about numerical stability. Here is an interesting blog post about designing algorithms to be more stable through repeated passes. Luckily, in our film scanning situation, we’re insulated from most of these problems.