Linear Gamma Experiment (long, with screenshots)

The “Image viewer for linear gamma images” topic got me to thinking about the thing in color management I still have trouble with, gamma. So, I took rawproc 0.6.2, @elle’s profiles, and my development test image and set out to 1) see if rawproc made a legitimate linear gamma viewer, and 2) try to wrap my head around what the TRC curves in the profiles really did.

So, two running instances of rawproc, configured thusly:

input.cms=1 - gotta have CMS turned on to do this
cms.profilepath= /home/glenn/ImageStuff/ColorspaceTest/elles_icc_profiles/profiles - where all the profiles reside
display.cms.displayprofile=W2242_1_2017-09-15_16-16_2.2_F-S_XYZLUT+MTX.icc - the thing DisplayCal spit out for my calibrated display, sRGB gamma

Note the display profile has gamma=2.2 TRCs.

I opened the test raw with the following parameters:

input.raw.libraw.colorspace=raw
input.raw.libraw.gamma=linear
input.raw.libraw.cameraprofile=Nikon_D7000_Sunlight.icc

colorspace and gamma do the same thing as dcraw -o 0 -g 1.0. cameraprofile will, when the two previous parameters are raw/linear, find the specified profile and assign it to the image. Nikon_D7000_Sunlight.icc is my calibrated camera profile, made with @elle’s instructions. Oh, its TRCs are linear. Here are the two rawprocs at this point:

Bit of explanation, what you’re looking at: The dock on the left has three panes: 1) Commands, 2) Histogram, and 3) Parameters. In these screenshots, Commands actually has tools in it past the file open, but the checkbox next to the filename displays the result of the input described above. The histogram shows most of the data below 56 on the 0-255 scale (the internal image is floating point, 0.0-1.0), and there are no parameters at this point. Right-clicking the filename in either rawproc allows opening an Information dialog that, among other things, confirms the assigned profile. One more thing to note, the display is produced with the 2.2 TRC, so you’re not really looking at linear gamma. I don’t have this screenshot, but I temporarily replace the display profile with @elle’s linear sRGB profile, and it was dark. Point is, the internal image is linear. Oh and maybe another point would be that I had room to expose to the right…

Next thing to add is a working colorspace:

Now, the Commands pane has the colorspace tool checked for display, both rawprocs. And, the display image hasn’t changed, but the histograms are now different. That’s because I used a linear gamma rec2020 profile to convert the right-hand rawproc internal image, and the gamma 1.8 profile to convert the left hand rawproc internal image. You can see all that in the Parameters panes.

Now, I’ll add a “contrast-stretch” scaling to fill the available tone space. This is the ‘blackwhitepoint’ tool, and the sliders are positioned at roughly the extents of the internal image data (note the histogram shows the result of the operation):

This is where the image becomes usable, but the difference to me is a bit un-intuitive. To my thinking, it’s almost as if the histograms belong to the other rawprocs’ display images. But, the shadow tones are less “crushed” in the linear gamma right-hand-side rawproc, which kinda makes sense. I don’t have a linear gamma calibrated display profile, so I temporarily substituted it with sRGB-elle-V4-g10.icc, and the linear gamma display images confirm this.

I think doing linear gamma editing at this point would, with the linear gamma right-hand-side rawproc, involve inserting the desired tools after the colorspace tool but before the blackwhitepoint tool. I tried a curve tool, but with the data at the bottom of the histogram, I didn’t have much curve to work with.

So @elle, I think rawproc would be a viable linear gamma viewer, but you’d have to work at the configuration. And I think, within the capabilities of its limited toolset, it can do linear gamma editing. I still need to figure out the histograms vice the display images…

One change I’ll probably make to the histogram tool is a choice box to select either 1) the displayed tool’s internal image, 2) the selected tool’s internal image, or 3) the displayed image for the histogram. Another change will be a parameter to enable/disable LCMS optimization for the display transform, per the other thread.

Anyway, food for thought…

3 Likes

Hi Glenn,

In an ICC profile color-managed workflow, the CMM (color management module, usually LCMS for free/libre software) takes care of converting the image from the image’s assigned/embedded ICC profile to the monitor’s assigned ICC profile.

So there is no reason at all to have a linear gamma monitor profile for displaying linear gamma images. In fact there are very good reasons to not ever make linear gamma monitor profiles, as this requires sacrificing bit depth and smooth transitions for the sake of calibrating the monitor’s more or less perceptually uniform TRC to be linear via the video card LUTS.

But if LCMS is the CMM, then as you’ve already noted, for displaying linear gamma images it’s important to give the user the option to disable the optimizations. Or depending on the particular use case and software, it might be easier to just completely disable the optimizations in the code base, with no options provided. Those LCMS optimizations do assume perceptually uniform image encoding.

As aside, this Krita documentation does a super nice job of explaining the difference between editing in linear gamma color spaces and editing in perceptually uniform color spaces:

Results of autostretching range from “only a little different” to “hugely different” when done using linear RGB vs perceptually uniform RGB. If you have an unstretched png for the train image, I can put up a screenshot showing the difference.

Sorry for the daft question, what are “the optimizations”?

In LCMS API documentation under “Flags” for ICC profile transforms are several flags related to speeding up ICC profile transforms, in other words optimizing the tranform for speed at the expense of accuracy:

  • cmsFLAGS_NOOPTIMIZE 0x0100 // Inhibit optimizations

  • cmsFLAGS_HIGHRESPRECALC 0x0400 // Use more memory to give better // accurancy. Use on linear XYZ

  • cmsFLAGS_LOWRESPRECALC 0x0800 // Use less memory to minimize resouces

In tificc, these are the equivalent options:

-c<0,1,2,3> - Precalculates transform (0=Off, 1=Normal, 2=Hi-res, 3=LoRes)

“-c 0” corresponds to “cmsFLAGS_NOOPTIMIZE”.

More like a compromise than an optimization…

Yes, it was a “what if” exercise, to attempt to “see” the working profile image on the screen. Didn’t look good, didn’t tell me too much more than I already knew…

I’m still struggling a bit with the utility of linear gamma editing. Intuitively it makes sense, work on the pixels before you scale the image out of its original linear range, but then the tools need to be adjusted to work that limited range. With the curve tool, I had to put a control point constraint at 56 on the 0-255 scale, and do all the curving between 0 and 56. Now, this is an underexposed image in ETTR terms, so shooting ETTR may be a prerequisite to linear gamma editing, maybe?

Bear-of-little-brain thinking aloud here… :smiley:

Well, coding is full of optimzations that sacrifice a little bit of this for a little bit of that, and very often the “this” and “that” are accuracy vs speed. Marti gave a very nice summary here: Re: [Lcms-user] What does cmsFLAGS_NOOPTIMIZE actually do? | Little cms color engine though of course I disagree with his suggestion that “For users, I would recommend to NEVER use linear XYZ spaces. They are good for nothing, nor for storage, nor for image processing.”

By “linear XYZ spaces” I’m assuming Marti is referring to linear RGB matrix color spaces, which by definition use XYZ as the Profile Connection Space. He specifically mentions 16-bit precision, but of course the discussion also applies to 32-bit precision.

The LCMS optimizations work just fine with 8-bit images when the source and destination ICC profiles are for perceptually uniform color spaces, and of course as Marti points out, nobody should ever use a linear gamma color space for 8-bit images as there are too few tonal steps devoted to the shadows.

I’m a little puzzled by Marti’s statement that "Placing a NOOPTIMIZE in all transforms would prevent problems, but at big performance penalty . . . " I just don’t see the performance penalty in practice, not when the conversions are between matrix profiles. Maybe on older hardware? Maybe in a situation where many, many conversions are being done over and over again, in situations where the in-memory “device link” he mentions needs to be constantly recalculated? Maybe if the user has chosen a LUT monitor profile instead of a matrix monitor profile?

I do see a slowdown when soft proofing to a printer profile is being done. But this involves a double ICC profile conversion, to a LUT printer profile plus the conversion from the LUT printer profile to the monitor profile.

I’m only speaking from experience using Linux, so maybe other operating systems benefit more from the LCMS optimizations?

Manipulating Curves for the shadow areas of linear gamma images is not easy precisely for reasons you give, the shadows are very far to the left of the histogram, and the last stop, the highlights, takes up half of the histogram. This is more a UI problem than anything else. The User Interface needs to provide sufficient number of increments to allow proper setting of Curve points in the shadows, and also it would be nice to be able to zoom in closely to the portion of the histogram currently being worked on - I think PixInsight has this feature. The GIMP devs are working on this problem, along with the problem of somehow showing out of display range values on the histogram UI - I think these are not very easy UI problems to solve.

On the other hand, manipulating the highlights using Curves on linear gamma images is a dream - lots of room in the User Interface for setting the highlight points!

Just about all of my images taken outdoors in bright daylight are underexposed in terms of “neutral gray”, but exposed correctly given my goal of avoiding clipped highlights. The only other alternative is to take ev-bracketed exposures and blend the resulting frames, which is the preferred approach but ideally requires a tripod and a subject that obligingly stands perfectly still.

All of which is a round-about way to say “ETTR” has nothing much to do with editing in linear gamma RGB color spaces, separate topics altogether, though of course it’s nice to maximize the shadow detail when possible, by using ETTR.

With raw files shot with my old Canon 400D (which unlike my Sony A7 did not lossy compress shadows down to a measly 9 bits of information) I never have any problem with extracting very useable shadow detail from daylight shots that were “ETTL” to avoid clipped highlights. I haven’t used the Sony to take similar shots, so one of these days I’ll set up a test comparison, and I hope to be pleasantly surprised.

In rawproc, I made an early decision that was based more on my lack of math chops than anything, I picked a spline algorithm that delivers floating point Ys for X lookups. The danged thing just worked without me having to study the ins and outs of splines, so It’s In There For Better Or Worse… Thing is, that decision is probably a boon here, in that the curve scaling, 0-255, works with any pixel range because the floating point lookups scale to 0-65535 if 16-bit, or 0.0-1.0 if floating point. I just need to figure out a UI-based offset to easily bound a curve pane to the linear range. The bugaboo with most such ‘expansions’ is usually in the increase in parameters; I store the full tool string for a manipulated image in its ImageDescription exif, and it’s getting rather long.

I’m also going to implement an unbounded mode for the histogram; the data is there, it just needs to be displayed. The UI for this one will probably be a on-off (0|1) property, that is easy to implement. Oh and display.cms.transformoptimizations=1|0…

Oh, now I understand what you mean - a good exercise!