GNOME Bugzilla – Bug 755376
"Extracted L" from "Tools/GEGL Operation/Extract Component/Component LAB L" isn't really "L"
Last modified: 2018-05-22 12:11:29 UTC
The "extracted L component" from GIMP "Tools/GEGL Operation/Extract Component/Component LAB L" isn't really "L". It differs from true LAB L by the amount that the sRGB "almost perceptually uniform" TRC differs from a true perceptually uniform "LAB L" TRC (parameters below taken from http://ninedegreesbelow.com/photography/lcms-make-icc-profiles.html): /* sRGB TRC */ cmsFloat64Number srgb_parameters[5] = { 2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045 }; /* LAB "L" (perceptually uniform) TRC */ cmsFloat64Number labl_parameters[5] = { 3.0, 0.862076, 0.137924, 0.110703, 0.080002 }; It's easy to show that "Extract Component/Component LAB L" doesn't really produce LAB Lightness: Change the extracted "L component" layer's blend mode to LCH Lightness and set it over a copy of the original color layer from which the LAB L channel was extracted. If the extracted "L component" is really LAB Lightness, the image tonality won't change, but it does.
There are several ways to get from the extracted LAB L channel back to sRGB: 1. Assign a gray profile with the LAB L TRC to the extracted LAB L and convert to a gray profile with the sRGB TRC before sending the result to the GIMP XCF file. 2. Change the mode to RGB and assign any RGB profile that has the LAB L TRC (they all produce the same result on an image where R=G=B everywhere). And then convert to the regular sRGB profile before sending the result to the GIMP XCF file. 3. LAB "L" converted to RGB in some specified RGB color space is exactly the same as RGB Luminance, calculated using linear RGB (otherwise you get Luma, not Luminance). So "operations/workshop/component-extract.c" could just output RGB Luminance whenever the LAB L component is requested. As an aside, don't use the gamma hack with Tools/GEGL Operation/Extract Component/Component LAB L, unless you just like the "look" and don't really want LAB L. At gamma precision using the gamma hack produces something close to, but not quite the same as "Luma", and at linear precision it's hard to say what the gamma hack produces, but it's not LAB Lightness. As a second aside, GIMP 2.9's "decompose to LAB" does produce an accurate L channel in the grayscale LAB layer stack. But dragging that L channel over to a color layer stack that's in the regular sRGB color space produces a layer that is "almost but not quite" equal to the LAB Lightness channel, exactly as happens with Tools/GEGL Operation/Extract Component/Component LAB L. If there is an interest, I can try to write a patch that incorporates into GEGL's "operations/workshop/component-extract.c" the same changes that I made in this patch for GIMP's "plug-ins/common/decompose.c": https://bug755270.bugzilla-attachments.gnome.org/attachment.cgi?id=311797
Sorry about the typo in the title. It should read "Extracted L", not "Extracted L t".
(In reply to Elle Stone from comment #1) > If there is an interest, I can try to write a patch that incorporates into > GEGL's "operations/workshop/component-extract.c" the same changes that I > made in this patch for GIMP's "plug-ins/common/decompose.c" I originally implement this operation to obtain several black & white versions of an image in a mask creation context, without any considerations for other possible usages. So, if it can be usefull in a color correction context, feel free to provide a patch to fix this inaccuracy.
(In reply to Thomas Manni from comment #3) > I originally implement this operation to obtain several black & white > versions of an image in a mask creation context, without any considerations > for other possible usages. > > So, if it can be usefull in a color correction context, feel free to provide > a patch to fix this inaccuracy. No doubt there are additional use cases, but I can think of three excellent use cases for code that extracts channels without having to decompose to the desired color space and then retrieve the resulting channel layer(s): 1. As you say, for making layer masks. 2. For use as blending layers. 3. As a step in making black and white renditions. So it would be very nice to have accurately extracted channels. I've checked the extracted channels for RGB and LAB, using the two supplied options "Linear output" and "Invert". As currently coded (putting the LAB midpoint of 127 vs 127.5 to one side): 1. Leaving the "Linear output" box *unchecked* produces correct (RGB) or *almost* correct (LAB) results. 2. Checking the "Linear output" box produces *in*correct results, as if an approximately "Levels gamma=2.22" adjustment had been applied to the correct results. 3. Checking the "Invert output" box produces radiometrically incorrect results regardless of whether the "Linear output" box is checked or not. The Invert code is operating on perceptually uniform RGB, when for radiometrically correct results it should operate on linearized RGB. Results are the same regardless of whether the layer stack is using linear light or perceptually uniform precision. The "Linear output" option could simply be removed, in which case when users really do want to apply an approximately "Levels gamma=2.22" adjustment to the extracted channel, they can use the GIMP Levels operation. As points of reference: * GIMP "Colors/Components/Decompose to RGB" produces correct results at both linear and gamma precisions. * GIMP "Colors/Components/Decompose to LAB" produces *almost* correct results at both linear and gamma precisions. The deviation from correct is equal to the difference between the sRGB and LAB L TRCs (http://ninedegreesbelow.com/photography/lab-lightness-to-black-and-white-gimp29-photoshop.html#decompose-and-drag). This is a color management issue. One solution is to change the mode of the decomposed layer stack from Y to RGB, create an RGB profile with the sRGB primaries and the Lab-L TRC, and assign it to the extracted LAB channels, and then convert to the GIMP built-in profile.
The CMYK extracted channels seemed very odd. So I added functions to component-extract.c to extract just CMY, to make it easier to track down what wasn't working the way it should. At linear precision, after adding functions to extract just CMY, component-extract.c produces results on linear RGB IF both of the following is true: "Linear output" is *un*checked and the Gamma hack *is* checked. At gamma precision, component-extract.c can't be used to produce CMY channels that are linear inversions of the RGB channels. Results are either an inversion of perceptually uniform RGB, or else are wrong in various other ways. As naive CMY just inverts RGB, and the "meaning" of RGB numbers derive from the color space profile/TRC, it seems to me that the extracted/decomposed naive CMY channels should be exactly the same as the radiometrically correct inversion of the RGB channels, regardless of the precision (linear or perceptually uniform) of the layer stack. Which is to say the babl flipping in the naive CMYK code seems to not be required at all. So using the gegl code with extract to CMY, and *modifying* the babl naive-CMYK code to remove the linear_to_gamma_2_2 and gamma_2_2_to_linear functions: At linear precision extracting the CMY channels produces correct results IF the "Linear output box is checked. The gamma hack has no effect at all. And checking both the Invert component box *and* the Linear output box gives you the corresponding RGB channels, which is what I would expect from inverting naive CMY. Unless someone has a very compelling reason why the naive CMY channels shouldn't be the same as the radiometrically correct inversions of the RGB channels, this seems like correct behavior to me.
Created attachment 316267 [details] [review] 1 of 3 patches affecting component-extract.c
Created attachment 316268 [details] [review] 2 of 3 patches affecting component-extract.c
Created attachment 316270 [details] [review] 3 of 3 patches affecting component-extract.c For the three attached patches, one goal is to get component-extract.c and GIMP's decompose-compose to produce the same correct results. The other goal is to get all the component-extract.c channel extractions to work the same when using the check box options. But the behavior still varies from one channel to the next, with LAB currently being the odd set of channels compared to RGB/CMY(K). Results from the patched code are still odd for HSV/HSL and maybe YCbCr (which I didn't try extracting). So the same problem that affects the extracted CMYK channels in the current component-extract.c code might also affect HSV/HSL (and maybe YCbCr), and a solution might be to modify the relevant babl code as I did for CMY/CMYK.
The attached patches need more work, so there's probably not much point in even looking at them.
Created attachment 316378 [details] [review] component-extract patch so component-extract, decompose produce the same channels
Created attachment 316379 [details] [review] decompose patch so component-extract and decompose produce same channels
Sorry for the unclear name for patch "2 of 3 patches . . . ". If the babl/extensions/naive-CMYK.c code is left unpatched, then decomposing to CMY produces something other than the radiometrically correct inverse of RGB. See Comment 5 above. With all three patches applied: gegl/operations/workshop/component-extract.c and gimp/plug-ins/common/decompose.c produce the same resulting channels, except for YCbCr. LCH and CMY have been added to component-extract.c. I commented out the "invert" code because currently it operates on perceptually uniform RGB. Users always have the option to extract and then invert, although currently there's no easy way in GIMP to do a radiometrically correct RGB invert. In component-extract.c, HSV/L Hue has been relabelled to differentiate it from LCH Hue. In gimp/plug-ins/common/decompose.c the resulting channel labels for HSV and HSL have been modified to indicate which decomposition was used. HSV/HSL results match GIMP 2.8 results, which seems right as there's no such thing as "radiometrically correct HSV/HSL". RGB/LAB/LCH results are correct, except the LAB/LCH results still have the grayscale color-management issue caused by the difference between the LAB-L and sRGB TRCs. CMY results are the radiometrically correct inverse of RGB, and CMYK starts with the radiometrically correct inverse of RGB. The resulting YCbCr channels are still different for component-extract.c and decompose.c. I didn't try to track down the source of the difference. There are two babl files for YCbCr, so maybe the two files use different babl files to do the decomposition.
Created attachment 344432 [details] [review] Add LCH to component-extract.c and fix LAB ranges This patch fixes the LAB ranges and also adds LCH Chroma and Hue to component-extract.c This patch does not address the fact that the LAB/LCH extracted component is interpreted "as if" the LAB companding curve were exactly the same as the sRGB companding curve (which it is not). Unrelated to the "LAB/sRGB companding curve" issue, the "component-extract to LCH Chroma channel" code produces an image entirely composed of black or white. FWIW, in my patched GIMP the same code produces what default GIMP's "decompose to LCH" produces. The odd result from the "extract Chroma" code might be related to the odd results from the Chroma layer blend code. But this possibility doesn't explain why default GIMP's "decompose to LCH" still does produce the right result for the Chroma layer.
Created attachment 344434 [details] version of the sRGB profile with the lab "L" companding curve Note that the extracted LAB L channel should be identical to the result of running "Colors/Desaturate/Desaturate/" and choosing Luminance. I don't have the requisite coding skills to fix the fact that currently the LAB/LCH extracted components are treated "as if" the LAB and sRGB companding curves are the same. But here is a workaround, that perhaps can provide a clue as to how to fix the problem: At "gamma" precision: 1. extract the LAB L channel. 2. drag the extracted LAB L channel out as a new image and assign the attached "labl" version of the sRGB profile to the new image. 3. convert the new image to the built-in sRGB profile and drag it back to the original layer stack. At "linear" precision, do exactly the same steps, except after step 2, first change the precision to "gamma" precision before assigning the labl version of sRGB.
(In reply to Elle Stone from comment #13) Thanks, I push a slightly modified version of your patch... > The odd result from the "extract Chroma" code might be related to the odd > results from the Chroma layer blend code. But this possibility doesn't > explain why default GIMP's "decompose to LCH" still does produce the right > result for the Chroma layer. ... because the Chroma component need to be scaled appropriatly.
-- GitLab Migration Automatic Message -- This bug has been migrated to GNOME's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/gegl/issues/29.