1 /*
2     File:       iccRoundTrip.cpp
3 
4     Contains:   Console app to parse and display profile round-trip statistics
5 
6     Version:    V1
7 
8     Copyright:  � see below
9 */
10 
11 /*
12  * The ICC Software License, Version 0.2
13  *
14  *
15  * Copyright (c) 2003-2010 The International Color Consortium. All rights
16  * reserved.
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  *
22  * 1. Redistributions of source code must retain the above copyright
23  *    notice, this list of conditions and the following disclaimer.
24  *
25  * 2. Redistributions in binary form must reproduce the above copyright
26  *    notice, this list of conditions and the following disclaimer in
27  *    the documentation and/or other materials provided with the
28  *    distribution.
29  *
30  * 3. In the absence of prior written permission, the names "ICC" and "The
31  *    International Color Consortium" must not be used to imply that the
32  *    ICC organization endorses or promotes products derived from this
33  *    software.
34  *
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR
40  * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the The International Color Consortium.
52  *
53  *
54  * Membership in the ICC is encouraged when this software is used for
55  * commercial purposes.
56  *
57  *
58  * For more information on The International Color Consortium, please
59  * see <http://www.color.org/>.
60  *
61  *
62  */
63 
64 //////////////////////////////////////////////////////////////////////
65 // HISTORY:
66 //
67 // -Initial implementation by Max Derhak 10-1-2007
68 //
69 //////////////////////////////////////////////////////////////////////
70 
71 
72 #include <stdio.h>
73 #include <math.h>
74 #include "IccUtil.h"
75 #include "IccEval.h"
76 #include "IccPrmg.h"
77 
78 class CIccMinMaxEval : public CIccEvalCompare
79 {
80 public:
81   CIccMinMaxEval();
82 
83   void Compare(icFloatNumber *pixel, icFloatNumber *deviceLab, icFloatNumber *lab1, icFloatNumber *lab2);
84 
GetMean1()85   icFloatNumber GetMean1() { return sum1 / num1; }
GetMean2()86   icFloatNumber GetMean2() { return sum2 / num2; }
87 
88   icFloatNumber minDE1, minDE2;
89   icFloatNumber maxDE1, maxDE2;
90 
91   icFloatNumber maxLab1[3], maxLab2[3];
92 
93 protected:
94 
95   icFloatNumber sum1, sum2;
96   icFloatNumber num1, num2;
97 };
98 
CIccMinMaxEval()99 CIccMinMaxEval::CIccMinMaxEval()
100 {
101   minDE1 = minDE2 = 10000;
102   maxDE1 = maxDE2 = -1;
103   sum1 = sum2 = 0;
104   num1 = num2 = 0;
105 
106   memset(&maxLab1[0], 0, sizeof(maxLab1));
107   memset(&maxLab2[0], 0, sizeof(maxLab2));
108 }
109 
Compare(icFloatNumber * pixel,icFloatNumber * deviceLab,icFloatNumber * lab1,icFloatNumber * lab2)110 void CIccMinMaxEval::Compare(icFloatNumber *pixel, icFloatNumber *deviceLab, icFloatNumber *lab1, icFloatNumber *lab2)
111 {
112   icFloatNumber DE1 = icDeltaE(deviceLab, lab1);
113   icFloatNumber DE2 = icDeltaE(lab1, lab2);
114 
115   if (DE1<minDE1) {
116     minDE1 = DE1;
117   }
118 
119   if (DE1>maxDE1) {
120     maxDE1 = DE1;
121     memcpy(&maxLab1[0], deviceLab, sizeof(maxLab1));
122   }
123 
124   if (DE2<minDE2) {
125     minDE2 = DE2;
126   }
127 
128   if (DE2>maxDE2) {
129     maxDE2 = DE2;
130     memcpy(&maxLab2[0], deviceLab, sizeof(maxLab2));
131   }
132 
133   sum1 += DE1;
134   num1 += 1.0;
135 
136   sum2 += DE2;
137   num2 += 1.0;
138 }
139 
140 
main(int argc,char * argv[])141 int main(int argc, char* argv[])
142 {
143   int nArg = 1;
144 
145   if (argc<=1) {
146     printf("Usage: iccRoundTrip profile {rendering_intent=1 {use_mpe=0}}\n");
147     printf("  where rendering_intent is (0=perceptual, 1=relative, 2=saturation, 3=absolute)\n");
148     return -1;
149   }
150 
151   icRenderingIntent nIntent = icRelativeColorimetric;
152   int nUseMPE = 0;
153 
154   if (argc>2) {
155     nIntent = (icRenderingIntent)atoi(argv[2]);
156     if (argc>3) {
157       nUseMPE = atoi(argv[3]);
158     }
159   }
160 
161   CIccMinMaxEval eval;
162 
163   icStatusCMM stat = eval.EvaluateProfile(argv[1], 0, nIntent, icInterpLinear, (nUseMPE!=0));
164 
165   if (stat!=icCmmStatOk) {
166     printf("Unable to perform round trip on '%s'\n", argv[1]);
167     return -1;
168   }
169 
170   CIccPRMG prmg;
171 
172   stat = prmg.EvaluateProfile(argv[1], nIntent, icInterpLinear, (nUseMPE!=0));
173 
174   if (stat!=icCmmStatOk) {
175     printf("Unable to perform PRMG analysis on '%s'\n", argv[1]);
176     return -1;
177   }
178 
179   CIccInfo info;
180 
181   printf("Profile:          '%s'\n", argv[1]);
182   printf("Rendering Intent: %s\n", info.GetRenderingIntentName(nIntent));
183   printf("Specified Gamut:  %s\n", prmg.m_bPrmgImplied ? "Perceptual Reference Medium Gamut" : "Not Specified");
184 
185   printf("\nRound Trip 1\n");
186   printf(  "------------\n");
187   printf("Min DeltaE:    %8.2" ICFLOATSFX "\n", eval.minDE1);
188   printf("Mean DeltaE:   %8.2" ICFLOATSFX "\n", eval.GetMean1());
189   printf("Max DeltaE:    %8.2" ICFLOATSFX "\n\n", eval.maxDE1);
190 
191   printf("Max L, a, b:   " ICFLOATFMT ", " ICFLOATFMT ", " ICFLOATFMT "\n", eval.maxLab1[0], eval.maxLab1[1], eval.maxLab1[2]);
192 
193   printf("\nRound Trip 2\n");
194   printf(  "------------\n");
195   printf("Min DeltaE:    %8.2" ICFLOATSFX "\n", eval.minDE2);
196   printf("Mean DeltaE:   %8.2" ICFLOATSFX "\n", eval.GetMean2());
197   printf("Max DeltaE:    %8.2" ICFLOATSFX "\n\n", eval.maxDE2);
198 
199   printf("Max L, a, b:   " ICFLOATFMT ", " ICFLOATFMT ", " ICFLOATFMT "\n", eval.maxLab2[0], eval.maxLab2[1], eval.maxLab2[2]);
200 
201   if (prmg.m_nTotal) {
202     printf("\nPRMG Interoperability - Round Trip Results\n");
203     printf(  "------------------------------------------------------\n");
204 
205     printf("DE <= 1.0 (%8u): %5.1f%%\n", prmg.m_nDE1, (float)prmg.m_nDE1/(float)prmg.m_nTotal*100.0);
206     printf("DE <= 2.0 (%8u): %5.1f%%\n", prmg.m_nDE2, (float)prmg.m_nDE2/(float)prmg.m_nTotal*100.0);
207     printf("DE <= 3.0 (%8u): %5.1f%%\n", prmg.m_nDE3, (float)prmg.m_nDE3/(float)prmg.m_nTotal*100.0);
208     printf("DE <= 5.0 (%8u): %5.1f%%\n", prmg.m_nDE5, (float)prmg.m_nDE5/(float)prmg.m_nTotal*100.0);
209     printf("DE <=10.0 (%8u): %5.1f%%\n", prmg.m_nDE10, (float)prmg.m_nDE10/(float)prmg.m_nTotal*100.0);
210     printf("Total     (%8u)\n", prmg.m_nTotal);
211   }
212   return 0;
213 }
214 
215