Thread: [Lcms-user] Color-balanced ICC profiles
An ICC-based CMM for color management
Brought to you by:
mm2
From: Elle S. <l.e...@gm...> - 2013-08-28 11:54:01
|
My apologies in advance for a long preamble to three short questions! It seems to me that a fundamental requirement of an RGB working space is that it be color-balanced, meaning that if R=G=B, then in CieLAB space a=b=0 (the color is completely neutral gray). Also, for an 8-bit image, if R=G=B=255, then LAB L* should be 100 on a scale from 0 to 100. The "sRGB.icm" profile that comes with Argyllcms *is* color-balanced. Checking "sRGB.icm" using transicc and xicclu, there is a small discrepency between transicc and xicclu values: $ transicc -w -i sRGB-argyll.icc -o *Lab -t1 -c0 R? G? B? 255 255 255 L*=100.0000 a*=0.0005 b*=-0.0004 $ xicclu -ir -pl -s255 sRGB-argyll.icc 255.000000 255.000000 255.000000 [RGB] -> MatrixFwd -> 100.000000 0.000000 0.000000 [Lab] I wrote a program that uses lcms (v2.5) to make 3 different V2 sRGB profiles. Whether the resulting profile is color-balanced depends on the values used for the D65 white point. The profile that uses the D65 value from the Argyll sRGB profile is *almost* color-balanced. But the profiles that use the D65 value from the lcms API are not color-balanced. This is true whether the profiles are V4 or V2, but the examples below are V2 so that xicclu can also read the profiles. cmsCIExyY d65_lcms = {0.3127, 0.3291, 1.0}; /* from lcms 2.5 API */ cmsCIExyY d65_argyll = {0.312700492, 0.329000939, 1.0}; /* argyllcms srgb white point */ Code for three sRGB profiles: 1. whitepoint = d65_argyll; /* using d65-argyll */ primaries = srgb_primaries; tone_curve[0] = tone_curve[1] = tone_curve[2] = srgb_parametric_curve[0]; profile = cmsCreateRGBProfile ( &whitepoint, &primaries, tone_curve ); cmsSetProfileVersion(profile, 2.1); filename = "sRGB-V2-d65-argyll.icc"; cmsSaveProfileToFile(profile, filename); 2. whitepoint = d65_lcms; /* using d65_lcms */ primaries = srgb_primaries ; tone_curve[0] = tone_curve[1] = tone_curve[2] = srgb_parametric_curve[0]; profile = cmsCreateRGBProfile ( &whitepoint, &primaries, tone_curve ); cmsSetProfileVersion(profile, 2.1); filename = "sRGB-V2-d65-lcms.icc"; cmsSaveProfileToFile(profile, filename); 3. hprofile = cmsCreate_sRGBProfile(); /* cmsCreate_sRGBProfile */ cmsSetProfileVersion(hprofile, 2.1); filename = "lcms-cmsCreate_sRGBProfile.icc"; cmsSaveProfileToFile(hprofile, filename); 1 above, using the same D65 value as the Argyllcms "sRGB.icm", produces a profile that is almost identical to sRGB.icm and is almost color-balanced: $ transicc -w -i sRGB-V2-d65-argyll.icc -o *Lab -t1 -c0 R? G? B? 255 255 255 L*=100.0000 a*=0.0005 b*=0.0008 $ xicclu -ir -pl -s255 sRGB-V2-d65-argyll.icc 255.000000 255.000000 255.000000 [RGB] -> MatrixFwd -> 100.000000 0.000000 0.001233 [Lab] 2 and 3 above, using the D65 value from the lcms API, produce almost identical profiles that are not color-balanced. Checking "lcms-cmsCreate_sRGBProfile.icc": $ transicc -w -i lcms-cmsCreate_sRGBProfile.icc -o *Lab -t1 -c0 R? G? B? 255 255 255 L*=100.0006 a*=-0.0020 b*=0.0018 $ xicclu -ir -pl -s255 lcms-cmsCreate_sRGBProfile.icc 255.000000 255.000000 255.000000 [RGB] -> MatrixFwd -> 100.000590 -0.002543 0.002250 [Lab] Similar results obtain with other D65 profiles (eg adobe_compatible) and also with D50 profiles like widegamut and prophoto, where again the difference between color-balanced and not color-balanced depends on using a white point that isn't exactly equal to official D50 white point values. Three questions: First, when making a profile, is there any reason to use official D65 and D50 white points that produce profiles that aren't color-balanced? Second, for an 8-bit image, perhaps it doesn't matter whether an ICC profile is perfectly color-balanced or not. Does it matter for the increasing number of image editors and raw processors that work with 32-bit linear gamma floating point images? Third, why the discrepency between xicclu and transicc values? Thanks in advance for insight on this issue of color-balanced profiles! -- Elle Stone http://ninedegreesbelow.com - articles on color management & open source photography |
From: <mar...@li...> - 2013-08-29 09:33:51
|
Hi Elle, RGB spaces may or may not have centered neutral axis. It is a good premise when you are defining a device space for a physical device (i.e. a printer or a scanner/camera). But the RGB color model does not require that. RGB color spaces implementing absolute colorimetric intent does not behave in such way, to give you a common example. Centered neutral axis is, however, a very desirable attribute and most if not all exchange RGB color spaces as well as many device spaces are using this requirement. This is on color spaces, still nothing to do with ICC profiles. Then, when we use ICC profiles to describe color spaces, there are some limitations that the ICC technology and file format do impose: First and most important is the quantization. The "normal" profiles (as there is a floating extension largely unused) have a maximum precision of 16 bits. That means, no matter what you do, you always have some uncertainty over the third decimal. That quantity is far below the JND (just noticeable difference). This is not a big issue since ICC profiles are intended for human vision, they use spaces like XYZ or Lab and therefore quantities below the human acuity are not important. Because that, a perfect match is not guaranteed. Some widespread profiles have gaps. Take the usual "sRGB Color Space Profile.icm" which is a sort of "de facto" standard: transicc -i "sRGB Color Space Profile.icm" -o *Lab LittleCMS ColorSpace conversion calculator - 4.2 [LittleCMS 2.05] Enter values, 'q' to quit R? 255 G? 255 B? 255 L*=99.9988 a*=0.0188 b*=-0.0173 Yes, that is right! There is some chroma on pure white and it is located slightly below D50. But still, it does work for many people, in fact, very few people knows about this mismatch and they are equally happy using this profile. Now for your questions: > First, when making a profile, is there any reason to > use official D65 and D50 white points that produce profiles that > aren't color-balanced? The ICC spec defines values for D50, if you want to fully adhere to the spec, you have to use such value. The residual amount of chroma you get is so low that can be ignored. For D65, I use the CCT black-body radiator formula on 6504K as described by CIE. Really, should be around 6503.6K > Second, for an 8-bit image, perhaps it doesn't matter whether an ICC > profile is perfectly color-balanced or not. Does it matter for the > increasing number of image editors and raw processors that work with > 32-bit linear gamma floating point images? This is the whole point of ICC floating point extension, which does not suffer from this limitation > Third, why the discrepency between xicclu and transicc values? Small discrepancies (below second decimal) may be explained by different rounding strategies. But you are just checking matrix-shape profiles which are a minimal set of the huge variation of possible profiles. In general, I have found xicclu and transicc to be highly consistent. Much more that Adobe and ColorSync, for example. Regards Marti Maria. Quoting Elle Stone <l.e...@gm...>: > My apologies in advance for a long preamble to three short questions! > > It seems to me that a fundamental requirement of an RGB working space > is that it be color-balanced, meaning that if R=G=B, then in CieLAB > space a=b=0 (the color is completely neutral gray). Also, for an 8-bit > image, if R=G=B=255, then LAB L* should be 100 on a scale from 0 to > 100. > > The "sRGB.icm" profile that comes with Argyllcms *is* color-balanced. > Checking "sRGB.icm" using transicc and xicclu, there is a small > discrepency between transicc and xicclu values: > > $ transicc -w -i sRGB-argyll.icc -o *Lab -t1 -c0 > R? G? B? 255 255 255 L*=100.0000 a*=0.0005 b*=-0.0004 > > $ xicclu -ir -pl -s255 sRGB-argyll.icc > 255.000000 255.000000 255.000000 [RGB] -> MatrixFwd -> 100.000000 > 0.000000 0.000000 [Lab] > > I wrote a program that uses lcms (v2.5) to make 3 different V2 sRGB > profiles. Whether the resulting profile is color-balanced depends on > the values used for the D65 white point. The profile that uses the D65 > value from the Argyll sRGB profile is *almost* color-balanced. But the > profiles that use the D65 value from the lcms API are not > color-balanced. This is true whether the profiles are V4 or V2, but > the examples below are V2 so that xicclu can also read the profiles. > > cmsCIExyY d65_lcms = {0.3127, 0.3291, 1.0}; /* from > lcms 2.5 API */ > cmsCIExyY d65_argyll = {0.312700492, 0.329000939, 1.0}; /* > argyllcms srgb white point */ > > Code for three sRGB profiles: > 1. whitepoint = d65_argyll; /* using d65-argyll */ > primaries = srgb_primaries; > tone_curve[0] = tone_curve[1] = tone_curve[2] = srgb_parametric_curve[0]; > profile = cmsCreateRGBProfile ( &whitepoint, &primaries, tone_curve ); > cmsSetProfileVersion(profile, 2.1); > filename = "sRGB-V2-d65-argyll.icc"; > cmsSaveProfileToFile(profile, filename); > > 2. whitepoint = d65_lcms; /* using d65_lcms */ > primaries = srgb_primaries ; > tone_curve[0] = tone_curve[1] = tone_curve[2] = srgb_parametric_curve[0]; > profile = cmsCreateRGBProfile ( &whitepoint, &primaries, tone_curve ); > cmsSetProfileVersion(profile, 2.1); > filename = "sRGB-V2-d65-lcms.icc"; > cmsSaveProfileToFile(profile, filename); > > 3. hprofile = cmsCreate_sRGBProfile(); /* cmsCreate_sRGBProfile */ > cmsSetProfileVersion(hprofile, 2.1); > filename = "lcms-cmsCreate_sRGBProfile.icc"; > cmsSaveProfileToFile(hprofile, filename); > > 1 above, using the same D65 value as the Argyllcms "sRGB.icm", > produces a profile that is almost identical to sRGB.icm and is almost > color-balanced: > > $ transicc -w -i sRGB-V2-d65-argyll.icc -o *Lab -t1 -c0 > R? G? B? 255 255 255 L*=100.0000 a*=0.0005 b*=0.0008 > > $ xicclu -ir -pl -s255 sRGB-V2-d65-argyll.icc > 255.000000 255.000000 255.000000 [RGB] -> MatrixFwd -> 100.000000 > 0.000000 0.001233 [Lab] > > 2 and 3 above, using the D65 value from the lcms API, produce almost > identical profiles that are not color-balanced. Checking > "lcms-cmsCreate_sRGBProfile.icc": > > $ transicc -w -i lcms-cmsCreate_sRGBProfile.icc -o *Lab -t1 -c0 > R? G? B? 255 255 255 L*=100.0006 a*=-0.0020 b*=0.0018 > > $ xicclu -ir -pl -s255 lcms-cmsCreate_sRGBProfile.icc > 255.000000 255.000000 255.000000 [RGB] -> MatrixFwd -> 100.000590 > -0.002543 0.002250 [Lab] > > Similar results obtain with other D65 profiles (eg adobe_compatible) > and also with D50 profiles like widegamut and prophoto, where again > the difference between color-balanced and not color-balanced depends > on using a white point that isn't exactly equal to official D50 white > point values. > > Three questions: First, when making a profile, is there any reason to > use official D65 and D50 white points that produce profiles that > aren't color-balanced? > > Second, for an 8-bit image, perhaps it doesn't matter whether an ICC > profile is perfectly color-balanced or not. Does it matter for the > increasing number of image editors and raw processors that work with > 32-bit linear gamma floating point images? > > Third, why the discrepency between xicclu and transicc values? > > Thanks in advance for insight on this issue of color-balanced profiles! > > -- > Elle Stone > http://ninedegreesbelow.com - articles on color management & open > source photography > > ------------------------------------------------------------------------------ > Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more! > Discover the easy way to master current and previous Microsoft technologies > and advance your career. Get an incredible 1,500+ hours of step-by-step > tutorial videos with LearnDevNow. Subscribe today and save! > http://pubads.g.doubleclick.net/gampad/clk?id=58040911&iu=/4140/ostg.clktrk > _______________________________________________ > Lcms-user mailing list > Lcm...@li... > https://lists.sourceforge.net/lists/listinfo/lcms-user |
From: Richard H. <hug...@gm...> - 2013-08-29 09:52:42
|
On 29 August 2013 10:33, <mar...@li...> wrote: > The ICC spec defines values for D50, if you want to fully adhere to > the spec, you have to use such value. Hmm, I've been using a value of x:0.345653 y:0.358596 when generating my profiles rather than the CIE D50 values of x:0.345703 y:0.358539 -- I'll fix that now. I assumed 5003K was exactly equal to D50. > you get is so low that can be ignored. For D65, I use the CCT > black-body radiator formula on 6504K as described by CIE. Really, > should be around 6503.6K Do either of you know where the CIE refers to D65? I see an example as "WhitePoint [0.9505 1 1.0890]" in the EPS example, but nothing approaching a standard. Also, do you have exact xy coordinates for either 6504K or 6503.6K handy? I've been using cmsWhitePointFromTemp (&w, 6504) but I'm wondering if that's accurate enough. Thanks, Richard. |
From: Elle S. <l.e...@gm...> - 2013-08-29 10:31:09
|
On 8/29/13, Richard Hughes <hug...@gm...> wrote: > Do either of you know where the CIE refers to D65? I see an example as > "WhitePoint [0.9505 1 1.0890]" in the EPS example, but nothing > approaching a standard. To me the CIE website seems not user-friendly. However, this bit of code lists the following D65 values from ASTM and from Wyszecki & Styles: https://github.com/fhoech/opi.py/blob/master/lib/colormath.py ASTM E308-01 D65: {"X": 0.95047, "Z": 1.08883} Wyszecki & Stiles D65: {"X": 0.95017, "Z": 1.08813} Tracking down ASTM and Wyszecki & Stiles: http://www.astm.org/DATABASE.CART/HISTORICAL/E308-01.htm http://www.amazon.com/Color-Science-Concepts-Quantitative-Formulae/dp/0471399183 Lindbloom uses the ASTM D65 values (http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html) Why the different D65 values? Are white point values really specified to 5 decimal places in the standards? Or are the values on the web rounded? Is either ASTM or Wyszecki/Styles "the" standard? Elle |
From: Richard H. <hug...@gm...> - 2013-08-29 10:49:49
|
On 29 August 2013 11:30, Elle Stone <l.e...@gm...> wrote: > Styles: https://github.com/fhoech/opi.py/blob/master/lib/colormath.py > Why the different D65 values? So that looks like a CIE D65, which is probably most interesting to me. Florian, do you remember where you got the CIE D65 values from? Richard. |
From: Richard H. <hug...@gm...> - 2013-08-29 15:12:04
|
On 29 August 2013 13:59, Florian Höch <lis...@ho...> wrote: > from the xy chromaticity coordinates of D65 0.3127 0.3290 to XYZ and which is the same as xyY=(0.312700492, 0.329000939, 1.000000000) Notice all the zeros in xy? I can't think that's a co-incidence... So the question remains, what xy profile values do I use for a D65 whitepoint? Richard. |
From: Elle S. <l.e...@gm...> - 2013-08-29 17:12:43
|
Marti, thank you for answering my long question! The context was that I was asked if there was a stand-alone program for generating ICC profiles. I didn't know of any, but realized that I could write a simple program. So I looked for values to use for primaries, white points, and tone curves. I found very good agreement on primaries and tone curves, not so much for white points. Plus I was puzzled by the "color-balanced/not color-balanced" results. In case anyone is curious, the table below shows various D65 white point values: x y Source 0.312730 0.329020 Danny Pascale, "A Review of RGB Color Spaces" 0.312700 0.329001 AdobeRGB1998.icc profile 0.312700 0.329000 Adobe RGB (1998) Color Image Encoding 0.312700 0.329001 Argyllcms sRGB.icm profile 0.312727 0.329023 colormath.py ASTM 0.312727 0.329023 colormath.py Wyszecki & Stiles 0.312704 0.329023 http://color.org/chadtag.xalter 0.312727 0.329023 http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html 0.312727 0.329023 Hunter Lab ASTM E308 values, Insights on Color, Vol. 14, No. 2 0.312700 0.329100 LCMS API documentation, sRGB D65 0.312716 0.329001 V4 ICC Specs, B.2 Embedding ICC profiles in EPS files -- Elle Stone http://ninedegreesbelow.com - articles on color management & open source photography |
From: Elle S. <l.e...@gm...> - 2013-09-01 22:07:15
|
While creating profiles using different profile white points, I noticed a pattern that suggests a rounding error. For example, running the command "xicclu -ir -pl -s255 profile.icc" on the following 7 profiles produces these results: Apple-CCT 100.000000 -0.002638 0.000000 Apple-D65code 100.000000 0.000000 0.000000 perfect CIE-RGB-CCT 100.000000 0.000000 0.001233 CIE-RGB-E_5454K 100.000000 0.000000 0.001233 Clay-CCT 100.000000 -0.002638 0.001233 Clay-D65_old 100.000000 0.000000 0.001233 NTSC-CCT 100.000000 0.000000 0.001233 NTSC-C_6774K 100.000000 0.000000 0.001233 SMPTE-CCT 100.000000 0.000000 -0.001233 SMPTE-D65_old 100.000000 -0.002638 0.001233 sRGB-CCT 99.999410 0.002543 -0.001017 sRGB-D65code 100.000000 0.000000 0.001233 Widegamut-CCT 100.000590 -0.005181 0.001017 Widegamut-D50_lcms 100.000000 0.000000 0.001233 Profile white point key: "CCT" = lcms correlated color temp; I used 6503.6 for D65. D65code = (0.31271, 0.32912) E_5454K = (0.333608970, 0.348572909) Robertson equations D65_old = (0.312700, 0.329000) C_6774K = (0.308548930, 0.324928102) Robertson equations D50_lcms = (0.345702915, 0.358538597) In the profiles above, the value +/- 0.001233 shows up ten times over a diverse set of profile white points. Including results from other profiles, 0.002543, 0.001017 and 0.002638 also show up multiple times, though not as frequently as 0.001233. For R=G=B=255, no deviation from 0 in the Lab "a" channel plus a deviation of 0.001233 in the Lab "b" channel corresponds to a deviation of 0.000015 (+0.001233) or 0.000016 (-0.001233) in the Z XYZ channel (the X value deviation is 0 in either case). The values "0.000015" and "0.000016" are important numbers when converting from XYZ to hexadecimal: 0.000015 (and any smaller value), multiplied by 65535 and converted to hex, is 0. 0.000016, multiplied by 65535 and converted to hex, is 1. This might be purely coincidental, but it suggests a decimal to hexadecimal rounding error. So I looked for a possible source of a "1 hex unit" error and perhaps found one. The following lines are in the "lcms2.h" file: // D50 XYZ normalized to Y=1.0 #define cmsD50X 0.9642 #define cmsD50Y 1.0 #define cmsD50Z 0.8249 Using these cmsD50X and cmsD50Z values, here's the round-trip conversion through hex: starting values: (0.964200000, 1.0, 0.824900000) convert to hex: (F6D4, FFFF, D32B) convert back to decimal: (0.964187076, 1.0, 0.824887465) absolute difference: (0.000012924, 0.0, 0.000012535) According to iccToXml, for profiles generated by lcms the profile header illuminant value is (0.964202881, 1, 0.824905396). The corresponding round-trip conversion through hex values are: starting values: (0.964202881, 1.0, 0.824905396) convert to hex: (F6D5, FFFF, D32C) convert back to decimal: (0.824902724, 1.0, 0.964202335) absolute difference: (0.000000546, 0.0, 0.000002672) Notice that the iccToXml illuminant values convert to hex and back with a smaller error, and also the resulting hex values are larger by 1 hex unit (F6D4->F6D5, D32B->D32C). So what happens if the D50 XYZ values in lcms2.h are changed to match the iccToXml illuminant values? // D50 XYZ normalized to Y=1.0 #define cmsD50X 0.96420288 //iccToXml header illuminant value #define cmsD50Y 1.0 #define cmsD50Z 0.82490540 //iccToXml header illuminant value To find out, I *Changed the D50 values in lcms2.h to equal the header illuminant value reported by iccToXml *Recompiled lcms *Recompiled my profile-making code *Recreated all the profiles using the exact same white points as before Here are the new xicclu results: Apple-mod-CCT 100.000000 0.002638 0.000000 flipped sign Apple-mod-D65code 100.000000 0.000000 0.000000 perfect CIE-RGB-mod-CCT 100.000000 0.000000 0.000000 perfect CIE-mod-RGB-E_5454 100.000000 0.000000 0.000000 perfect Clay-mod-CCT 100.000000 0.000000 0.001233 improved Clay-mod-D65_old 100.000000 0.000000 0.000000 perfect NTSC-mod-CCT 100.000000 0.000000 0.000000 perfect NTSC-mod-C_6774 100.000000 0.000000 0.000000 perfect SMPTE-mod-CCT 100.000000 0.000000 -0.001233 no change SMPTE-mod-D65_old 100.000000 0.000000 0.000000 perfect sRGB-mod-CCT 99.999410 0.002543 -0.001017 no change sRGB-mod-D65code 100.000000 0.000000 0.000000 perfect Widegamut-mod-CCT 100.000590 -0.005181 0.001017 no change Widegamut-mod-D50_lcms 100.000000 0.000000 0.000000 perfect I've checked many more profiles than are listed above, and the results are 100% consistent. "Color balanced" isn't everything! I checked all the profiles against the Lindbloom xyY values by calculating the sum of the absolute differences in the x,y,Y values for the red, blue, and green channels. In most cases, the profiles produced by the modified lcms2.h file are slightly closer to the Lindbloom values than the profiles produced by the unmodified lcms2.h file. Widegamut and CIE-RGB values are slightly farther away. In all cases the change is very small. So if you actually had the patience to read all the way through this post, does it look like there might be something in the lcms source code that is systematically introducing small rounding errors that are independent of the profile white point? Elle |
From: <mar...@li...> - 2013-09-03 07:58:01
|
Hi Elle, This is a nice finding. I have to double check the implications, but for what it seems you are proposing a value for D50 that minimizes the rounding errors on some circumstances. > So what happens if the D50 XYZ values in lcms2.h are changed to match > the iccToXml illuminant values? XYZ numbers are stored in s15.16 fixed point, so, doing a quick roundtrip test I get: cmsS15Fixed16Number xe = _cmsDoubleTo15Fixed16(cmsD50X); cmsS15Fixed16Number ye = _cmsDoubleTo15Fixed16(cmsD50Y); cmsS15Fixed16Number ze = _cmsDoubleTo15Fixed16(cmsD50Z); cmsFloat64Number x = _cms15Fixed16toDouble(xe); cmsFloat64Number y = _cms15Fixed16toDouble(ye); cmsFloat64Number z = _cms15Fixed16toDouble(ze); double dx = fabs(cmsD50X - x); double dy = fabs(cmsD50Y - y); double dz = fabs(cmsD50Z - z); printf("dX, dY, dZ = (%f %f %f)\n", dx, dy, dz); Which results in: dX, dY, dZ = (0.000003 0.000000 0.000005) Doing same with the values you propose 0.96420288, 1.0, 0.82490540 results in a perfect round trip of dx=dy=dz=0 Unfortunately I cannot change such numbers because the PCSXYZ values are defined in the ICC spec in many places, table D.5 for example. But I can bring this discussion to the ICC, and see if they see value in changing the constants. Anyway, keep in mind this only applies on matrix-shaper profiles, which are a *very reduced* subset of all available profile types. On LUT-based output profiles, using those values may probably make little difference, and since D50 is used to normalize the PCS may have other side effects. Also, giving 0.000000 or 0.000005 is a pure cosmetic question, since this is far below the noticeable difference. Regards Marti Quoting Elle Stone <l.e...@gm...>: > While creating profiles using different profile white points, I > noticed a pattern that suggests a rounding error. For example, running > the command "xicclu -ir -pl -s255 profile.icc" on the following 7 > profiles produces these results: > > Apple-CCT 100.000000 -0.002638 0.000000 > Apple-D65code 100.000000 0.000000 0.000000 perfect > > CIE-RGB-CCT 100.000000 0.000000 0.001233 > CIE-RGB-E_5454K 100.000000 0.000000 0.001233 > > Clay-CCT 100.000000 -0.002638 0.001233 > Clay-D65_old 100.000000 0.000000 0.001233 > > NTSC-CCT 100.000000 0.000000 0.001233 > NTSC-C_6774K 100.000000 0.000000 0.001233 > > SMPTE-CCT 100.000000 0.000000 -0.001233 > SMPTE-D65_old 100.000000 -0.002638 0.001233 > > sRGB-CCT 99.999410 0.002543 -0.001017 > sRGB-D65code 100.000000 0.000000 0.001233 > > Widegamut-CCT 100.000590 -0.005181 0.001017 > Widegamut-D50_lcms 100.000000 0.000000 0.001233 > > Profile white point key: > "CCT" = lcms correlated color temp; I used 6503.6 for D65. > D65code = (0.31271, 0.32912) > E_5454K = (0.333608970, 0.348572909) Robertson equations > D65_old = (0.312700, 0.329000) > C_6774K = (0.308548930, 0.324928102) Robertson equations > D50_lcms = (0.345702915, 0.358538597) > > In the profiles above, the value +/- 0.001233 shows up ten times over > a diverse set of profile white points. Including results from other > profiles, 0.002543, 0.001017 and 0.002638 also show up multiple times, > though not as frequently as 0.001233. > > For R=G=B=255, no deviation from 0 in the Lab "a" channel plus a > deviation of 0.001233 in the Lab "b" channel corresponds to a > deviation of 0.000015 (+0.001233) or 0.000016 (-0.001233) in the Z XYZ > channel (the X value deviation is 0 in either case). The values > "0.000015" and "0.000016" are important numbers when converting from > XYZ to hexadecimal: > > 0.000015 (and any smaller value), multiplied by 65535 and converted to > hex, is 0. > 0.000016, multiplied by 65535 and converted to hex, is 1. > > This might be purely coincidental, but it suggests a decimal to > hexadecimal rounding error. So I looked for a possible source of a "1 > hex unit" error and perhaps found one. The following lines are in the > "lcms2.h" file: > > // D50 XYZ normalized to Y=1.0 > #define cmsD50X 0.9642 > #define cmsD50Y 1.0 > #define cmsD50Z 0.8249 > > Using these cmsD50X and cmsD50Z values, here's the round-trip > conversion through hex: > > starting values: (0.964200000, 1.0, 0.824900000) > convert to hex: (F6D4, FFFF, D32B) > convert back to decimal: (0.964187076, 1.0, 0.824887465) > absolute difference: (0.000012924, 0.0, 0.000012535) > > According to iccToXml, for profiles generated by lcms the profile > header illuminant value is (0.964202881, 1, 0.824905396). The > corresponding round-trip conversion through hex values are: > > starting values: (0.964202881, 1.0, 0.824905396) > convert to hex: (F6D5, FFFF, D32C) > convert back to decimal: (0.824902724, 1.0, 0.964202335) > absolute difference: (0.000000546, 0.0, 0.000002672) > > Notice that the iccToXml illuminant values convert to hex and back > with a smaller error, and also the resulting hex values are larger by > 1 hex unit (F6D4->F6D5, D32B->D32C). > > So what happens if the D50 XYZ values in lcms2.h are changed to match > the iccToXml illuminant values? > > // D50 XYZ normalized to Y=1.0 > #define cmsD50X 0.96420288 //iccToXml header illuminant value > #define cmsD50Y 1.0 > #define cmsD50Z 0.82490540 //iccToXml header illuminant value > > To find out, I > *Changed the D50 values in lcms2.h to equal the header illuminant > value reported by iccToXml > *Recompiled lcms > *Recompiled my profile-making code > *Recreated all the profiles using the exact same white points as before > > Here are the new xicclu results: > > Apple-mod-CCT 100.000000 0.002638 0.000000 flipped sign > Apple-mod-D65code 100.000000 0.000000 0.000000 perfect > > CIE-RGB-mod-CCT 100.000000 0.000000 0.000000 perfect > CIE-mod-RGB-E_5454 100.000000 0.000000 0.000000 perfect > > Clay-mod-CCT 100.000000 0.000000 0.001233 improved > Clay-mod-D65_old 100.000000 0.000000 0.000000 perfect > > NTSC-mod-CCT 100.000000 0.000000 0.000000 perfect > NTSC-mod-C_6774 100.000000 0.000000 0.000000 perfect > > SMPTE-mod-CCT 100.000000 0.000000 -0.001233 no change > SMPTE-mod-D65_old 100.000000 0.000000 0.000000 perfect > > sRGB-mod-CCT 99.999410 0.002543 -0.001017 no change > sRGB-mod-D65code 100.000000 0.000000 0.000000 perfect > > Widegamut-mod-CCT 100.000590 -0.005181 0.001017 no change > Widegamut-mod-D50_lcms 100.000000 0.000000 0.000000 perfect > > I've checked many more profiles than are listed above, and the results > are 100% consistent. > > "Color balanced" isn't everything! I checked all the profiles against > the Lindbloom xyY values by calculating the sum of the absolute > differences in the x,y,Y values for the red, blue, and green channels. > In most cases, the profiles produced by the modified lcms2.h file are > slightly closer to the Lindbloom values than the profiles produced by > the unmodified lcms2.h file. Widegamut and CIE-RGB values are slightly > farther away. In all cases the change is very small. > > So if you actually had the patience to read all the way through this > post, does it look like there might be something in the lcms source > code that is systematically introducing small rounding errors that are > independent of the profile white point? > > Elle |
From: Elle S. <l.e...@gm...> - 2013-09-03 14:29:27
|
Hi Marti, >> So what happens if the D50 XYZ values in lcms2.h are changed to match >> the iccToXml illuminant values? A possibly related question/observation: How is it that the profile header illuminant values are so resistant to changes in the lcms2.h D50 values? I tried several variations on the default (0.9642, 1.0, 0.8249) values, and began to think that as far as the resulting header illuminant values go, perhaps it didn't make any difference, that perhaps the header illuminant values were hard-coded somewhere, because iccToXml always showed (0.96420288, 1.00000000, 0.82490540). But recompiling lcms with D50=(1.0,1.0,1.0) resulted in iccToXml showing the header illuminant as (1.00000000, 1.00000000, 1.00000000). So the D50 value in lcms2.h does affect the resulting header illuminant. But it takes a bit of shifting away from the standard D50 values! > Anyway, keep in mind this only applies on > matrix-shaper profiles, which are a *very reduced* subset of all > available profile types. On LUT-based output profiles, using those > values may probably make little difference, and since D50 is used to > normalize the PCS may have other side effects. My apologies for being so focussed on matrix profiles. But so far the open source RGB working space profiles are all matrix profiles. It seems color.org is introducing LUT versions of standard V2 matrix working space profiles, but I've never used them. Occasionally I use device LUT profiles, but those are made with Argyllcms (camera, monitor) or some third party (commercial printer). > Also, giving 0.000000 > or 0.000005 is a pure cosmetic question, since this is far below the > noticeable difference. For most people and most purposes and especially with 8-bit images, I agree the difference is so small as to not be noticed or even exist for 8-bit images. But if you work with high bit depth images, assign the lcms built-in sRGB profile to an image, convert to a working space that really is color-balanced (or vice versa) and do a fairly extreme saturation (e.g with channel mixer or by converting to Lab and playing with the ab channels or by moving the levels black point up quite a bit), nominally neutral colors will shift colors (I've tried, it happens). People who oversaturate their images might not care that gray and white now have a color cast. But then again, they might, and they might just be using the oversaturated layer as a means to some further editing goal. Also, for those people who make a new camera profile for every shot, perhaps shooting advertisements or artwork, color balancing is critical and a working space that isn't color-balanced might be another obstacle in their path toward perfect color control. I posted my profile-making code to my website in case anyone wants to check whether there are errors in the code: http://ninedegreesbelow.com/photography/lcms-make-icc-profiles.html Best regards, Elle |