1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4 //
5 //
6 //                       License Agreement
7 //              For Open Source Computer Vision Library
8 //
9 // Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved.
10 // Third party copyrights are property of their respective owners.
11 //
12 // Licensed under the Apache License, Version 2.0 (the "License");
13 // you may not use this file except in compliance with the License.
14 // You may obtain a copy of the License at
15 //
16 //             http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the License is distributed on an "AS IS" BASIS,
20 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 // See the License for the specific language governing permissions and
22 // limitations under the License.
23 //
24 // Author: Longbu Wang <wanglongbu@huawei.com.com>
25 //         Jinheng Zhang <zhangjinheng1@huawei.com>
26 //         Chenqi Shan <shanchenqi@huawei.com>
27 
28 #include "color.hpp"
29 
30 namespace cv {
31 namespace ccm {
Color()32 Color::Color()
33     : colors(Mat())
34     , cs(*std::make_shared<ColorSpace>())
35 {}
Color(Mat colors_,enum COLOR_SPACE cs_)36 Color::Color(Mat colors_, enum COLOR_SPACE cs_)
37     : colors(colors_)
38     , cs(*GetCS::getInstance().get_cs(cs_))
39 {}
40 
Color(Mat colors_,const ColorSpace & cs_,Mat colored_)41 Color::Color(Mat colors_, const ColorSpace& cs_, Mat colored_)
42     : colors(colors_)
43     , cs(cs_)
44     , colored(colored_)
45 {
46     grays = ~colored;
47 }
Color(Mat colors_,enum COLOR_SPACE cs_,Mat colored_)48 Color::Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_)
49     : colors(colors_)
50     , cs(*GetCS::getInstance().get_cs(cs_))
51     , colored(colored_)
52 {
53     grays = ~colored;
54 }
55 
Color(Mat colors_,const ColorSpace & cs_)56 Color::Color(Mat colors_, const ColorSpace& cs_)
57     : colors(colors_)
58     , cs(cs_)
59 {}
60 
to(const ColorSpace & other,CAM method,bool save)61 Color Color::to(const ColorSpace& other, CAM method, bool save)
62 {
63     if (history.count(other) == 1)
64     {
65         return *history[other];
66     }
67     if (cs.relate(other))
68     {
69         return Color(cs.relation(other).run(colors), other);
70     }
71     Operations ops;
72     ops.add(cs.to).add(XYZ(cs.io).cam(other.io, method)).add(other.from);
73     std::shared_ptr<Color> color(new Color(ops.run(colors), other));
74     if (save)
75     {
76         history[other] = color;
77     }
78     return *color;
79 }
to(COLOR_SPACE other,CAM method,bool save)80 Color Color::to(COLOR_SPACE other, CAM method, bool save)
81 {
82     return to(*GetCS::getInstance().get_cs(other), method, save);
83 }
84 
channel(Mat m,int i)85 Mat Color::channel(Mat m, int i)
86 {
87     Mat dchannels[3];
88     split(m, dchannels);
89     return dchannels[i];
90 }
91 
toGray(IO io,CAM method,bool save)92 Mat Color::toGray(IO io, CAM method, bool save)
93 {
94     XYZ xyz = *XYZ::get(io);
95     return channel(this->to(xyz, method, save).colors, 1);
96 }
97 
toLuminant(IO io,CAM method,bool save)98 Mat Color::toLuminant(IO io, CAM method, bool save)
99 {
100     Lab lab = *Lab::get(io);
101     return channel(this->to(lab, method, save).colors, 0);
102 }
103 
diff(Color & other,DISTANCE_TYPE method)104 Mat Color::diff(Color& other, DISTANCE_TYPE method)
105 {
106     return diff(other, cs.io, method);
107 }
108 
diff(Color & other,IO io,DISTANCE_TYPE method)109 Mat Color::diff(Color& other, IO io, DISTANCE_TYPE method)
110 {
111     Lab lab = *Lab::get(io);
112     switch (method)
113     {
114     case cv::ccm::DISTANCE_CIE76:
115     case cv::ccm::DISTANCE_CIE94_GRAPHIC_ARTS:
116     case cv::ccm::DISTANCE_CIE94_TEXTILES:
117     case cv::ccm::DISTANCE_CIE2000:
118     case cv::ccm::DISTANCE_CMC_1TO1:
119     case cv::ccm::DISTANCE_CMC_2TO1:
120         return distance(to(lab).colors, other.to(lab).colors, method);
121     case cv::ccm::DISTANCE_RGB:
122         return distance(to(*cs.nl).colors, other.to(*cs.nl).colors, method);
123     case cv::ccm::DISTANCE_RGBL:
124         return distance(to(*cs.l).colors, other.to(*cs.l).colors, method);
125     default:
126         CV_Error(Error::StsBadArg, "Wrong method!" );
127         break;
128     }
129 }
130 
getGray(double JDN)131 void Color::getGray(double JDN)
132 {
133     if (!grays.empty())
134     {
135         return;
136     }
137     Mat lab = to(COLOR_SPACE_Lab_D65_2).colors;
138     Mat gray(colors.size(), colors.type());
139     int fromto[] = { 0, 0, -1, 1, -1, 2 };
140     mixChannels(&lab, 1, &gray, 1, fromto, 3);
141     Mat d = distance(lab, gray, DISTANCE_CIE2000);
142     this->grays = d < JDN;
143     this->colored = ~grays;
144 }
145 
operator [](Mat mask)146 Color Color::operator[](Mat mask)
147 {
148     return Color(maskCopyTo(colors, mask), cs);
149 }
150 
getColorChecker(const double * checker,int row)151 Mat GetColor::getColorChecker(const double* checker, int row)
152 {
153     Mat res(row, 1, CV_64FC3);
154     for (int i = 0; i < row; ++i)
155     {
156         res.at<Vec3d>(i, 0) = Vec3d(checker[3 * i], checker[3 * i + 1], checker[3 * i + 2]);
157     }
158     return res;
159 }
160 
getColorCheckerMASK(const uchar * checker,int row)161 Mat GetColor::getColorCheckerMASK(const uchar* checker, int row)
162 {
163     Mat res(row, 1, CV_8U);
164     for (int i = 0; i < row; ++i)
165     {
166         res.at<uchar>(i, 0) = checker[i];
167     }
168     return res;
169 }
170 
getColor(CONST_COLOR const_color)171 std::shared_ptr<Color> GetColor::getColor(CONST_COLOR const_color)
172 {
173 
174     /** @brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls
175            see Miscellaneous.md for details.
176 */
177     static const double ColorChecker2005_LAB_D50_2[24][3] = { { 37.986, 13.555, 14.059 },
178         { 65.711, 18.13, 17.81 },
179         { 49.927, -4.88, -21.925 },
180         { 43.139, -13.095, 21.905 },
181         { 55.112, 8.844, -25.399 },
182         { 70.719, -33.397, -0.199 },
183         { 62.661, 36.067, 57.096 },
184         { 40.02, 10.41, -45.964 },
185         { 51.124, 48.239, 16.248 },
186         { 30.325, 22.976, -21.587 },
187         { 72.532, -23.709, 57.255 },
188         { 71.941, 19.363, 67.857 },
189         { 28.778, 14.179, -50.297 },
190         { 55.261, -38.342, 31.37 },
191         { 42.101, 53.378, 28.19 },
192         { 81.733, 4.039, 79.819 },
193         { 51.935, 49.986, -14.574 },
194         { 51.038, -28.631, -28.638 },
195         { 96.539, -0.425, 1.186 },
196         { 81.257, -0.638, -0.335 },
197         { 66.766, -0.734, -0.504 },
198         { 50.867, -0.153, -0.27 },
199         { 35.656, -0.421, -1.231 },
200         { 20.461, -0.079, -0.973 } };
201 
202     static const uchar ColorChecker2005_COLORED_MASK[24] = { 1, 1, 1, 1, 1, 1,
203         1, 1, 1, 1, 1, 1,
204         1, 1, 1, 1, 1, 1,
205         0, 0, 0, 0, 0, 0 };
206     static const double Vinyl_LAB_D50_2[18][3] = { { 100, 0.00520000001, -0.0104 },
207         { 73.0833969, -0.819999993, -2.02099991 },
208         { 62.493, 0.425999999, -2.23099995 },
209         { 50.4640007, 0.446999997, -2.32399988 },
210         { 37.7970009, 0.0359999985, -1.29700005 },
211         { 0, 0, 0 },
212         { 51.5880013, 73.5179977, 51.5690002 },
213         { 93.6989975, -15.7340002, 91.9420013 },
214         { 69.4079971, -46.5940018, 50.4869995 },
215         { 66.61000060000001, -13.6789999, -43.1720009 },
216         { 11.7110004, 16.9799995, -37.1759987 },
217         { 51.973999, 81.9440002, -8.40699959 },
218         { 40.5489998, 50.4399986, 24.8490009 },
219         { 60.8160019, 26.0690002, 49.4420013 },
220         { 52.2529984, -19.9500008, -23.9960003 },
221         { 51.2859993, 48.4700012, -15.0579996 },
222         { 68.70700069999999, 12.2959995, 16.2129993 },
223         { 63.6839981, 10.2930002, 16.7639999 } };
224     static const uchar Vinyl_COLORED_MASK[18] = { 0, 0, 0, 0, 0, 0,
225         1, 1, 1, 1, 1, 1,
226         1, 1, 1, 1, 1, 1 };
227     static const double DigitalSG_LAB_D50_2[140][3] = { { 96.55, -0.91, 0.57 },
228         { 6.43, -0.06, -0.41 },
229         { 49.7, -0.18, 0.03 },
230         { 96.5, -0.89, 0.59 },
231         { 6.5, -0.06, -0.44 },
232         { 49.66, -0.2, 0.01 },
233         { 96.52, -0.91, 0.58 },
234         { 6.49, -0.02, -0.28 },
235         { 49.72, -0.2, 0.04 },
236         { 96.43, -0.91, 0.67 },
237         { 49.72, -0.19, 0 },
238         { 32.6, 51.58, -10.85 },
239         { 60.75, 26.22, -18.6 },
240         { 28.69, 48.28, -39 },
241         { 49.38, -15.43, -48.48 },
242         { 60.63, -30.77, -26.23 },
243         { 19.29, -26.37, -6.15 },
244         { 60.15, -41.77, -12.6 },
245         { 21.42, 1.67, 8.79 },
246         { 49.69, -0.2, 0.01 },
247         { 6.5, -0.03, -0.67 },
248         { 21.82, 17.33, -18.35 },
249         { 41.53, 18.48, -37.26 },
250         { 19.99, -0.16, -36.29 },
251         { 60.16, -18.45, -31.42 },
252         { 19.94, -17.92, -20.96 },
253         { 60.68, -6.05, -32.81 },
254         { 50.81, -49.8, -9.63 },
255         { 60.65, -39.77, 20.76 },
256         { 6.53, -0.03, -0.43 },
257         { 96.56, -0.91, 0.59 },
258         { 84.19, -1.95, -8.23 },
259         { 84.75, 14.55, 0.23 },
260         { 84.87, -19.07, -0.82 },
261         { 85.15, 13.48, 6.82 },
262         { 84.17, -10.45, 26.78 },
263         { 61.74, 31.06, 36.42 },
264         { 64.37, 20.82, 18.92 },
265         { 50.4, -53.22, 14.62 },
266         { 96.51, -0.89, 0.65 },
267         { 49.74, -0.19, 0.03 },
268         { 31.91, 18.62, 21.99 },
269         { 60.74, 38.66, 70.97 },
270         { 19.35, 22.23, -58.86 },
271         { 96.52, -0.91, 0.62 },
272         { 6.66, 0, -0.3 },
273         { 76.51, 20.81, 22.72 },
274         { 72.79, 29.15, 24.18 },
275         { 22.33, -20.7, 5.75 },
276         { 49.7, -0.19, 0.01 },
277         { 6.53, -0.05, -0.61 },
278         { 63.42, 20.19, 19.22 },
279         { 34.94, 11.64, -50.7 },
280         { 52.03, -44.15, 39.04 },
281         { 79.43, 0.29, -0.17 },
282         { 30.67, -0.14, -0.53 },
283         { 63.6, 14.44, 26.07 },
284         { 64.37, 14.5, 17.05 },
285         { 60.01, -44.33, 8.49 },
286         { 6.63, -0.01, -0.47 },
287         { 96.56, -0.93, 0.59 },
288         { 46.37, -5.09, -24.46 },
289         { 47.08, 52.97, 20.49 },
290         { 36.04, 64.92, 38.51 },
291         { 65.05, 0, -0.32 },
292         { 40.14, -0.19, -0.38 },
293         { 43.77, 16.46, 27.12 },
294         { 64.39, 17, 16.59 },
295         { 60.79, -29.74, 41.5 },
296         { 96.48, -0.89, 0.64 },
297         { 49.75, -0.21, 0.01 },
298         { 38.18, -16.99, 30.87 },
299         { 21.31, 29.14, -27.51 },
300         { 80.57, 3.85, 89.61 },
301         { 49.71, -0.2, 0.03 },
302         { 60.27, 0.08, -0.41 },
303         { 67.34, 14.45, 16.9 },
304         { 64.69, 16.95, 18.57 },
305         { 51.12, -49.31, 44.41 },
306         { 49.7, -0.2, 0.02 },
307         { 6.67, -0.05, -0.64 },
308         { 51.56, 9.16, -26.88 },
309         { 70.83, -24.26, 64.77 },
310         { 48.06, 55.33, -15.61 },
311         { 35.26, -0.09, -0.24 },
312         { 75.16, 0.25, -0.2 },
313         { 44.54, 26.27, 38.93 },
314         { 35.91, 16.59, 26.46 },
315         { 61.49, -52.73, 47.3 },
316         { 6.59, -0.05, -0.5 },
317         { 96.58, -0.9, 0.61 },
318         { 68.93, -34.58, -0.34 },
319         { 69.65, 20.09, 78.57 },
320         { 47.79, -33.18, -30.21 },
321         { 15.94, -0.42, -1.2 },
322         { 89.02, -0.36, -0.48 },
323         { 63.43, 25.44, 26.25 },
324         { 65.75, 22.06, 27.82 },
325         { 61.47, 17.1, 50.72 },
326         { 96.53, -0.89, 0.66 },
327         { 49.79, -0.2, 0.03 },
328         { 85.17, 10.89, 17.26 },
329         { 89.74, -16.52, 6.19 },
330         { 84.55, 5.07, -6.12 },
331         { 84.02, -13.87, -8.72 },
332         { 70.76, 0.07, -0.35 },
333         { 45.59, -0.05, 0.23 },
334         { 20.3, 0.07, -0.32 },
335         { 61.79, -13.41, 55.42 },
336         { 49.72, -0.19, 0.02 },
337         { 6.77, -0.05, -0.44 },
338         { 21.85, 34.37, 7.83 },
339         { 42.66, 67.43, 48.42 },
340         { 60.33, 36.56, 3.56 },
341         { 61.22, 36.61, 17.32 },
342         { 62.07, 52.8, 77.14 },
343         { 72.42, -9.82, 89.66 },
344         { 62.03, 3.53, 57.01 },
345         { 71.95, -27.34, 73.69 },
346         { 6.59, -0.04, -0.45 },
347         { 49.77, -0.19, 0.04 },
348         { 41.84, 62.05, 10.01 },
349         { 19.78, 29.16, -7.85 },
350         { 39.56, 65.98, 33.71 },
351         { 52.39, 68.33, 47.84 },
352         { 81.23, 24.12, 87.51 },
353         { 81.8, 6.78, 95.75 },
354         { 71.72, -16.23, 76.28 },
355         { 20.31, 14.45, 16.74 },
356         { 49.68, -0.19, 0.05 },
357         { 96.48, -0.88, 0.68 },
358         { 49.69, -0.18, 0.03 },
359         { 6.39, -0.04, -0.33 },
360         { 96.54, -0.9, 0.67 },
361         { 49.72, -0.18, 0.05 },
362         { 6.49, -0.03, -0.41 },
363         { 96.51, -0.9, 0.69 },
364         { 49.7, -0.19, 0.07 },
365         { 6.47, 0, -0.38 },
366         { 96.46, -0.89, 0.7 } };
367 
368     switch (const_color)
369     {
370 
371     case cv::ccm::COLORCHECKER_Macbeth:
372     {
373         Mat ColorChecker2005_LAB_D50_2_ = GetColor::getColorChecker(*ColorChecker2005_LAB_D50_2, 24);
374         Mat ColorChecker2005_COLORED_MASK_ = GetColor::getColorCheckerMASK(ColorChecker2005_COLORED_MASK, 24);
375         std::shared_ptr<Color> Macbeth_D50_2 = std::make_shared<Color>(ColorChecker2005_LAB_D50_2_, COLOR_SPACE_Lab_D50_2, ColorChecker2005_COLORED_MASK_);
376         return Macbeth_D50_2;
377     }
378 
379     case cv::ccm::COLORCHECKER_Vinyl:
380     {
381         Mat Vinyl_LAB_D50_2__ = GetColor::getColorChecker(*Vinyl_LAB_D50_2, 18);
382         Mat Vinyl_COLORED_MASK__ = GetColor::getColorCheckerMASK(Vinyl_COLORED_MASK, 18);
383         std::shared_ptr<Color> Vinyl_D50_2 = std::make_shared<Color>(Vinyl_LAB_D50_2__, COLOR_SPACE_Lab_D50_2, Vinyl_COLORED_MASK__);
384         return Vinyl_D50_2;
385     }
386 
387     case cv::ccm::COLORCHECKER_DigitalSG:
388     {
389         Mat DigitalSG_LAB_D50_2__ = GetColor::getColorChecker(*DigitalSG_LAB_D50_2, 140);
390         std::shared_ptr<Color> DigitalSG_D50_2 = std::make_shared<Color>(DigitalSG_LAB_D50_2__, COLOR_SPACE_Lab_D50_2);
391         return DigitalSG_D50_2;
392     }
393     }
394     CV_Error(Error::StsNotImplemented, "");
395 }
396 
397 }
398 }  // namespace cv::ccm
399