Summary: | CIE color rendering errors | ||
---|---|---|---|
Product: | Ghostscript | Reporter: | Jack Moffitt <jack> |
Component: | PS Interpreter | Assignee: | L. Peter Deutsch <ghost> |
Status: | NOTIFIED FIXED | ||
Severity: | normal | ||
Priority: | P2 | ||
Version: | master | ||
Hardware: | All | ||
OS: | All | ||
Customer: | Word Size: | --- |
Description
Jack Moffitt
2001-09-27 22:36:00 UTC
Comment originally by loewenstein@users.sourceforge.net Logged In: YES user_id=335045 This is a duplicate of two attempts at submitting the bug by e-mail, with no response or acknowledgment. Comment originally by lpd@users.sourceforge.net Logged In: YES user_id=8861 I've verified, using our PostScript emulation of the CIE rendering algorithms (lib/docie.ps), that the combined transforms are indeed the identity transform. I've also verified, using -ZC, that the C code (presumably some combination of gscie.c, gscrd.c, and gsciemap.c) is not producing the correct result. -ZC shows that the first intermediate result ,after the PQR stage, is already fairly far off the correct values. I will investigate further. Comment originally by lpd@users.sourceforge.net Logged In: YES user_id=8861 The problem is a numerical sensitivity that arises when any intermediate value in the CIE pipeline is close to zero (as it is in this case for the XYZ values: all 3 values of the first color triple, and the Z value of the 2nd and 3rd color triple, are less than .01). Each cache for sampled function values has 512 entries, so TransformPQR, which has a range of [-0.5 .. 2.0], is only sampled at intervals of approximately 0.005. The code doesn't interpolate between cached values at intermediate steps, since it's computationally expensive and almost never improves the quality of the result. Consequently, if an intermediate value is less than 0.01, the result of looking it up in the cache may be off by a large factor from the correct value. The code does provide a compile-time option to interpolate intermediate cached values (CIE_INTERPOLATE_INTERMEDIATE in gscie.h). When I enabled this option, the output RGB values were correct -- they matched the exact (docie.ps) values to within 2%. I believe a reasonable approach to this problem is to conditionally use interpolation when it would make a difference -- namely when the values in the adjoining cache entries differ by more than, say, 5%. I believe this test is still worth making, since interpolation adds an additional 18 floating multiplies, 27 floating point add/subtracts, and 9 floating point floor operations to each stage of the pipeline that is actually used (2 such stages in the sRGB case). In fact, the sensitive regions can be identified when the caches are built, so the check for whether the lookup value is in a sensitive region can be a simple range test. Since this is a non-trivial change, I'll ask the GS developer forum for opinions before proceeding further. Comment originally by loewenstein@users.sourceforge.net Logged In: YES user_id=335045 I must say that the problem is pretty much what I guessed from the symptoms and reading the comments in the C code. I would recommend some additional changes. Firstly, check for equality of the colorspace and rendering blackpoints and whitepoints. If they are both equal, eliminate the PQR calculation altogether as allowed by the PostScript specification. Given that you are allowing some error in the color rendering, this could be an approximate equality check. (I have already communicated this privately, with some more crazy suggestions!). Secondly, refine RangePQR using the knowledge of The range of X, Y and Z. You are basing the interval in the cache on the range specified in the PostScript rendering dictionary (in this case RangePQR). This range is intended to indicate a valid range for the TransformPQR function arguments (for the function to produce valid results); it is not an indication of the range within which the arguments will actually fall. It is straightforward to calculate from the range of X, Y and Z (in this color space each component ranges between the whitepoint and the blackpoint). This range, in the format of RangePQR is: [-0.1757646 1.11719255 -0.7130651 1.7534663 -0.0685 1.15820885] You will notice that the only limit that can be exceeded is the lower limit of Q, which is specified as -0.5 (I am virtually certain this is a bug in the rendering specification). Ghostscript should use its knowledge of the range of X, Y, and Z to calculate the possible range of P, Q and R, so that the caching interval can be minimized. The user should be free to code arbitrarily large ranges should no clipping to a range be desired. Ghostscript should do this for all ranges and functions in the rendering and colorspace dictionaries. Doing a perfect job is a potentially non-linear programming problem, but it should be sufficient for this application to propagate the range through just one matrix multiplication or function application at a time (this gives a somewhat pessimistic, but safe result). Comment originally by lpd@users.sourceforge.net Logged In: YES user_id=8861 Your suggestions are good, but they wouldn't help this particular problem. 1. Check for equality of white/black points: yes, Ghostscript should definitely do that. However, for this particular color space and rendering dictionary, the code already figures out that TransformPQR is the identity, simply by looking at the sampled values, and optimizes it out. 2. Refine RangePQR based on possible ranges of XYZ: actually, Ghostscript already does exactly what you describe in some places in the CIE code, but it should do it in more. In this situation, however, neither of these things (would) help. With TransformPQR optimized out, the values after the MatrixLMN(Encode) step are very close to the correct values (within 1% or so), but the N value is so close to 0 that the lack of interpolation results in wildly incorrect values when looking up this values in the sampled cache for the EncodeLMN procedure: specifically, the N value is approximately 0.00212, 0.00242, and 0.00698 in the 3 test cases. I think selective interpolation is still going to be needed. Comment originally by lpd@users.sourceforge.net Logged In: YES user_id=8861 Code for doing selective interpolation has been tested and is being reviewed. Comment originally by lpd@users.sourceforge.net Logged In: YES user_id=8861 The selective interpolation fix has been checked in. |