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 "precomp.hpp"
29 
30 #include "colorspace.hpp"
31 #include "operations.hpp"
32 #include "io.hpp"
33 
34 namespace cv {
35 namespace ccm {
getIlluminants(const IO & io)36 static const std::vector<double>& getIlluminants(const IO& io)
37 {
38     static const std::map<IO, std::vector<double>> illuminants = {
39         { IO::getIOs(A_2), { 1.098466069456375, 1, 0.3558228003436005 } },
40         { IO::getIOs(A_10), { 1.111420406956693, 1, 0.3519978321919493 } },
41         { IO::getIOs(D50_2), { 0.9642119944211994, 1, 0.8251882845188288 } },
42         { IO::getIOs(D50_10), { 0.9672062750333777, 1, 0.8142801513128616 } },
43         { IO::getIOs(D55_2), { 0.956797052643698, 1, 0.9214805860173273 } },
44         { IO::getIOs(D55_10), { 0.9579665682254781, 1, 0.9092525159847462 } },
45         { IO::getIOs(D65_2), { 0.95047, 1., 1.08883 } },
46         { IO::getIOs(D65_10), { 0.94811, 1., 1.07304 } },
47         { IO::getIOs(D75_2), { 0.9497220898840717, 1, 1.226393520724154 } },
48         { IO::getIOs(D75_10), { 0.9441713925645873, 1, 1.2064272211720228 } },
49         { IO::getIOs(E_2), { 1., 1., 1. } },
50         { IO::getIOs(E_10), { 1., 1., 1. } },
51     };
52     auto it = illuminants.find(io);
53     CV_Assert(it != illuminants.end());
54     return it->second;
55 };
56 
57 /* @brief Basic class for ColorSpace.
58  */
relate(const ColorSpace & other) const59 bool ColorSpace::relate(const ColorSpace& other) const
60 {
61     return (type == other.type) && (io == other.io);
62 };
63 
relation(const ColorSpace &) const64 Operations ColorSpace::relation(const ColorSpace& /*other*/) const
65 {
66     return Operations::get_IDENTITY_OPS();
67 }
68 
operator <(const ColorSpace & other) const69 bool ColorSpace::operator<(const ColorSpace& other) const
70 {
71     return (io < other.io || (io == other.io && type < other.type) || (io == other.io && type == other.type && linear < other.linear));
72 }
73 
74 /* @brief Base of RGB color space;
75  *        the argument values are from AdobeRGB;
76  *        Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space
77  */
relation(const ColorSpace & other) const78 Operations RGBBase_::relation(const ColorSpace& other) const
79 {
80     if (linear == other.linear)
81     {
82         return Operations::get_IDENTITY_OPS();
83     }
84     if (linear)
85     {
86         return Operations({ Operation(fromL) });
87     }
88     return Operations({ Operation(toL) });
89 }
90 
91 /* @brief Initial operations.
92  */
init()93 void RGBBase_::init()
94 {
95     setParameter();
96     calLinear();
97     calM();
98     calOperations();
99 }
100 
101 /* @brief Produce color space instance with linear and non-linear versions.
102  * @param rgbl type of RGBBase_.
103  */
bind(RGBBase_ & rgbl)104 void RGBBase_::bind(RGBBase_& rgbl)
105 {
106     init();
107     rgbl.init();
108     l = &rgbl;
109     rgbl.l = &rgbl;
110     nl = this;
111     rgbl.nl = this;
112 }
113 
114 /* @brief Calculation of M_RGBL2XYZ_base.
115  */
calM()116 void RGBBase_::calM()
117 {
118     Mat XYZr, XYZg, XYZb, XYZ_rgbl, Srgb;
119     XYZr = Mat(xyY2XYZ({ xr, yr }), true);
120     XYZg = Mat(xyY2XYZ({ xg, yg }), true);
121     XYZb = Mat(xyY2XYZ({ xb, yb }), true);
122     merge(std::vector<Mat> { XYZr, XYZg, XYZb }, XYZ_rgbl);
123     XYZ_rgbl = XYZ_rgbl.reshape(1, XYZ_rgbl.rows);
124     Mat XYZw = Mat(getIlluminants(io), true);
125     solve(XYZ_rgbl, XYZw, Srgb);
126     merge(std::vector<Mat> { Srgb.at<double>(0) * XYZr, Srgb.at<double>(1) * XYZg,
127                   Srgb.at<double>(2) * XYZb },
128             M_to);
129     M_to = M_to.reshape(1, M_to.rows);
130     M_from = M_to.inv();
131 };
132 
133 /* @brief operations to or from XYZ.
134  */
calOperations()135 void RGBBase_::calOperations()
136 {
137     // rgb -> rgbl
138     toL = [this](Mat rgb) -> Mat { return toLFunc(rgb); };
139 
140     // rgbl -> rgb
141     fromL = [this](Mat rgbl) -> Mat { return fromLFunc(rgbl); };
142 
143     if (linear)
144     {
145         to = Operations({ Operation(M_to.t()) });
146         from = Operations({ Operation(M_from.t()) });
147     }
148     else
149     {
150         to = Operations({ Operation(toL), Operation(M_to.t()) });
151         from = Operations({ Operation(M_from.t()), Operation(fromL) });
152     }
153 }
154 
toLFunc(Mat &)155 Mat RGBBase_::toLFunc(Mat& /*rgb*/) { return Mat(); }
156 
fromLFunc(Mat &)157 Mat RGBBase_::fromLFunc(Mat& /*rgbl*/) { return Mat(); }
158 
159 /* @brief Base of Adobe RGB color space;
160  */
161 
toLFunc(Mat & rgb)162 Mat AdobeRGBBase_::toLFunc(Mat& rgb) { return gammaCorrection(rgb, gamma); }
163 
fromLFunc(Mat & rgbl)164 Mat AdobeRGBBase_::fromLFunc(Mat& rgbl)
165 {
166     return gammaCorrection(rgbl, 1. / gamma);
167 }
168 
169 /* @brief Base of sRGB color space;
170  */
171 
calLinear()172 void sRGBBase_::calLinear()
173 {
174     alpha = a + 1;
175     K0 = a / (gamma - 1);
176     phi = (pow(alpha, gamma) * pow(gamma - 1, gamma - 1)) / (pow(a, gamma - 1) * pow(gamma, gamma));
177     beta = K0 / phi;
178 }
179 
180 /* @brief Used by toLFunc.
181  */
toLFuncEW(double & x)182 double sRGBBase_::toLFuncEW(double& x)
183 {
184     if (x > K0)
185     {
186         return pow(((x + alpha - 1) / alpha), gamma);
187     }
188     else if (x >= -K0)
189     {
190         return x / phi;
191     }
192     else
193     {
194         return -(pow(((-x + alpha - 1) / alpha), gamma));
195     }
196 }
197 
198 /* @brief Linearization.
199  * @param rgb the input array, type of cv::Mat.
200  * @return the output array, type of cv::Mat.
201  */
toLFunc(Mat & rgb)202 Mat sRGBBase_::toLFunc(Mat& rgb)
203 {
204     return elementWise(rgb,
205             [this](double a_) -> double { return toLFuncEW(a_); });
206 }
207 
208 /* @brief Used by fromLFunc.
209  */
fromLFuncEW(double & x)210 double sRGBBase_::fromLFuncEW(double& x)
211 {
212     if (x > beta)
213     {
214         return alpha * pow(x, 1 / gamma) - (alpha - 1);
215     }
216     else if (x >= -beta)
217     {
218         return x * phi;
219     }
220     else
221     {
222         return -(alpha * pow(-x, 1 / gamma) - (alpha - 1));
223     }
224 }
225 
226 /* @brief Delinearization.
227  * @param rgbl the input array, type of cv::Mat.
228  * @return the output array, type of cv::Mat.
229  */
fromLFunc(Mat & rgbl)230 Mat sRGBBase_::fromLFunc(Mat& rgbl)
231 {
232     return elementWise(rgbl,
233             [this](double a_) -> double { return fromLFuncEW(a_); });
234 }
235 
236 /* @brief sRGB color space.
237  *        data from https://en.wikipedia.org/wiki/SRGB.
238  */
setParameter()239 void sRGB_::setParameter()
240 {
241     xr = 0.64;
242     yr = 0.33;
243     xg = 0.3;
244     yg = 0.6;
245     xb = 0.15;
246     yb = 0.06;
247     a = 0.055;
248     gamma = 2.4;
249 }
250 
251 /* @brief Adobe RGB color space.
252  */
setParameter()253 void AdobeRGB_::setParameter()
254 {
255     xr = 0.64;
256     yr = 0.33;
257     xg = 0.21;
258     yg = 0.71;
259     xb = 0.15;
260     yb = 0.06;
261     gamma = 2.2;
262 }
263 
264 /* @brief Wide-gamut RGB color space.
265  *        data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space.
266  */
setParameter()267 void WideGamutRGB_::setParameter()
268 {
269     xr = 0.7347;
270     yr = 0.2653;
271     xg = 0.1152;
272     yg = 0.8264;
273     xb = 0.1566;
274     yb = 0.0177;
275     gamma = 2.2;
276 }
277 
278 /* @brief ProPhoto RGB color space.
279  *        data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space.
280  */
setParameter()281 void ProPhotoRGB_::setParameter()
282 {
283     xr = 0.734699;
284     yr = 0.265301;
285     xg = 0.159597;
286     yg = 0.840403;
287     xb = 0.036598;
288     yb = 0.000105;
289     gamma = 1.8;
290 }
291 
292 /* @brief DCI-P3 RGB color space.
293  *        data from https://en.wikipedia.org/wiki/DCI-P3.
294  */
295 
setParameter()296 void DCI_P3_RGB_::setParameter()
297 {
298     xr = 0.68;
299     yr = 0.32;
300     xg = 0.265;
301     yg = 0.69;
302     xb = 0.15;
303     yb = 0.06;
304     gamma = 2.2;
305 }
306 
307 /* @brief Apple RGB color space.
308  *        data from
309  * http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html.
310  */
setParameter()311 void AppleRGB_::setParameter()
312 {
313     xr = 0.625;
314     yr = 0.34;
315     xg = 0.28;
316     yg = 0.595;
317     xb = 0.155;
318     yb = 0.07;
319     gamma = 1.8;
320 }
321 
322 /* @brief REC_709 RGB color space.
323  *        data from https://en.wikipedia.org/wiki/Rec._709.
324  */
setParameter()325 void REC_709_RGB_::setParameter()
326 {
327     xr = 0.64;
328     yr = 0.33;
329     xg = 0.3;
330     yg = 0.6;
331     xb = 0.15;
332     yb = 0.06;
333     a = 0.099;
334     gamma = 1 / 0.45;
335 }
336 
337 /* @brief REC_2020 RGB color space.
338  *        data from https://en.wikipedia.org/wiki/Rec._2020.
339  */
340 
setParameter()341 void REC_2020_RGB_::setParameter()
342 {
343     xr = 0.708;
344     yr = 0.292;
345     xg = 0.17;
346     yg = 0.797;
347     xb = 0.131;
348     yb = 0.046;
349     a = 0.09929682680944;
350     gamma = 1 / 0.45;
351 }
352 
cam(IO dio,CAM method)353 Operations XYZ::cam(IO dio, CAM method)
354 {
355     return (io == dio) ? Operations()
356                        : Operations({ Operation(cam_(io, dio, method).t()) });
357 }
cam_(IO sio,IO dio,CAM method) const358 Mat XYZ::cam_(IO sio, IO dio, CAM method) const
359 {
360     static std::map<std::tuple<IO, IO, CAM>, Mat> cams;
361 
362     if (sio == dio)
363     {
364         return Mat::eye(cv::Size(3, 3), CV_64FC1);
365     }
366     if (cams.count(std::make_tuple(dio, sio, method)) == 1)
367     {
368         return cams[std::make_tuple(dio, sio, method)];
369     }
370     /* @brief XYZ color space.
371     *        Chromatic adaption matrices.
372     */
373 
374     static const Mat Von_Kries = (Mat_<double>(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822);
375     static const Mat Bradford = (Mat_<double>(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296);
376     static const std::map<CAM, std::vector<Mat>> MAs = {
377         { IDENTITY, { Mat::eye(Size(3, 3), CV_64FC1), Mat::eye(Size(3, 3), CV_64FC1) } },
378         { VON_KRIES, { Von_Kries, Von_Kries.inv() } },
379         { BRADFORD, { Bradford, Bradford.inv() } }
380     };
381 
382     // Function from http://www.brucelindbloom.com/index.html?ColorCheckerRGB.html.
383     Mat XYZws = Mat(getIlluminants(dio));
384     Mat XYZWd = Mat(getIlluminants(sio));
385     Mat MA = MAs.at(method)[0];
386     Mat MA_inv = MAs.at(method)[1];
387     Mat M = MA_inv * Mat::diag((MA * XYZws) / (MA * XYZWd)) * MA;
388     cams[std::make_tuple(dio, sio, method)] = M;
389     cams[std::make_tuple(sio, dio, method)] = M.inv();
390     return M;
391 }
392 
get(IO io)393 std::shared_ptr<XYZ> XYZ::get(IO io)
394 {
395     static std::map<IO, std::shared_ptr<XYZ>> xyz_cs;
396 
397     if (xyz_cs.count(io) == 1)
398     {
399         return xyz_cs[io];
400     }
401     std::shared_ptr<XYZ> XYZ_CS = std::make_shared<XYZ>(io);
402     xyz_cs[io] = XYZ_CS;
403     return xyz_cs[io];
404 }
405 
406 /* @brief Lab color space.
407  */
Lab(IO io_)408 Lab::Lab(IO io_)
409     : ColorSpace(io_, "Lab", true)
410 {
411     to = { Operation([this](Mat src) -> Mat { return tosrc(src); }) };
412     from = { Operation([this](Mat src) -> Mat { return fromsrc(src); }) };
413 }
414 
fromxyz(cv::Vec3d & xyz)415 Vec3d Lab::fromxyz(cv::Vec3d& xyz)
416 {
417     auto& il = getIlluminants(io);
418     double x = xyz[0] / il[0],
419            y = xyz[1] / il[1],
420            z = xyz[2] / il[2];
421     auto f = [](double t) -> double {
422         return t > t0 ? std::cbrt(t) : (m * t + c);
423     };
424     double fx = f(x), fy = f(y), fz = f(z);
425     return { 116. * fy - 16., 500 * (fx - fy), 200 * (fy - fz) };
426 }
427 
428 /* @brief Calculate From.
429  * @param src the input array, type of cv::Mat.
430  * @return the output array, type of cv::Mat
431  */
fromsrc(Mat & src)432 Mat Lab::fromsrc(Mat& src)
433 {
434     return channelWise(src,
435             [this](cv::Vec3d a) -> cv::Vec3d { return fromxyz(a); });
436 }
437 
tolab(cv::Vec3d & lab)438 Vec3d Lab::tolab(cv::Vec3d& lab)
439 {
440     auto f_inv = [](double t) -> double {
441         return t > delta ? pow(t, 3.0) : (t - c) / m;
442     };
443     double L = (lab[0] + 16.) / 116., a = lab[1] / 500., b = lab[2] / 200.;
444     auto& il = getIlluminants(io);
445     return { il[0] * f_inv(L + a),
446         il[1] * f_inv(L),
447         il[2] * f_inv(L - b) };
448 }
449 
450 /* @brief Calculate To.
451  * @param src the input array, type of cv::Mat.
452  * @return the output array, type of cv::Mat
453  */
tosrc(Mat & src)454 Mat Lab::tosrc(Mat& src)
455 {
456     return channelWise(src,
457             [this](cv::Vec3d a) -> cv::Vec3d { return tolab(a); });
458 }
459 
get(IO io)460 std::shared_ptr<Lab> Lab::get(IO io)
461 {
462     static std::map<IO, std::shared_ptr<Lab>> 	lab_cs;
463 
464     if (lab_cs.count(io) == 1)
465     {
466         return lab_cs[io];
467     }
468     std::shared_ptr<Lab> Lab_CS(new Lab(io));
469     lab_cs[io] = Lab_CS;
470     return lab_cs[io];
471 }
472 
GetCS()473 GetCS::GetCS()
474 {
475     // nothing
476 }
477 
getInstance()478 GetCS& GetCS::getInstance()
479 {
480     static GetCS instance;
481     return instance;
482 }
483 
get_rgb(enum COLOR_SPACE cs_name)484 std::shared_ptr<RGBBase_> GetCS::get_rgb(enum COLOR_SPACE cs_name)
485 {
486     switch (cs_name)
487     {
488     case cv::ccm::COLOR_SPACE_sRGB:
489     {
490         if (map_cs.count(cs_name) < 1)
491         {
492             std::shared_ptr<sRGB_> sRGB_CS(new sRGB_(false));
493             std::shared_ptr<sRGB_> sRGBL_CS(new sRGB_(true));
494             (*sRGB_CS).bind(*sRGBL_CS);
495             map_cs[COLOR_SPACE_sRGB] = sRGB_CS;
496             map_cs[COLOR_SPACE_sRGBL] = sRGBL_CS;
497         }
498         break;
499     }
500     case cv::ccm::COLOR_SPACE_AdobeRGB:
501     {
502         if (map_cs.count(cs_name) < 1)
503         {
504             std::shared_ptr<AdobeRGB_> AdobeRGB_CS(new AdobeRGB_(false));
505             std::shared_ptr<AdobeRGB_> AdobeRGBL_CS(new AdobeRGB_(true));
506             (*AdobeRGB_CS).bind(*AdobeRGBL_CS);
507             map_cs[COLOR_SPACE_AdobeRGB] = AdobeRGB_CS;
508             map_cs[COLOR_SPACE_AdobeRGBL] = AdobeRGBL_CS;
509         }
510         break;
511     }
512     case cv::ccm::COLOR_SPACE_WideGamutRGB:
513     {
514         if (map_cs.count(cs_name) < 1)
515         {
516             std::shared_ptr<WideGamutRGB_> WideGamutRGB_CS(new WideGamutRGB_(false));
517             std::shared_ptr<WideGamutRGB_> WideGamutRGBL_CS(new WideGamutRGB_(true));
518             (*WideGamutRGB_CS).bind(*WideGamutRGBL_CS);
519             map_cs[COLOR_SPACE_WideGamutRGB] = WideGamutRGB_CS;
520             map_cs[COLOR_SPACE_WideGamutRGBL] = WideGamutRGBL_CS;
521         }
522         break;
523     }
524     case cv::ccm::COLOR_SPACE_ProPhotoRGB:
525     {
526         if (map_cs.count(cs_name) < 1)
527         {
528             std::shared_ptr<ProPhotoRGB_> ProPhotoRGB_CS(new ProPhotoRGB_(false));
529             std::shared_ptr<ProPhotoRGB_> ProPhotoRGBL_CS(new ProPhotoRGB_(true));
530             (*ProPhotoRGB_CS).bind(*ProPhotoRGBL_CS);
531             map_cs[COLOR_SPACE_ProPhotoRGB] = ProPhotoRGB_CS;
532             map_cs[COLOR_SPACE_ProPhotoRGBL] = ProPhotoRGBL_CS;
533         }
534         break;
535     }
536     case cv::ccm::COLOR_SPACE_DCI_P3_RGB:
537     {
538         if (map_cs.count(cs_name) < 1)
539         {
540             std::shared_ptr<DCI_P3_RGB_> DCI_P3_RGB_CS(new DCI_P3_RGB_(false));
541             std::shared_ptr<DCI_P3_RGB_> DCI_P3_RGBL_CS(new DCI_P3_RGB_(true));
542             (*DCI_P3_RGB_CS).bind(*DCI_P3_RGBL_CS);
543             map_cs[COLOR_SPACE_DCI_P3_RGB] = DCI_P3_RGB_CS;
544             map_cs[COLOR_SPACE_DCI_P3_RGBL] = DCI_P3_RGBL_CS;
545         }
546         break;
547     }
548     case cv::ccm::COLOR_SPACE_AppleRGB:
549     {
550         if (map_cs.count(cs_name) < 1)
551         {
552             std::shared_ptr<AppleRGB_> AppleRGB_CS(new AppleRGB_(false));
553             std::shared_ptr<AppleRGB_> AppleRGBL_CS(new AppleRGB_(true));
554             (*AppleRGB_CS).bind(*AppleRGBL_CS);
555             map_cs[COLOR_SPACE_AppleRGB] = AppleRGB_CS;
556             map_cs[COLOR_SPACE_AppleRGBL] = AppleRGBL_CS;
557         }
558         break;
559     }
560     case cv::ccm::COLOR_SPACE_REC_709_RGB:
561     {
562         if (map_cs.count(cs_name) < 1)
563         {
564             std::shared_ptr<REC_709_RGB_> REC_709_RGB_CS(new REC_709_RGB_(false));
565             std::shared_ptr<REC_709_RGB_> REC_709_RGBL_CS(new REC_709_RGB_(true));
566             (*REC_709_RGB_CS).bind(*REC_709_RGBL_CS);
567             map_cs[COLOR_SPACE_REC_709_RGB] = REC_709_RGB_CS;
568             map_cs[COLOR_SPACE_REC_709_RGBL] = REC_709_RGBL_CS;
569         }
570         break;
571     }
572     case cv::ccm::COLOR_SPACE_REC_2020_RGB:
573     {
574         if (map_cs.count(cs_name) < 1)
575         {
576             std::shared_ptr<REC_2020_RGB_> REC_2020_RGB_CS(new REC_2020_RGB_(false));
577             std::shared_ptr<REC_2020_RGB_> REC_2020_RGBL_CS(new REC_2020_RGB_(true));
578             (*REC_2020_RGB_CS).bind(*REC_2020_RGBL_CS);
579             map_cs[COLOR_SPACE_REC_2020_RGB] = REC_2020_RGB_CS;
580             map_cs[COLOR_SPACE_REC_2020_RGBL] = REC_2020_RGBL_CS;
581         }
582         break;
583     }
584     case cv::ccm::COLOR_SPACE_sRGBL:
585     case cv::ccm::COLOR_SPACE_AdobeRGBL:
586     case cv::ccm::COLOR_SPACE_WideGamutRGBL:
587     case cv::ccm::COLOR_SPACE_ProPhotoRGBL:
588     case cv::ccm::COLOR_SPACE_DCI_P3_RGBL:
589     case cv::ccm::COLOR_SPACE_AppleRGBL:
590     case cv::ccm::COLOR_SPACE_REC_709_RGBL:
591     case cv::ccm::COLOR_SPACE_REC_2020_RGBL:
592         CV_Error(Error::StsBadArg, "linear RGB colorspaces are not supported, you should assigned as normal RGB color space");
593         break;
594 
595     default:
596         CV_Error(Error::StsBadArg, "Only RGB color spaces are supported");
597     }
598     return (std::dynamic_pointer_cast<RGBBase_>)(map_cs[cs_name]);
599 }
600 
get_cs(enum COLOR_SPACE cs_name)601 std::shared_ptr<ColorSpace> GetCS::get_cs(enum COLOR_SPACE cs_name)
602 {
603     switch (cs_name)
604     {
605     case cv::ccm::COLOR_SPACE_sRGB:
606     case cv::ccm::COLOR_SPACE_sRGBL:
607     {
608         if (map_cs.count(cs_name) < 1)
609         {
610             std::shared_ptr<sRGB_> sRGB_CS(new sRGB_(false));
611             std::shared_ptr<sRGB_> sRGBL_CS(new sRGB_(true));
612             (*sRGB_CS).bind(*sRGBL_CS);
613             map_cs[COLOR_SPACE_sRGB] = sRGB_CS;
614             map_cs[COLOR_SPACE_sRGBL] = sRGBL_CS;
615         }
616         break;
617     }
618     case cv::ccm::COLOR_SPACE_AdobeRGB:
619     case cv::ccm::COLOR_SPACE_AdobeRGBL:
620     {
621         if (map_cs.count(cs_name) < 1)
622         {
623             std::shared_ptr<AdobeRGB_> AdobeRGB_CS(new AdobeRGB_(false));
624             std::shared_ptr<AdobeRGB_> AdobeRGBL_CS(new AdobeRGB_(true));
625             (*AdobeRGB_CS).bind(*AdobeRGBL_CS);
626             map_cs[COLOR_SPACE_AdobeRGB] = AdobeRGB_CS;
627             map_cs[COLOR_SPACE_AdobeRGBL] = AdobeRGBL_CS;
628         }
629         break;
630     }
631     case cv::ccm::COLOR_SPACE_WideGamutRGB:
632     case cv::ccm::COLOR_SPACE_WideGamutRGBL:
633     {
634         if (map_cs.count(cs_name) < 1)
635         {
636             std::shared_ptr<WideGamutRGB_> WideGamutRGB_CS(new WideGamutRGB_(false));
637             std::shared_ptr<WideGamutRGB_> WideGamutRGBL_CS(new WideGamutRGB_(true));
638             (*WideGamutRGB_CS).bind(*WideGamutRGBL_CS);
639             map_cs[COLOR_SPACE_WideGamutRGB] = WideGamutRGB_CS;
640             map_cs[COLOR_SPACE_WideGamutRGBL] = WideGamutRGBL_CS;
641         }
642         break;
643     }
644     case cv::ccm::COLOR_SPACE_ProPhotoRGB:
645     case cv::ccm::COLOR_SPACE_ProPhotoRGBL:
646     {
647         if (map_cs.count(cs_name) < 1)
648         {
649             std::shared_ptr<ProPhotoRGB_> ProPhotoRGB_CS(new ProPhotoRGB_(false));
650             std::shared_ptr<ProPhotoRGB_> ProPhotoRGBL_CS(new ProPhotoRGB_(true));
651             (*ProPhotoRGB_CS).bind(*ProPhotoRGBL_CS);
652             map_cs[COLOR_SPACE_ProPhotoRGB] = ProPhotoRGB_CS;
653             map_cs[COLOR_SPACE_ProPhotoRGBL] = ProPhotoRGBL_CS;
654         }
655         break;
656     }
657     case cv::ccm::COLOR_SPACE_DCI_P3_RGB:
658     case cv::ccm::COLOR_SPACE_DCI_P3_RGBL:
659     {
660         if (map_cs.count(cs_name) < 1)
661         {
662             std::shared_ptr<DCI_P3_RGB_> DCI_P3_RGB_CS(new DCI_P3_RGB_(false));
663             std::shared_ptr<DCI_P3_RGB_> DCI_P3_RGBL_CS(new DCI_P3_RGB_(true));
664             (*DCI_P3_RGB_CS).bind(*DCI_P3_RGBL_CS);
665             map_cs[COLOR_SPACE_DCI_P3_RGB] = DCI_P3_RGB_CS;
666             map_cs[COLOR_SPACE_DCI_P3_RGBL] = DCI_P3_RGBL_CS;
667         }
668         break;
669     }
670     case cv::ccm::COLOR_SPACE_AppleRGB:
671     case cv::ccm::COLOR_SPACE_AppleRGBL:
672     {
673         if (map_cs.count(cs_name) < 1)
674         {
675             std::shared_ptr<AppleRGB_> AppleRGB_CS(new AppleRGB_(false));
676             std::shared_ptr<AppleRGB_> AppleRGBL_CS(new AppleRGB_(true));
677             (*AppleRGB_CS).bind(*AppleRGBL_CS);
678             map_cs[COLOR_SPACE_AppleRGB] = AppleRGB_CS;
679             map_cs[COLOR_SPACE_AppleRGBL] = AppleRGBL_CS;
680         }
681         break;
682     }
683     case cv::ccm::COLOR_SPACE_REC_709_RGB:
684     case cv::ccm::COLOR_SPACE_REC_709_RGBL:
685     {
686         if (map_cs.count(cs_name) < 1)
687         {
688             std::shared_ptr<REC_709_RGB_> REC_709_RGB_CS(new REC_709_RGB_(false));
689             std::shared_ptr<REC_709_RGB_> REC_709_RGBL_CS(new REC_709_RGB_(true));
690             (*REC_709_RGB_CS).bind(*REC_709_RGBL_CS);
691             map_cs[COLOR_SPACE_REC_709_RGB] = REC_709_RGB_CS;
692             map_cs[COLOR_SPACE_REC_709_RGBL] = REC_709_RGBL_CS;
693         }
694         break;
695     }
696     case cv::ccm::COLOR_SPACE_REC_2020_RGB:
697     case cv::ccm::COLOR_SPACE_REC_2020_RGBL:
698     {
699         if (map_cs.count(cs_name) < 1)
700         {
701             std::shared_ptr<REC_2020_RGB_> REC_2020_RGB_CS(new REC_2020_RGB_(false));
702             std::shared_ptr<REC_2020_RGB_> REC_2020_RGBL_CS(new REC_2020_RGB_(true));
703             (*REC_2020_RGB_CS).bind(*REC_2020_RGBL_CS);
704             map_cs[COLOR_SPACE_REC_2020_RGB] = REC_2020_RGB_CS;
705             map_cs[COLOR_SPACE_REC_2020_RGBL] = REC_2020_RGBL_CS;
706         }
707         break;
708     }
709     case cv::ccm::COLOR_SPACE_XYZ_D65_2:
710         return XYZ::get(IO::getIOs(D65_2));
711         break;
712     case cv::ccm::COLOR_SPACE_XYZ_D50_2:
713         return XYZ::get(IO::getIOs(D50_2));
714         break;
715     case cv::ccm::COLOR_SPACE_XYZ_D65_10:
716         return XYZ::get(IO::getIOs(D65_10));
717         break;
718     case cv::ccm::COLOR_SPACE_XYZ_D50_10:
719         return XYZ::get(IO::getIOs(D50_10));
720         break;
721     case cv::ccm::COLOR_SPACE_XYZ_A_2:
722         return XYZ::get(IO::getIOs(A_2));
723         break;
724     case cv::ccm::COLOR_SPACE_XYZ_A_10:
725         return XYZ::get(IO::getIOs(A_10));
726         break;
727     case cv::ccm::COLOR_SPACE_XYZ_D55_2:
728         return XYZ::get(IO::getIOs(D55_2));
729         break;
730     case cv::ccm::COLOR_SPACE_XYZ_D55_10:
731         return XYZ::get(IO::getIOs(D55_10));
732         break;
733     case cv::ccm::COLOR_SPACE_XYZ_D75_2:
734         return XYZ::get(IO::getIOs(D75_2));
735         break;
736     case cv::ccm::COLOR_SPACE_XYZ_D75_10:
737         return XYZ::get(IO::getIOs(D75_10));
738         break;
739     case cv::ccm::COLOR_SPACE_XYZ_E_2:
740         return XYZ::get(IO::getIOs(E_2));
741         break;
742     case cv::ccm::COLOR_SPACE_XYZ_E_10:
743         return XYZ::get(IO::getIOs(E_10));
744         break;
745     case cv::ccm::COLOR_SPACE_Lab_D65_2:
746         return Lab::get(IO::getIOs(D65_2));
747         break;
748     case cv::ccm::COLOR_SPACE_Lab_D50_2:
749         return Lab::get(IO::getIOs(D50_2));
750         break;
751     case cv::ccm::COLOR_SPACE_Lab_D65_10:
752         return Lab::get(IO::getIOs(D65_10));
753         break;
754     case cv::ccm::COLOR_SPACE_Lab_D50_10:
755         return Lab::get(IO::getIOs(D50_10));
756         break;
757     case cv::ccm::COLOR_SPACE_Lab_A_2:
758         return Lab::get(IO::getIOs(A_2));
759         break;
760     case cv::ccm::COLOR_SPACE_Lab_A_10:
761         return Lab::get(IO::getIOs(A_10));
762         break;
763     case cv::ccm::COLOR_SPACE_Lab_D55_2:
764         return Lab::get(IO::getIOs(D55_2));
765         break;
766     case cv::ccm::COLOR_SPACE_Lab_D55_10:
767         return Lab::get(IO::getIOs(D55_10));
768         break;
769     case cv::ccm::COLOR_SPACE_Lab_D75_2:
770         return Lab::get(IO::getIOs(D75_2));
771         break;
772     case cv::ccm::COLOR_SPACE_Lab_D75_10:
773         return Lab::get(IO::getIOs(D75_10));
774         break;
775     case cv::ccm::COLOR_SPACE_Lab_E_2:
776         return Lab::get(IO::getIOs(E_2));
777         break;
778     case cv::ccm::COLOR_SPACE_Lab_E_10:
779         return Lab::get(IO::getIOs(E_10));
780         break;
781     default:
782         break;
783     }
784 
785     return map_cs[cs_name];
786 }
787 
788 }
789 }  // namespace cv::ccm
790