## lcms-user

 [Lcms-user] Re: Tetrahedral Interpolation From: - 2002-11-22 09:04:20 ```Hi, Since your question is quite interesting, I've also forwarded to mailing list. Hope this is not a problem to you. > I have been looking at your LCMS 1.09 code, and I have a question > concerning your interpolation routines, specifically the tetrahedral > interpolation routine using the Sakamoto algorithm. I have an > application that requires the use of such an algorithm, and (I hope you > don't mind) I was going to borrow this routine from your code. The > function in question is cmsTetrahedralInterp16(). Of course you can borrow any routine, this is the goal of open source, at least for me. And what you are asking for, is a very frequent question. So frequent, that I did promote this part to lcms API in ver 1.09 You can use the low level routines, or, and I will recommend this latter, use the LUT interface to accomplish same. The LUT interface is easy to use and allows also to add pre/post linearization, and if you plan to convert RGB -> XYZ the prelinearization part is really a must. It can increase a lot the precission whilst lowering the amount of data (CLUT points) required. Then, here are the functions needed. More details in lcmsapi.txt LPLUT cmsAllocLUT(void); LPLUT cmsAllocLinearTable(LPLUT Lut, LPGAMMATABLE Tables[], int nTable); LPLUT cmsAlloc3DGrid(LPLUT Lut, int clutPoints, int inputChan, int outputChan); int cmsSample3DGrid(LPLUT Lut, _cmsSAMPLER Sampler, LPVOID Cargo, DWORD dwFlags); void cmsFreeLUT(LPLUT Lut); void cmsEvalLUT(LPLUT Lut, WORD In[], WORD Out[]); The typical procedure is: - First you allocate an empty LUT by calling cmsAllocLUT() - Then you add whatsever linearization by means of cmsAllocLinearTable() - Then you declare your multidimensional table size using cmsAlloc3DGrid() - Finally, you fill the table by using a callback function and cmsSample3DGrid() This gives to you a ready to use LUT. You can then evaluate values across this LUT by using cmsEvalLUT(). Where done, use cmsFreeLUT() to get rid of the memory. A couple of comments. If you plan to use RGB -> XYZ, you should use a prelinearization table for decoupling gamma of RGB space. You could use cmsBuildGamma() to create such curve. For example, sRGB to XYZ needs a gamma curve of approximately gamma=2.2 Avoiding this table will result in quantization errors due to "impedance" mismatch between both spaces, XYZ has an aparent gamma of 1.0! You can use then lcms as a static library and only the needed routines will got linked. I tried to adjust granularity of library to allow very lightweight overhead in such cases. Ok, anyway I will try to answer about the implementation details as well. > Input[] appears to be the input values, which in my case would be the > X, Y and Z (input) values I enter to find the corresponding RGB > (output) values. Output[] appears to be the result of the > interpolation; the R, G, and B values the function identifies as > corresponding to my input X, Y and Z values. Correct? Yes, that is. > LutTable[] appears to be used by the function DENS, but I am not sure > about the pointers to Domain and nOutputs. I am assuming that nOutputs > is the total number of output channels (in my case 3)? But, I am not > sure about Domain; does that represent the last count in my CLUT (in my > case 728)? You can fill the L6PARAMS struct by calling cmsCalcCLUT16Params(int nSamples, int InputChan, int OutputChan, LPL16PARAMS p); You need to specify the cube (or hypercube in case of CMYK) side, and the number of input/output channels. In your case I assume 729 means a cube of 9 gridponts in each side. L16PARAMS params; cmsCalcCLUT16Params(9, 3, 3, ¶ms); ... cmsTetrahedralInterp16(Input[], Output[], Dens[], ¶ms); But again, please note that 9 points is not enough without linearization table. For my testings, you need at least 48!!! points to decouple gamma. But a simple 6 points prelinearization and 6 points on grid gives same accurancy as 48 points, so this step is really required. Hope this helps, Martí Maria The little cms project http://www.littlecms.com marti@... ----- Original Message ----- From: "Christopher Brown" Sent: Friday, November 22, 2002 12:27 AM Subject: Tetrahedral Interpolation > Hello Marti - > > I have been looking at your LCMS 1.09 code, and I have a question > concerning your interpolation routines, specifically the tetrahedral > interpolation routine using the Sakamoto algorithm. I have an > application that requires the use of such an algorithm, and (I hope you > don't mind) I was going to borrow this routine from your code. The > function in question is cmsTetrahedralInterp16(). > > Basically, what I have is a CLUT comprised of 729 RGB values with > corresponding XYZ values. The idea would be to take any given set of > XYZ values, and locate the appropriate corresponding RGB values, based > on the 729 data points contained in my CLUT. The values in the CLUT are > currently 16-bits each in the range 0 to 65535. > > Now, I think I understand basically what this routine is doing. > However, I just want to verify a few things. There appear to be four > values passed to the function: Input[], Output[], LutTable[] and > LPL16PARAMS. > > Input[] appears to be the input values, which in my case would be the > X, Y and Z (input) values I enter to find the corresponding RGB > (output) values. Output[] appears to be the result of the > interpolation; the R, G, and B values the function identifies as > corresponding to my input X, Y and Z values. Correct? > > LutTable[] appears to be used by the function DENS, but I am not sure > about the pointers to Domain and nOutputs. I am assuming that nOutputs > is the total number of output channels (in my case 3)? But, I am not > sure about Domain; does that represent the last count in my CLUT (in my > case 728)? > > Based on this, please let me know if the following is correct: > > Domain = 728 (last count in CLUT, 0 - 728) > clutPoints = 729 (Domain + 1) > nOutputs = 3 > TotalOut = nOutputs > Input[] = Input values X, Y and Z > Output[] = Output values R, G and B > px = (X * 728) / 65535 > py = (Y * 728) / 65535 > pz = (Z * 728) / 65535 > > LutTable[] I am not entirely sure about. But, I am assuming that, if > RGB is my output, then c1 would look at R values, c2 at G values and c3 > at B values? This is the part that I am not clear on. Finally, what is > LPL16PARAMS? > > I apologize for asking so many questions; I want to thank you in > advance for any help you can give. Do you happen to have any > information regarding the Sakamoto algorithm, or can you point me to > any papers written on the topic? Also, what is your feeling as to how > this routine compares with your other tetrahedral and trilinear > interpolation routines, in terms of speed and accuracy? How does it > compare to the Catmull-Rom interpolation (that is remarked out in your > code)? > > Thanks again for all your help! > > Kind Regards, > > - Chris Brown > > > ```