Thread: [Lcms-user] Negative channel values are clipped upon floating point conversions to profiles with tr
An ICC-based CMM for color management
                
                Brought to you by:
                
                    mm2
                    
                
            
            
        
        
        
    | 
      
      
      From: Elle S. <ell...@ni...> - 2016-08-10 14:20:02
       | 
| Hi Marti and all,
It seems that floating point (unbounded) conversions to RGB matrix 
profiles with true gamma TRCs (other than gamma=1.0), such as ClayRGB 
with gamma=2.2 TRC, will clip negative channel values to zero. But 
unbounded conversions to profiles with parametric TRCs, such as the sRGB 
parametric TRC, does not clip negative channel values.
I understand that pow(value, gamma) is undefined for negative values, 
but would code like this make it possible to not clip when converting at 
floating point to a profile with a true gamma TRC? Or perhaps the 
results wouldn't make any sense?
if (value < 0)
       {
       value = -1.0 * value;
       value =  pow (value, gamma);
       value = -1.0 * value;
       }
Best regards,
Elle
-- 
http://ninedegreesbelow.com
Color management and free/libre photography
 | 
| 
      
      
      From: Noel C. <NCa...@Pr...> - 2016-08-10 16:10:51
       | 
| Just a comment related to negative numbers and practical usage... At ProDigital Software we make Photoshop plug-ins. One set in particular adds lighting effects to images, and we handle any RGB format that Photoshop can deliver to us, including 32 bit floating point. We specifically had to add code that zeroes any negative values received, which we found were occasionally being delivered in images expressed in the ColorMatch RGB space. To us negative values can't possibly make sense. Put another way, what's blacker than black? Even modern physics doesn't attempt to describe what's inside the event horizon of a black hole. At least not in the same realm as the physics that describe the visible universe. Granted, the code that ensures no negative values can exist wasn't hard to write nor particularly wasteful of resources, but it DOES take a little time. From our perspective, if all color engines were to ensure only positive numbers would be generated (as LittleCMS does) we could have saved our user a little time starting our software every time it's run. I'm not making a hard case against lifting the restriction against emitting negative numbers from LittleCMS transforms, except to say that as a tool/engine we currently rely on the current behavior and if it's changed we'd like an OPTION to keep it working as it does now. Thanks. -Noel | 
| 
      
      
      From: Elle S. <ell...@ni...> - 2016-08-10 18:14:51
       | 
| On 08/10/2016 12:10 PM, Noel Carboni wrote: > Just a comment related to negative numbers and practical usage... > > At ProDigital Software we make Photoshop plug-ins. One set in > particular adds lighting effects to images, and we handle any RGB format > that Photoshop can deliver to us, including 32 bit floating point. > > We specifically had to add code that zeroes any negative values > received, which we found were occasionally being delivered in images > expressed in the ColorMatch RGB space. > > To us negative values can't possibly make sense. > > Put another way, what's blacker than black? Even modern physics doesn't > attempt to describe what's inside the event horizon of a black hole. At > least not in the same realm as the physics that describe the visible > universe. Not all colors that have one or two negative channel value, also have negative Luminance. Luminance depends on all three channel values. Profiles that support unbounded profile conversions include profiles with parametric curves such as the V4 sRGB parametric TRC. When using unbounded ICC profile conversions and working at floating point precision, one can convert any color from any color space to any other color space that supports unbounded ICC profile conversions. Any color that is out of gamut with respect to the destination color space will have one or two channel values that are less than zero. I'm not sure whether clipping to zero for destination profiles with true gamma (non-linear-gamma) TRCs is intended behavior or not, but it certainly is unexpected based on how conversions to profiles with parametric TRCs behave. If you don't want floating point conversions to profiles that support unbounded conversions, then use the cmsFLAGS_NONEGATIVES flag during the profile conversion. > Granted, the code that ensures no negative values can exist wasn't hard > to write nor particularly wasteful of resources, but it DOES take a > little time. From our perspective, if all color engines were to ensure > only positive numbers would be generated (as LittleCMS does) we could > have saved our user a little time starting our software every time it's > run. > > I'm not making a hard case against lifting the restriction against > emitting negative numbers from LittleCMS transforms, except to say that > as a tool/engine we currently rely on the current behavior and if it's > changed we'd like an OPTION to keep it working as it does now. That restriction was lifted when LCMS V2 was first released and it's incredibly useful (understatement) and important contribution to ICC profile color management. http://www.littlecms.com/CIC18_UnboundedCMM.pdf http://ninedegreesbelow.com/photography/lcms2-unbounded-mode.html http://ninedegreesbelow.com/photography/high-bit-depth-gimp-tutorial-edit-tonality-color-separately.html#out-of-gamut-colors Best, Elle | 
| 
      
      
      From: Noel C. <NCa...@Pr...> - 2016-08-10 18:34:08
       | 
| Thank you for the clarifications, Elle. -Noel | 
| 
      
      
      From: Graeme G. <gr...@ar...> - 2016-08-12 00:38:14
       | 
| Noel Carboni wrote: > To us negative values can't possibly make sense. Note that in some contexts they do. Viewed as a 3D space, there are an infinite range of possible coordinates. When transforming through different appearance spaces, you can end up with intermediate values that are valid (in the sense that they mean something) but that are imaginary (they correspond to no realizable color). If you are gamut mapping, then you would like even imaginary values to be mapped in a way that preserves their fundamental characteristics (hue, lightness, saturation) as much as possible, as well as their relationships between each other. Clipping -ve per component values is easy to implement, but just like the whiter than the white point case, you can end up with hue shifts and other undesirable changes to the intended color. Graeme Gill. | 
| 
      
      
      From: Kevin W. <kev...@gm...> - 2016-08-17 09:04:41
       | 
| besides the cases already covered with gamut mapping etc, you can also get "negative" values due to uncertainty of where black is. Take for example the case of a digital sensor in a camera, if you capture with the lens cap on, noise will mean you will get a range of values about a mean value, if this is value considered as 0 then there will be some pixels where the value is less than zero, throwing away this by clipping degrades the quality of the images. on the subject of extending/extrapolating trc, one approach is to mirror the function similar to Elle's suggestion using temp = pow(abs(x)) out = copysign(temp, x) this tends to be reasonable as it gives a continuous gradient. Kevin | 
| 
      
      
      From: Marti M. <mar...@li...> - 2016-08-17 11:15:36
       | 
| >temp = pow(abs(x)) >out = copysign(temp, x) Yes, this is reasonable. But it should be placed in the profile by the profile creator, not performed by the CMM. CMM should never "guess" data. If the profile gives a valid math expression for negative numbers, the CMM is free to use it and deal with negative numbers, or to clip to zero as many CMMs does. But this does not work in the inverse way: if the profile does NOT give any clue on what to do on negative numbers, then the CMM has to clip them to zero. This is a sort of critical thing for inter-operability sake. Regards Marti Maria The LittleCMS project http://www.littlecms.com -----Original Message----- From: Kevin Wheatley [mailto:kev...@gm...] Sent: miércoles, 17 de agosto de 2016 11:05 To: LCMS mailing list <lcm...@li...> Subject: Re: [Lcms-user] Negative channel values are clipped upon floating point conversions to profiles with true gamma TRCs besides the cases already covered with gamut mapping etc, you can also get "negative" values due to uncertainty of where black is. Take for example the case of a digital sensor in a camera, if you capture with the lens cap on, noise will mean you will get a range of values about a mean value, if this is value considered as 0 then there will be some pixels where the value is less than zero, throwing away this by clipping degrades the quality of the images. on the subject of extending/extrapolating trc, one approach is to mirror the function similar to Elle's suggestion using temp = pow(abs(x)) out = copysign(temp, x) this tends to be reasonable as it gives a continuous gradient. Kevin ---------------------------------------------------------------------------- -- _______________________________________________ Lcms-user mailing list Lcm...@li... https://lists.sourceforge.net/lists/listinfo/lcms-user | 
| 
      
      
      From: Noel C. <NCa...@Pr...> - 2016-08-10 19:24:00
       | 
| Thanks for the additional input, James. I'll be honest - that individual channels may go negative while the overall luminance remains positive represents a new level of awareness for me. We strive to get our color-management right and up to now I was considering negative values (observed to be very small in absolute value) as a bug or side effect of processing inaccuracy (we know Photoshop doesn't always get things perfect). We *haven't*, however, been using the cmsFLAGS_NONEGATIVES flag as we never observed negative values out of LittleCMS transforms. We use LittleCMS to convert to our internal working space... It's possible that without the clamping code our software will just work. We already handle HDR (values greater than 1.0). With this new level of understanding I'm going to look over whether the reasons we had been clamping negative values even still exist - it's possible because of my misunderstanding that they were only needed during development before our color-management infrastructure was fully implemented and matured. We did not start out using a floating point internal representation at first, though we do now. Thank you all for prompting me to revisit this. -Noel | 
| 
      
      
      From: Marti M. <mar...@li...> - 2016-08-11 10:37:24
       | 
| Hi, > but would code like this make it possible to not clip when converting at floating point to a profile with a true gamma TRC? Pow of a negative values is a NaN for very good reasons. I can extend parametric curves that have negative domain defined, but guessing numbers is a bad practice because would work for some cases and completely fail on others. If you use the extension you propose to pivot points in gamut mapping, for example, the results will come completely messed out. sRGB can do be extended, because in lower part gamma uses a linear ramp that is defined in negative zone. AdobeRGB cannot because is a pure exponential. Regards Marti Maria The LittleCMS project http://www.littlecms.com -----Original Message----- From: Elle Stone [mailto:ell...@ni...] Sent: miércoles, 10 de agosto de 2016 16:26 To: Lcms Liste <lcm...@li...> Subject: [Lcms-user] Negative channel values are clipped upon floating point conversions to profiles with true gamma TRCs Hi Marti and all, It seems that floating point (unbounded) conversions to RGB matrix profiles with true gamma TRCs (other than gamma=1.0), such as ClayRGB with gamma=2.2 TRC, will clip negative channel values to zero. But unbounded conversions to profiles with parametric TRCs, such as the sRGB parametric TRC, does not clip negative channel values. I understand that pow(value, gamma) is undefined for negative values, but would code like this make it possible to not clip when converting at floating point to a profile with a true gamma TRC? Or perhaps the results wouldn't make any sense? if (value < 0) { value = -1.0 * value; value = pow (value, gamma); value = -1.0 * value; } Best regards, Elle -- http://ninedegreesbelow.com Color management and free/libre photography ---------------------------------------------------------------------------- -- What NetFlow Analyzer can do for you? Monitors network bandwidth and traffic patterns at an interface-level. Reveals which users, apps, and protocols are consuming the most bandwidth. Provides multi-vendor support for NetFlow, J-Flow, sFlow and other flows. Make informed decisions using capacity planning reports. http://sdm.link/zohodev2dev _______________________________________________ Lcms-user mailing list Lcm...@li... https://lists.sourceforge.net/lists/listinfo/lcms-user | 
| 
      
      
      From: Elle S. <ell...@ni...> - 2016-08-11 19:35:51
       | 
| On 08/11/2016 06:37 AM, Marti Maria wrote: > > Hi, > >> but would code like this make it possible to not clip when converting at > floating point to a profile with a true gamma TRC? > > > Pow of a negative values is a NaN for very good reasons. I can extend > parametric curves that have negative domain defined, but guessing numbers is > a bad practice because would work for some cases and completely fail on > others. If you use the extension you propose to pivot points in gamut > mapping, for example, the results will come completely messed out. > > sRGB can do be extended, because in lower part gamma uses a linear ramp that > is defined in negative zone. AdobeRGB cannot because is a pure exponential. Hi Marti, What you say makes sense as numbers calculated using my suggestion for getting around the NaN issue do very rapidly get very large. Does this means these RGB numbers don't produce the same XYZ colors in the destination color space as in the source color space? I have a follow-up question. For unbounded floating point conversions to sRGB, values below zero are extended linearly. Are values above 1.0 also extended linearly, perhaps using the slope at 1.0? I had assumed they were extended using gamma=2.4 calculations, but now I'm guessing this assumption might be wrong. Best regards, Elle > > Regards > > Marti Maria > The LittleCMS project > http://www.littlecms.com > > -----Original Message----- > From: Elle Stone [mailto:ell...@ni...] > Sent: miércoles, 10 de agosto de 2016 16:26 > To: Lcms Liste <lcm...@li...> > Subject: [Lcms-user] Negative channel values are clipped upon floating point > conversions to profiles with true gamma TRCs > > Hi Marti and all, > > It seems that floating point (unbounded) conversions to RGB matrix profiles > with true gamma TRCs (other than gamma=1.0), such as ClayRGB with gamma=2.2 > TRC, will clip negative channel values to zero. But unbounded conversions to > profiles with parametric TRCs, such as the sRGB parametric TRC, does not > clip negative channel values. > > I understand that pow(value, gamma) is undefined for negative values, but > would code like this make it possible to not clip when converting at > floating point to a profile with a true gamma TRC? Or perhaps the results > wouldn't make any sense? > > if (value < 0) > { > value = -1.0 * value; > value = pow (value, gamma); > value = -1.0 * value; > } > > Best regards, > Elle > -- > http://ninedegreesbelow.com > Color management and free/libre photography > | 
| 
      
      
      From: Marco F. <Mar...@en...> - 2016-08-17 09:55:56
       | 
| All, excuse me, not all that important and I didn't follow the details of the previous discussion. I didn't understand why the pow() function might have any issues with negative values. pow(abs(x)) == pow(x) or where is my thought mistake? -----Original Message----- From: Kevin Wheatley [mailto:kev...@gm...] Sent: Mittwoch, 17. August 2016 11:05 To: LCMS mailing list Subject: Re: [Lcms-user] Negative channel values are clipped upon floating point conversions to profiles with true gamma TRCs besides the cases already covered with gamut mapping etc, you can also get "negative" values due to uncertainty of where black is. Take for example the case of a digital sensor in a camera, if you capture with the lens cap on, noise will mean you will get a range of values about a mean value, if this is value considered as 0 then there will be some pixels where the value is less than zero, throwing away this by clipping degrades the quality of the images. on the subject of extending/extrapolating trc, one approach is to mirror the function similar to Elle's suggestion using temp = pow(abs(x)) out = copysign(temp, x) this tends to be reasonable as it gives a continuous gradient. Kevin ------------------------------------------------------------------------------ _______________________________________________ Lcms-user mailing list Lcm...@li... https://lists.sourceforge.net/lists/listinfo/lcms-user | 
| 
      
      
      From: Kevin W. <kev...@gm...> - 2016-08-17 10:38:39
       | 
| On Wed, Aug 17, 2016 at 10:21 AM, Marco Freudenberger <Mar...@en...> wrote: > All, > > excuse me, not all that important and I didn't follow the details of the previous discussion. > I didn't understand why the pow() function might have any issues with negative values. > pow(abs(x)) == pow(x) > or where is my thought mistake? ignoring the mistake I made with only including the value x and missing the y parameter, the function pow(x, y) when x is negative and y is not an integer then mathematically you can't represent it as a real number in the general case, that is why it returns NaN see https://en.wikipedia.org/wiki/Exponentiation#Real_exponents_with_negative_bases Kevin | 
| 
      
      
      From: Marco F. <Mar...@en...> - 2016-08-17 10:40:40
       | 
| I see, I was assuming pow() being a sqr function :-) Thanks. -----Original Message----- From: Kevin Wheatley [mailto:kev...@gm...] Sent: Mittwoch, 17. August 2016 12:39 To: Marco Freudenberger Cc: LCMS mailing list Subject: Re: [Lcms-user] Negative channel values are clipped upon floating point conversions to profiles with true gamma TRCs On Wed, Aug 17, 2016 at 10:21 AM, Marco Freudenberger <Mar...@en...> wrote: > All, > > excuse me, not all that important and I didn't follow the details of the previous discussion. > I didn't understand why the pow() function might have any issues with negative values. > pow(abs(x)) == pow(x) > or where is my thought mistake? ignoring the mistake I made with only including the value x and missing the y parameter, the function pow(x, y) when x is negative and y is not an integer then mathematically you can't represent it as a real number in the general case, that is why it returns NaN see https://en.wikipedia.org/wiki/Exponentiation#Real_exponents_with_negative_bases Kevin |