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