From 7a3d082d58ae215409e035b27052faf0a68b682c Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Mon, 31 Aug 2020 03:46:31 +0000 Subject: [PATCH 01/71] Add utils, io helpers, the operations for linearization and distance --- modules/mcc/include/opencv2/mcc/distance.hpp | 252 ++++++++++++++++++ modules/mcc/include/opencv2/mcc/io.hpp | 108 ++++++++ .../mcc/include/opencv2/mcc/operations.hpp | 142 ++++++++++ modules/mcc/include/opencv2/mcc/utils.hpp | 230 ++++++++++++++++ 4 files changed, 732 insertions(+) create mode 100644 modules/mcc/include/opencv2/mcc/distance.hpp create mode 100644 modules/mcc/include/opencv2/mcc/io.hpp create mode 100644 modules/mcc/include/opencv2/mcc/operations.hpp create mode 100644 modules/mcc/include/opencv2/mcc/utils.hpp diff --git a/modules/mcc/include/opencv2/mcc/distance.hpp b/modules/mcc/include/opencv2/mcc/distance.hpp new file mode 100644 index 00000000000..83c431512f0 --- /dev/null +++ b/modules/mcc/include/opencv2/mcc/distance.hpp @@ -0,0 +1,252 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level +// directory of this distribution and at http://opencv.org/license.html. + +/* + * MIT License + * + * Copyright (c) 2018 Pedro Diamel Marrero Fernández + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __OPENCV_MCC_DISTANCE_HPP__ +#define __OPENCV_MCC_DISTANCE_HPP__ + +#include "opencv2/mcc/utils.hpp" + +namespace cv { +namespace ccm { + +/* *\brief Enum of possibale functions to calculate the distance between + * colors.see https://en.wikipedia.org/wiki/Color_difference for details;*/ +enum DISTANCE_TYPE { + CIE76, + CIE94_GRAPHIC_ARTS, + CIE94_TEXTILES, + CIE2000, + CMC_1TO1, + CMC_2TO1, + RGB, + RGBL +}; + +/* *\ brief distance between two points in formula CIE76 + *\ param lab1 a 3D vector + *\ param lab2 a 3D vector + *\ return distance between lab1 and lab2 +*/ +double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2) { return norm(lab1 - lab2); }; + +/* *\ brief distance between two points in formula CIE94 + *\ param lab1 a 3D vector + *\ param lab2 a 3D vector + *\ param kH Hue scale + *\ param kC Chroma scale + *\ param kL Lightness scale + *\ param k1 first scale parameter + *\ param k2 second scale parameter + *\ return distance between lab1 and lab2 +*/ +double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH = 1.0, + double kC = 1.0, double kL = 1.0, double k1 = 0.045, + double k2 = 0.015) { + double dl = lab1[0] - lab2[0]; + double c1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); + double c2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); + double dc = c1 - c2; + double da = lab1[1] - lab2[1]; + double db = lab1[2] - lab2[2]; + double dh = pow(da, 2) + pow(db, 2) - pow(dc, 2); + double sc = 1.0 + k1 * c1; + double sh = 1.0 + k2 * c1; + double sl = 1.0; + double res = + pow(dl / (kL * sl), 2) + pow(dc / (kC * sc), 2) + dh / pow(kH * sh, 2); + + return res > 0 ? sqrt(res) : 0; +} + +double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2) { + return deltaCIE94(lab1, lab2); +} + +double toRad(double degree) { return degree / 180 * CV_PI; }; + +double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2) { + return deltaCIE94(lab1, lab2, 1.0, 1.0, 2.0, 0.048, 0.014); +} + +/* *\ brief distance between two points in formula CIE2000 + *\ param lab1 a 3D vector + *\ param lab2 a 3D vector + *\ param kL Lightness scale + *\ param kC Chroma scale + *\ param kH Hue scale + *\ return distance between lab1 and lab2 +*/ +double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1.0, + double kC = 1.0, double kH = 1.0) { + double delta_L_apo = lab2[0] - lab1[0]; + double l_bar_apo = (lab1[0] + lab2[0]) / 2.0; + double C1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); + double C2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); + double C_bar = (C1 + C2) / 2.0; + double G = sqrt(pow(C_bar, 7) / (pow(C_bar, 7) + pow(25, 7))); + double a1_apo = lab1[1] + lab1[1] / 2.0 * (1.0 - G); + double a2_apo = lab2[1] + lab2[1] / 2.0 * (1.0 - G); + double C1_apo = sqrt(pow(a1_apo, 2) + pow(lab1[2], 2)); + double C2_apo = sqrt(pow(a2_apo, 2) + pow(lab2[2], 2)); + double C_bar_apo = (C1_apo + C2_apo) / 2.0; + double delta_C_apo = C2_apo - C1_apo; + + double h1_apo; + if (C1_apo == 0) { + h1_apo = 0.0; + } else { + h1_apo = atan2(lab1[2], a1_apo); + if (h1_apo < 0.0) h1_apo += 2. * CV_PI; + } + + double h2_apo; + if (C2_apo == 0) { + h2_apo = 0.0; + } else { + h2_apo = atan2(lab2[2], a2_apo); + if (h2_apo < 0.0) h2_apo += 2. * CV_PI; + } + + double delta_h_apo; + if (abs(h2_apo - h1_apo) <= CV_PI) { + delta_h_apo = h2_apo - h1_apo; + } else if (h2_apo <= h1_apo) { + delta_h_apo = h2_apo - h1_apo + 2. * CV_PI; + } else { + delta_h_apo = h2_apo - h1_apo - 2. * CV_PI; + } + + double H_bar_apo; + if (C1_apo == 0 || C2_apo == 0) { + H_bar_apo = h1_apo + h2_apo; + } else if (abs(h1_apo - h2_apo) <= CV_PI) { + H_bar_apo = (h1_apo + h2_apo) / 2.0; + } else if (h1_apo + h2_apo < 2. * CV_PI) { + H_bar_apo = (h1_apo + h2_apo + 2. * CV_PI) / 2.0; + } else { + H_bar_apo = (h1_apo + h2_apo - 2. * CV_PI) / 2.0; + } + + double delta_H_apo = 2.0 * sqrt(C1_apo * C2_apo) * sin(delta_h_apo / 2.0); + double T = 1.0 - 0.17 * cos(H_bar_apo - toRad(30.)) + + 0.24 * cos(2.0 * H_bar_apo) + + 0.32 * cos(3.0 * H_bar_apo + toRad(6.0)) - + 0.2 * cos(4.0 * H_bar_apo - toRad(63.0)); + double sC = 1.0 + 0.045 * C_bar_apo; + double sH = 1.0 + 0.015 * C_bar_apo * T; + double sL = 1.0 + ((0.015 * pow(l_bar_apo - 50.0, 2.0)) / + sqrt(20.0 + pow(l_bar_apo - 50.0, 2.0))); + double RT = -2.0 * G * + sin(toRad(60.0) * + exp(-pow((H_bar_apo - toRad(275.0)) / toRad(25.0), 2.0))); + double res = + (pow(delta_L_apo / (kL * sL), 2.0) + pow(delta_C_apo / (kC * sC), 2.0) + + pow(delta_H_apo / (kH * sH), 2.0) + + RT * (delta_C_apo / (kC * sC)) * (delta_H_apo / (kH * sH))); + return res > 0 ? sqrt(res) : 0; +} + +double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2) { + return deltaCIEDE2000_(lab1, lab2); +} + +/* *\ brief distance between two points in formula CMC + *\ param lab1 a 3D vector + *\ param lab2 a 3D vector + *\ param kL Lightness scale + *\ param kC Chroma scale + *\ return distance between lab1 and lab2 +*/ +double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1, double kC = 1) { + double dL = lab2[0] - lab1[0]; + double da = lab2[1] - lab1[1]; + double db = lab2[2] - lab1[2]; + double C1 = sqrt(pow(lab1[1], 2.0) + pow(lab1[2], 2.0)); + double C2 = sqrt(pow(lab2[1], 2.0) + pow(lab2[2], 2.0)); + double dC = C2 - C1; + double dH = sqrt(pow(da, 2) + pow(db, 2) - pow(dC, 2)); + + double H1; + if (C1 == 0.) { + H1 = 0.0; + } else { + H1 = atan2(lab1[2], lab1[1]); + if (H1 < 0.0) H1 += 2. * CV_PI; + } + + double F = pow(C1, 2) / sqrt(pow(C1, 4) + 1900); + double T = (H1 > toRad(164) && H1 <= toRad(345)) + ? 0.56 + abs(0.2 * cos(H1 + toRad(168))) + : 0.36 + abs(0.4 * cos(H1 + toRad(35))); + ; + double sL = + lab1[0] < 16. ? 0.511 : (0.040975 * lab1[0]) / (1.0 + 0.01765 * lab1[0]); + ; + double sC = (0.0638 * C1) / (1.0 + 0.0131 * C1) + 0.638; + double sH = sC * (F * T + 1.0 - F); + + return sqrt(pow(dL / (kL * sL), 2.0) + pow(dC / (kC * sC), 2.0) + + pow(dH / sH, 2.0)); +} + +double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2) { + return deltaCMC(lab1, lab2); +} + +double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2) { + return deltaCMC(lab1, lab2, 2, 1); +} + +cv::Mat distance(cv::Mat src, cv::Mat ref, DISTANCE_TYPE distance_type) { + switch (distance_type) { + case cv::ccm::CIE76: + return distanceWise(src, ref, deltaCIE76); + case cv::ccm::CIE94_GRAPHIC_ARTS: + return distanceWise(src, ref, deltaCIE94GraphicArts); + case cv::ccm::CIE94_TEXTILES: + return distanceWise(src, ref, deltaCIE94Textiles); + case cv::ccm::CIE2000: + return distanceWise(src, ref, deltaCIEDE2000); + case cv::ccm::CMC_1TO1: + return distanceWise(src, ref, deltaCMC1To1); + case cv::ccm::CMC_2TO1: + return distanceWise(src, ref, deltaCMC2To1); + case cv::ccm::RGB: + return distanceWise(src, ref, deltaCIE76); + case cv::ccm::RGBL: + return distanceWise(src, ref, deltaCIE76); + default: + throw std::invalid_argument{"Wrong distance_type!"}; + break; + } +}; + +} // namespace ccm +} // namespace cv + +#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/io.hpp b/modules/mcc/include/opencv2/mcc/io.hpp new file mode 100644 index 00000000000..5b9afa68697 --- /dev/null +++ b/modules/mcc/include/opencv2/mcc/io.hpp @@ -0,0 +1,108 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +/* + * MIT License + * + * Copyright (c) 2018 Pedro Diamel Marrero Fernández + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __OPENCV_MCC_IO_HPP__ +#define __OPENCV_MCC_IO_HPP__ + +#include +#include +#include +#include + +namespace cv +{ +namespace ccm +{ +/* *\ brief Io is the meaning of illuminant and observer. See notes of ccm.hpp + * for supported list for illuminant and observer*/ +class IO +{ +public: + + std::string illuminant; + std::string observer; + + IO() {}; + + IO(std::string illuminant, std::string observer) :illuminant(illuminant), observer(observer) {}; + + virtual ~IO() {}; + + bool operator<(const IO& other) const + { + return (illuminant < other.illuminant || ((illuminant == other.illuminant) && (observer < other.observer))); + } + + bool operator==(const IO& other) const + { + return illuminant == other.illuminant && observer == other.observer; + }; +}; + +const IO A_2("A", "2"), A_10("A", "10"), + D50_2("D50", "2"), D50_10("D50", "10"), + D55_2("D55", "2"), D55_10("D55", "10"), + D65_2("D65", "2"), D65_10("D65", "10"), + D75_2("D75", "2"), D75_10("D75", "10"), + E_2("E", "2"), E_10("E", "10"); + +// data from https://en.wikipedia.org/wiki/Standard_illuminant. +const static std::map> illuminants_xy = +{ + {A_2, { 0.44757, 0.40745 }}, {A_10, { 0.45117, 0.40594 }}, + {D50_2, { 0.34567, 0.35850 }}, {D50_10, { 0.34773, 0.35952 }}, + {D55_2, { 0.33242, 0.34743 }}, {D55_10, { 0.33411, 0.34877 }}, + {D65_2, { 0.31271, 0.32902 }}, {D65_10, { 0.31382, 0.33100 }}, + {D75_2, { 0.29902, 0.31485 }}, {D75_10, { 0.45117, 0.40594 }}, + {E_2, { 1 / 3, 1 / 3 }}, {E_10, { 1 / 3, 1 / 3 }}, +}; + +std::vector xyY2XYZ(const std::vector& xyY) +{ + double Y = xyY.size() >= 3 ? xyY[2] : 1; + return { Y * xyY[0] / xyY[1], Y, Y / xyY[1] * (1 - xyY[0] - xyY[1]) }; +} + +/* *\ brief function to get illuminants*/ +static std::map > getIlluminant() +{ + std::map > illuminants; + for (auto it = illuminants_xy.begin(); it != illuminants_xy.end(); ++it) + { + illuminants[it->first] = xyY2XYZ(it->second); + } + return illuminants; +} + +const std::map > illuminants = getIlluminant(); + +} // namespace ccm +} // namespace cv + + +#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/operations.hpp b/modules/mcc/include/opencv2/mcc/operations.hpp new file mode 100644 index 00000000000..14c3c77162f --- /dev/null +++ b/modules/mcc/include/opencv2/mcc/operations.hpp @@ -0,0 +1,142 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +/* + * MIT License + * + * Copyright (c) 2018 Pedro Diamel Marrero Fernández + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __OPENCV_MCC_OPERATIONS_HPP__ +#define __OPENCV_MCC_OPERATIONS_HPP__ + +#include +#include +#include "opencv2/mcc/utils.hpp" + +namespace cv +{ +namespace ccm +{ + +typedef std::function MatFunc; + +/* *\ brief Operation class contains some operarions used for color space + * conversion containing linear transformation and non-linear transformation + */ +class Operation +{ +public: + bool linear; + cv::Mat M; + MatFunc f; + + Operation() : linear(true), M(cv::Mat()) {}; + + Operation(cv::Mat M) :linear(true), M( M ) {}; + + Operation(MatFunc f) : linear(false), f(f) {}; + + virtual ~Operation() {}; + /* *\ brief operator function will run operation*/ + cv::Mat operator()(cv::Mat& abc) + { + if (!linear) + { + return f(abc); + } + if (M.empty()) + { + return abc; + } + return multiple(abc, M); + }; + + /* *\ brief add function will conbine this operation + * with other linear transformation operation*/ + void add(const Operation& other) + { + if (M.empty()) + { + M = other.M.clone(); + } + else + { + M = M * other.M; + } + }; + + void clear() + { + M = cv::Mat(); + }; +}; + +const Operation IDENTITY_OP( [](cv::Mat x) {return x; } ); + +class Operations +{ +public: + std::vector ops; + + Operations() :ops{ } {}; + + Operations(std::initializer_list op) :ops{ op } {}; + + virtual ~Operations() {}; + + /* *\ brief add function will conbine this operation with other transformation operations*/ + Operations& add(const Operations& other) + { + ops.insert(ops.end(), other.ops.begin(), other.ops.end()); + return *this; + }; + + /* *\ brief run operations to make color conversion*/ + cv::Mat run(cv::Mat abc) + { + Operation hd; + for (auto& op : ops) + { + if (op.linear) + { + hd.add(op); + } + else + { + abc = hd(abc); + hd.clear(); + abc = op(abc); + } + } + abc = hd(abc); + return abc; + }; +}; + +const Operations IDENTITY_OPS{ IDENTITY_OP }; + +} // namespace ccm +} // namespace cv + + +#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/utils.hpp b/modules/mcc/include/opencv2/mcc/utils.hpp new file mode 100644 index 00000000000..8cb713200fd --- /dev/null +++ b/modules/mcc/include/opencv2/mcc/utils.hpp @@ -0,0 +1,230 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +/* + * MIT License + * + * Copyright (c) 2018 Pedro Diamel Marrero Fernández + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __OPENCV_MCC_UTILS_HPP__ +#define __OPENCV_MCC_UTILS_HPP__ + +#include +#include +#include +#include +#include + +namespace cv +{ +namespace ccm +{ + +/* *\ brief function for elementWise operation + *\ param src the input array, type of cv::Mat + *\ lambda a for operation +*/ +template +cv::Mat elementWise(const cv::Mat& src, F&& lambda) +{ + cv::Mat dst = src.clone(); + const int channel = src.channels(); + switch (channel) + { + case 1: + { + cv::MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) + { + (*it) = lambda((*it)); + } + break; + } + case 3: + { + cv::MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) + { + for (int j = 0; j < 3; j++) + { + (*it)[j] = lambda((*it)[j]); + } + } + break; + } + default: + throw std::invalid_argument { "Wrong channel!" }; + break; + } + return dst; +} + +/* *\ brief function for channel operation + *\ param src the input array, type of cv::Mat + *\ lambda the function for operation +*/ +template +cv::Mat channelWise(const cv::Mat& src, F&& lambda) +{ + cv::Mat dst = src.clone(); + cv::MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) + { + *it = lambda(*it); + } + return dst; +} + +/* *\ brief function for distance operation. + *\ param src the input array, type of cv::Mat. + *\ param ref another input array, type of cv::Mat. + *\ param lambda the computing method for distance . +*/ +template +cv::Mat distanceWise(cv::Mat& src, cv::Mat& ref, F&& lambda) +{ + cv::Mat dst = cv::Mat(src.size(), CV_64FC1); + cv::MatIterator_ it_src = src.begin(), end_src = src.end(), + it_ref = ref.begin(), end_ref = ref.end(); + cv::MatIterator_ it_dst = dst.begin(), end_dst = dst.end(); + for (; it_src != end_src; ++it_src, ++it_ref, ++it_dst) + { + *it_dst = lambda(*it_src, *it_ref); + } + return dst; +} + + +double gammaCorrection_(const double& element, const double& gamma) +{ + return (element >= 0 ? pow(element, gamma) : -pow((-element), gamma)); +} + +/* *\ brief gamma correction ,see ColorSpace.pdf for details. + *\ param src the input array,type of cv::Mat. + *\ param gamma a constant for gamma correction . +*/ +cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma) +{ + return elementWise(src, [gamma](double element)->double {return gammaCorrection_(element, gamma); }); +} + +/* *\ brief maskCopyTo a function to delete unsatisfied elementwise . + *\ param src the input array, type of cv::Mat. + *\ param mask operation mask that used to choose satisfided elementwise. + */ +cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) +{ + cv::Mat dst(countNonZero(mask), 1, src.type()); + const int channel = src.channels(); + auto it_mask = mask.begin(), end_mask = mask.end(); + switch (channel) + { + case 1: + { + auto it_src = src.begin(), end_src = src.end(); + auto it_dst = dst.begin(), end_dst = dst.end(); + for (; it_src != end_src; ++it_src, ++it_mask) + { + if (*it_mask) + { + (*it_dst) = (*it_src); + ++it_dst; + } + } + break; + } + case 3: + { + auto it_src = src.begin(), end_src = src.end(); + auto it_dst = dst.begin(), end_dst = dst.end(); + for (; it_src != end_src; ++it_src, ++it_mask) + { + if (*it_mask) + { + (*it_dst) = (*it_src); + ++it_dst; + } + } + break; + } + default: + throw std::invalid_argument { "Wrong channel!" }; + break; + } + return dst; +} + +/* *\ brief multiple the function used to compute an array with n channels mulipied by ccm . + *\ param src the input array, type of cv::Mat. + *\ param ccm the ccm matrix to make color correction. +*/ +cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm) +{ + cv::Mat tmp = xyz.reshape(1, xyz.rows * xyz.cols); + cv::Mat res = tmp * ccm; + res = res.reshape(res.cols, xyz.rows); + return res; +} + +/* *\ brief multiple the function used to get the mask of saturated colors, + colors between low and up will be choosed. + *\ param src the input array, type of cv::Mat. + *\ param low the threshold to choose saturated colors + *\ param up the threshold to choose saturated colors +*/ +cv::Mat saturate(cv::Mat& src, const double& low, const double& up) +{ + cv::Mat dst = cv::Mat::ones(src.size(), CV_8UC1); + cv::MatIterator_ it_src = src.begin(), end_src = src.end(); + cv::MatIterator_ it_dst = dst.begin(), end_dst = dst.end(); + for (; it_src != end_src; ++it_src, ++it_dst) + { + for (int i = 0; i < 3; ++i) + { + if ((*it_src)[i] > up || (*it_src)[i] < low) + { + *it_dst = 0.; + break; + } + } + } + return dst; +} + +const static cv::Mat m_gray = (cv::Mat_(3, 1) << 0.2126, 0.7152, 0.0722); + +/* *\ brief rgb2gray it is an approximation grayscale function for relative RGB color space, + * see Miscellaneous.pdf for details; + *\ param rgb the input array, type of cv::Mat. + */ +cv::Mat rgb2gray(cv::Mat rgb) +{ + return multiple(rgb, m_gray); +} + +} // namespace ccm +} // namespace cv + + +#endif From 51a8d664cdc8e21138feb8cf508c182fa02f314c Mon Sep 17 00:00:00 2001 From: Jinheng Zhang Date: Mon, 31 Aug 2020 03:49:23 +0000 Subject: [PATCH 02/71] Add the code for color, colorspace, linearization and ccm computation --- modules/mcc/include/opencv2/mcc/ccm.hpp | 532 +++++++++++++++ modules/mcc/include/opencv2/mcc/color.hpp | 249 +++++++ .../mcc/include/opencv2/mcc/colorspace.hpp | 636 ++++++++++++++++++ modules/mcc/include/opencv2/mcc/linearize.hpp | 300 +++++++++ 4 files changed, 1717 insertions(+) create mode 100644 modules/mcc/include/opencv2/mcc/ccm.hpp create mode 100644 modules/mcc/include/opencv2/mcc/color.hpp create mode 100644 modules/mcc/include/opencv2/mcc/colorspace.hpp create mode 100644 modules/mcc/include/opencv2/mcc/linearize.hpp diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp new file mode 100644 index 00000000000..a2038af02e5 --- /dev/null +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -0,0 +1,532 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +/* + * MIT License + * + * Copyright (c) 2018 Pedro Diamel Marrero Fernández + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __OPENCV_MCC_CCM_HPP__ +#define __OPENCV_MCC_CCM_HPP__ + +#include +#include +#include +#include +#include +#include +#include +#include "opencv2/mcc/linearize.hpp" + +namespace cv +{ +namespace ccm +{ + +/** + src : + detected colors of ColorChecker patches; + NOTICE: the color type is RGB not BGR, and the color values are in [0, 1]; + type: cv::Mat; + dst : + the reference colors; + NOTICE: Built-in color card or custom color card are supported; + Built-in: + Macbeth_D50_2: Macbeth ColorChecker with 2deg D50; + Macbeth_D65_2: Macbeth ColorChecker with 2deg D65; + Custom: + You should use Color + For the list of color spaces supported, see the notes below; + If the color type is some RGB, the format is RGB not BGR, and the color values are in [0, 1]; + type: Color; + colorspace : + the absolute color space that detected colors convert to; + NOTICE: it should be some RGB color space; + For the list of RGB color spaces supported, see the notes below; + type: ColorSpace; + ccm_type : + the shape of color correction matrix(CCM); + Supported list: + "CCM_3x3": 3x3 matrix; + "CCM_4x3": 4x3 matrix; + type: enum CCM_TYPE; + default: CCM_3x3; + distance : + the type of color distance; + Supported list: + "CIE2000"; + "CIE94_GRAPHIC_ARTS"; + "CIE94_TEXTILES"; + "CIE76"; + "CMC_1TO1"; + "CMC_2TO1"; + "RGB" : Euclidean distance of rgb color space; + "RGBL" : Euclidean distance of rgbl color space; + type: enum DISTANCE_TYPE; + default: CIE2000; + linear : + the method of linearization; + NOTICE: see Linearization.pdf for details; + Supported list: + "IDENTITY_" : no change is made; + "GAMMA": gamma correction; + Need assign a value to gamma simultaneously; + "COLORPOLYFIT": polynomial fitting channels respectively; + Need assign a value to deg simultaneously; + "GRAYPOLYFIT": grayscale polynomial fitting; + Need assign a value to deg and dst_whites simultaneously; + "COLORLOGPOLYFIT": logarithmic polynomial fitting channels respectively; + Need assign a value to deg simultaneously; + "GRAYLOGPOLYFIT": grayscale Logarithmic polynomial fitting; + Need assign a value to deg and dst_whites simultaneously; + type: enum LINEAR_TYPE; + default: IDENTITY_; + gamma : + the gamma value of gamma correction; + NOTICE: only valid when linear is set to "gamma"; + type: double; + default: 2.2; + + deg : + the degree of linearization polynomial; + NOTICE: only valid when linear is set to "COLORPOLYFIT", "GRAYPOLYFIT", + "COLORLOGPOLYFIT" and "GRAYLOGPOLYFIT"; + type: int; + default: 3; + saturated_threshold : + the threshold to determine saturation; + NOTICE: it is a tuple of [low, up]; + The colors in the closed interval [low, up] are reserved to participate + in the calculation of the loss function and initialization parameters. + type: std::vector; + default: { 0, 0.98 }; + --------------------------------------------------- + There are some ways to set weights: + 1. set weights_list only; + 2. set weights_coeff only; + see CCM.pdf for details; + + weights_list : + the list of weight of each color; + type: cv::Mat; + default: empty array; + + weights_coeff : + the exponent number of L* component of the reference color in CIE Lab color space; + type: double; + default: 0; + --------------------------------------------------- + initial_method_type : + the method of calculating CCM initial value; + see CCM.pdf for details; + Supported list: + 'LEAST_SQUARE': least-squre method; + 'WHITE_BALANCE': white balance method; + type: enum INITIAL_METHOD_TYPE; + + max_count, epsilon : + used in MinProblemSolver-DownhillSolver; + Terminal criteria to the algorithm; + type: int, double; + default: 5000, 1e-4; + + + --------------------------------------------------- + Supported Color Space: + Supported list of RGB color spaces: + sRGB; + AdobeRGB; + WideGamutRGB; + ProPhotoRGB; + DCI_P3_RGB; + AppleRGB; + REC_709_RGB; + REC_2020_RGB; + + Supported list of linear RGB color spaces: + sRGBL; + AdobeRGBL; + WideGamutRGBL; + ProPhotoRGBL; + DCI_P3_RGBL; + AppleRGBL; + REC_709_RGBL; + REC_2020_RGBL; + + Supported list of non-RGB color spaces: + Lab_D50_2; + Lab_D65_2; + XYZ_D50_2; + XYZ_D65_2; + + Supported IO (You can use Lab(io) or XYZ(io) to create color space): + A_2; + A_10; + D50_2; + D50_10; + D55_2; + D55_10; + D65_2; + D65_10; + D75_2; + D75_10; + E_2; + E_10; + + + --------------------------------------------------- + Abbr. + src, s: source; + dst, d: destination; + io: illuminant & observer; + sio, dio: source of io; destination of io; + rgbl: linear RGB + cs: color space; + cc: Colorchecker; + M, m: matrix + ccm: color correction matrix; + cam: chromatic adaption matrix; + +*/ + + +/* *\ brief Enum of the possible types of ccm. +*/ +enum CCM_TYPE +{ + CCM_3x3, + CCM_4x3 +}; + +/* *\ brief Enum of the possible types of initial method. +*/ +enum INITIAL_METHOD_TYPE +{ + WHITE_BALANCE, + LEAST_SQUARE +}; + + +/* *\ brief Core class of ccm model. + * produce a ColorCorrectionModel instance for inference. +*/ +class ColorCorrectionModel +{ +public: + // detected colors, the referenceand the RGB colorspace for conversion + cv::Mat src; + Color dst; + RGBBase_ &cs; + + // ccm type and shape + CCM_TYPE ccm_type; + int shape; + + // linear method and distance + std::shared_ptr linear; + DISTANCE_TYPE distance; + + cv::Mat weights; + cv::Mat ccm; + cv::Mat ccm0; + + int max_count; + double epsilon; + + ColorCorrectionModel(cv::Mat src, Color dst, RGBBase_ &cs, CCM_TYPE ccm_type, DISTANCE_TYPE distance, LINEAR_TYPE linear, + double gamma, int deg, std::vector saturated_threshold, cv::Mat weights_list, double weights_coeff, + INITIAL_METHOD_TYPE initial_method_type, int max_count, double epsilon) : + src(src), dst(dst), cs(cs), ccm_type(ccm_type), distance(distance), max_count(max_count), epsilon(epsilon) + { + cv::Mat saturate_mask = saturate(src, saturated_threshold[0], saturated_threshold[1]); + this->linear = getLinear(gamma, deg, this->src, this->dst, saturate_mask, this->cs, linear); + calWeightsMasks(weights_list, weights_coeff, saturate_mask); + + src_rgbl = this->linear->linearize(maskCopyTo(this->src, mask)); + this->dst = this->dst[mask]; + dst_rgbl = maskCopyTo(this->dst.to(*(this->cs.l)).colors, mask); + + // make no change for CCM_3x3, make change for CCM_4x3. + src_rgbl = prepare(src_rgbl); + + // distance function may affect the loss function and the fitting function + switch (this->distance) + { + case cv::ccm::RGBL: + initialLeastSquare(true); + break; + default: + switch (initial_method_type) + { + case cv::ccm::WHITE_BALANCE: + initialWhiteBalance(); + break; + case cv::ccm::LEAST_SQUARE: + initialLeastSquare(); + break; + default: + throw std::invalid_argument{"Wrong initial_methoddistance_type!"}; + break; + } + break; + } + + fitting(); + } + + /* *\ brief Make no change for CCM_3x3. + * convert cv::Mat A to [A, 1] in CCM_4x3. + *\ param inp the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat + */ + cv::Mat prepare(const cv::Mat &inp) + { + switch (ccm_type) + { + case cv::ccm::CCM_3x3: + shape = 9; + return inp; + case cv::ccm::CCM_4x3: + { + shape = 12; + cv::Mat arr1 = cv::Mat::ones(inp.size(), CV_64F); + cv::Mat arr_out(inp.size(), CV_64FC4); + cv::Mat arr_channels[3]; + split(inp, arr_channels); + merge(std::vector{arr_channels[0], arr_channels[1], arr_channels[2], arr1}, arr_out); + return arr_out; + } + default: + throw std::invalid_argument{"Wrong ccm_type!"}; + break; + } + }; + + /* *\ brief Fitting nonlinear - optimization initial value by white balance. + * see CCM.pdf for details. + *\ return the output array, type of cv::Mat + */ + cv::Mat initialWhiteBalance(void) + { + cv::Mat schannels[3]; + split(src_rgbl, schannels); + cv::Mat dchannels[3]; + split(dst_rgbl, dchannels); + std::vector initial_vec = { sum(dchannels[0])[0] / sum(schannels[0])[0], 0, 0, 0, + sum(dchannels[1])[0] / sum(schannels[1])[0], 0, 0, 0, + sum(dchannels[2])[0] / sum(schannels[2])[0], 0, 0, 0 }; + std::vector initial_vec_(initial_vec.begin(), initial_vec.begin() + shape); + cv::Mat initial_white_balance = cv::Mat(initial_vec_, true).reshape(0, shape / 3); + + return initial_white_balance; + }; + + /* *\ brief Fitting nonlinear-optimization initial value by least square. + * see CCM.pdf for details + *\ param fit if fit is True, return optimalization for rgbl distance function. + */ + void initialLeastSquare(bool fit = false) + { + cv::Mat A, B, w; + if (weights.empty()) + { + A = src_rgbl; + B = dst_rgbl; + } + else + { + pow(weights, 0.5, w); + cv::Mat w_; + merge(std::vector{w, w, w}, w_); + A = w_.mul(src_rgbl); + B = w_.mul(dst_rgbl); + } + solve(A.reshape(1, A.rows), B.reshape(1, B.rows), ccm0, DECOMP_SVD); + + // if fit is True, return optimalization for rgbl distance function. + if (fit) + { + ccm = ccm0; + cv::Mat residual = A.reshape(1, A.rows) * ccm.reshape(0, shape / 3) - B.reshape(1, B.rows); + Scalar s = residual.dot(residual); + double sum = s[0]; + loss = sqrt(sum / masked_len); + } + }; + + /* *\ brief Loss function base on cv::MinProblemSolver::Function. + * see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp + */ + class LossFunction : public cv::MinProblemSolver::Function + { + public: + ColorCorrectionModel *ccm_loss; + LossFunction(ColorCorrectionModel *ccm) : ccm_loss(ccm){}; + + /* *\ brief Reset dims to ccm->shape. + */ + int getDims() const + { + return ccm_loss->shape; + } + + /* *\ brief Reset calculation. + */ + double calc(const double *x) const + { + cv::Mat ccm(ccm_loss->shape, 1, CV_64F); + for (int i = 0; i < ccm_loss->shape; i++) + { + ccm.at(i, 0) = x[i]; + } + ccm = ccm.reshape(0, ccm_loss->shape / 3); + Mat reshapecolor = ccm_loss->src_rgbl.reshape(1, 0) * ccm; + cv::Mat dist = Color(reshapecolor.reshape(3, 0), ccm_loss->cs).diff(ccm_loss->dst, ccm_loss->distance); + cv::Mat dist_; + pow(dist, 2, dist_); + if (!ccm_loss->weights.empty()) + { + dist_ = ccm_loss->weights.mul(dist_); + } + Scalar ss = sum(dist_); + return ss[0]; + } + }; + + /* *\ brief Fitting ccm if distance function is associated with CIE Lab color space. + * see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp + * Set terminal criteria for solver is possible. + */ + void fitting(void) + { + cv::Ptr solver = cv::DownhillSolver::create(); + cv::Ptr ptr_F(new LossFunction(this)); + solver->setFunction(ptr_F); + cv::Mat reshapeccm = ccm0.reshape(0, 1); + cv::Mat step = cv::Mat::ones(reshapeccm.size(), CV_64F); + solver->setInitStep(step * 10); + /* TermCriteria termcrit = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, max_count, epsilon); + solver->setTermCriteria(termcrit);*/ + double res = solver->minimize(reshapeccm); + ccm = reshapeccm.reshape(0, shape); + double loss = pow((res / masked_len), 0.5); + //std::cout << " ccm " << ccm << std::endl; + //std::cout << " loss " << loss << std::endl; + }; + + /* *\ brief Infer using fitting ccm. + *\ param img the input image, type of cv::Mat. + *\ return the output array, type of cv::Mat. + */ + cv::Mat infer(const cv::Mat &img, bool islinear = false) + { + if (!ccm.data) + { + throw "No CCM values!"; + } + cv::Mat img_lin = linear->linearize(img); + cv::Mat img_ccm(img_lin.size(), img_lin.type()); + cv::Mat ccm_ = ccm.reshape(0, shape / 3); + img_ccm = multiple(prepare(img_lin), ccm_); + if (islinear == true) + { + return img_ccm; + } + return cs.fromL(img_ccm); + }; + + /* *\ brief Infer image and output as an BGR image with uint8 type. + * mainly for test or debug. + * input size and output size should be 255. + *\ param imgfile path name of image to infer. + *\ param islinear if linearize or not. + *\ return the output array, type of cv::Mat. + */ + cv::Mat inferImage(std::string imgfile, bool islinear = false) + { + const int inp_size = 255; + const int out_size = 255; + cv::Mat img = imread(imgfile); + cv::Mat img_; + cvtColor(img, img_, COLOR_BGR2RGB); + img_.convertTo(img_, CV_64F); + img_ = img_ / inp_size; + cv::Mat out = this->infer(img_, islinear); + cv::Mat out_ = out * out_size; + out_.convertTo(out_, CV_8UC3); + cv::Mat img_out = min(max(out_, 0), out_size); + cv::Mat out_img; + cvtColor(img_out, out_img, COLOR_RGB2BGR); + return out_img; + }; + +private: + cv::Mat mask; + cv::Mat dist; + int masked_len; + double loss; + + // RGBl of detected data and the reference + cv::Mat src_rgbl; + cv::Mat dst_rgbl; + + /* *\ brief Calculate weights and mask. + *\ param weights_list the input array, type of cv::Mat. + *\ param weights_coeff type of double. + *\ param saturate_list the input array, type of cv::Mat. + */ + void calWeightsMasks(cv::Mat weights_list, double weights_coeff, cv::Mat saturate_mask) + { + // weights + if (!weights_list.empty()) + { + weights = weights_list; + } + else if (weights_coeff != 0) + { + pow(dst.toLuminant(dst.cs.io), weights_coeff, weights); + } + + // masks + cv::Mat weight_mask = cv::Mat::ones(src.rows, 1, CV_8U); + if (!weights.empty()) + { + weight_mask = weights > 0; + } + this->mask = (weight_mask) & (saturate_mask); + + // weights' mask + if (!weights.empty()) + { + cv::Mat weights_masked = maskCopyTo(this->weights, this->mask); + weights = weights_masked / mean(weights_masked); + } + masked_len = sum(mask)[0]; + }; +}; + +} // namespace ccm +} // namespace cv + + +#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/color.hpp b/modules/mcc/include/opencv2/mcc/color.hpp new file mode 100644 index 00000000000..05634c8cafd --- /dev/null +++ b/modules/mcc/include/opencv2/mcc/color.hpp @@ -0,0 +1,249 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +/* + * MIT License + * + * Copyright (c) 2018 Pedro Diamel Marrero Fernández + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __OPENCV_MCC_COLOR_HPP__ +#define __OPENCV_MCC_COLOR_HPP__ + +#include +#include "opencv2/mcc/colorspace.hpp" +#include "opencv2/mcc/distance.hpp" +#include "opencv2/mcc/utils.hpp" + +namespace cv +{ +namespace ccm +{ + +/* *\ brief Color defined by color_values and color space +*/ + +class Color +{ +public: + + /* *\ param grays mask of grayscale color + *\ param colored mask of colored color + *\ param history storage of historical conversion + */ + cv::Mat colors; + const ColorSpace& cs; + cv::Mat grays; + cv::Mat colored; + std::map> history; + + Color(cv::Mat colors, const ColorSpace& cs) :colors(colors), cs(cs) {}; + + virtual ~Color() {}; + + /* *\ brief Change to other color space. + * The conversion process incorporates linear transformations to speed up. + * method is chromatic adapation method. + * when save if True, get data from history first. + *\ param other type of ColorSpace. + *\ return Color. + */ + Color to(const ColorSpace& other, CAM method = BRADFORD, bool save = true) + { + if (history.count(other) == 1) + { + + return *history[other]; + } + if (cs.relate(other)) + { + return Color(cs.relation(other).run(colors), other); + } + Operations ops; + ops.add(cs.to).add(XYZ(cs.io).cam(other.io, method)).add(other.from); + std::shared_ptr color(new Color(ops.run(colors), other)); + if (save) + { + history[other] = color; + } + return *color; + } + + /* *\ brief Channels split. + *\ return each channel. + */ + cv::Mat channel(cv::Mat m, int i) + { + cv::Mat dchannels[3]; + split(m, dchannels); + return dchannels[i]; + } + + /* *\ brief To Gray. + */ + cv::Mat toGray(IO io, CAM method = BRADFORD, bool save = true) + { + XYZ xyz(io); + return channel(this->to(xyz, method, save).colors, 1); + } + + /* *\ brief To Luminant. + */ + cv::Mat toLuminant(IO io, CAM method = BRADFORD, bool save = true) + { + Lab lab(io); + return channel(this->to(lab, method, save).colors, 0); + } + + /* *\ brief Diff without IO. + *\ param other type of Color. + *\ param method type of distance. + *\ return distance between self and other + */ + cv::Mat diff(Color& other, DISTANCE_TYPE method = CIE2000) + { + return diff(other, cs.io, method); + } + + /* *\ brief Diff with IO. + *\ param other type of Color. + *\ param io type of IO. + *\ param method type of distance. + *\ return distance between self and other + */ + cv::Mat diff(Color& other, IO io, DISTANCE_TYPE method = CIE2000) + { + Lab lab(io); + switch (method) + { + case cv::ccm::CIE76: + case cv::ccm::CIE94_GRAPHIC_ARTS: + case cv::ccm::CIE94_TEXTILES: + case cv::ccm::CIE2000: + case cv::ccm::CMC_1TO1: + case cv::ccm::CMC_2TO1: + return distance(to(lab).colors, other.to(lab).colors, method); + case cv::ccm::RGB: + return distance(to(*cs.nl).colors, other.to(*cs.nl).colors, method); + case cv::ccm::RGBL: + return distance(to(*cs.l).colors, other.to(*cs.l).colors, method); + default: + throw std::invalid_argument { "Wrong method!" }; + break; + } + } + + /* *\ brief Calculate gray mask. + */ + void getGray(double JDN = 2.0) + { + cv::Mat lab = to(Lab_D65_2).colors; + cv::Mat gray(colors.size(), colors.type()); + int fromto[] = { 0,0, -1,1, -1,2 }; + mixChannels(&lab, 1, &gray, 1, fromto, 3); + cv::Mat d = distance(lab, gray, CIE2000); + this->grays = d < JDN; + this->colored = ~grays; + } + + /* *\ brief Operator for mask copy. + */ + Color operator[](cv::Mat mask) + { + return Color(maskCopyTo(colors, mask), cs); + } + + Color operator=(Color inp) + { + return inp; + } +}; + + +/* *\ brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls + * see Miscellaneous.md for details. +*/ +const cv::Mat ColorChecker2005_LAB_D50_2 = (cv::Mat_(24, 1) << + cv::Vec3d(37.986, 13.555, 14.059), + cv::Vec3d(65.711, 18.13, 17.81), + cv::Vec3d(49.927, -4.88, -21.925), + cv::Vec3d(43.139, -13.095, 21.905), + cv::Vec3d(55.112, 8.844, -25.399), + cv::Vec3d(70.719, -33.397, -0.199), + cv::Vec3d(62.661, 36.067, 57.096), + cv::Vec3d(40.02, 10.41, -45.964), + cv::Vec3d(51.124, 48.239, 16.248), + cv::Vec3d(30.325, 22.976, -21.587), + cv::Vec3d(72.532, -23.709, 57.255), + cv::Vec3d(71.941, 19.363, 67.857), + cv::Vec3d(28.778, 14.179, -50.297), + cv::Vec3d(55.261, -38.342, 31.37), + cv::Vec3d(42.101, 53.378, 28.19), + cv::Vec3d(81.733, 4.039, 79.819), + cv::Vec3d(51.935, 49.986, -14.574), + cv::Vec3d(51.038, -28.631, -28.638), + cv::Vec3d(96.539, -0.425, 1.186), + cv::Vec3d(81.257, -0.638, -0.335), + cv::Vec3d(66.766, -0.734, -0.504), + cv::Vec3d(50.867, -0.153, -0.27), + cv::Vec3d(35.656, -0.421, -1.231), + cv::Vec3d(20.461, -0.079, -0.973)); + +const cv::Mat ColorChecker2005_LAB_D65_2 = (cv::Mat_(24, 1) << + cv::Vec3d(37.542, 12.018, 13.33), + cv::Vec3d(65.2, 14.821, 17.545), + cv::Vec3d(50.366, -1.573, -21.431), + cv::Vec3d(43.125, -14.63, 22.12), + cv::Vec3d(55.343, 11.449, -25.289), + cv::Vec3d(71.36, -32.718, 1.636), + cv::Vec3d(61.365, 32.885, 55.155), + cv::Vec3d(40.712, 16.908, -45.085), + cv::Vec3d(49.86, 45.934, 13.876), + cv::Vec3d(30.15, 24.915, -22.606), + cv::Vec3d(72.438, -27.464, 58.469), + cv::Vec3d(70.916, 15.583, 66.543), + cv::Vec3d(29.624, 21.425, -49.031), + cv::Vec3d(55.643, -40.76, 33.274), + cv::Vec3d(40.554, 49.972, 25.46), + cv::Vec3d(80.982, -1.037, 80.03), + cv::Vec3d(51.006, 49.876, -16.93), + cv::Vec3d(52.121, -24.61, -26.176), + cv::Vec3d(96.536, -0.694, 1.354), + cv::Vec3d(81.274, -0.61, -0.24), + cv::Vec3d(66.787, -0.647, -0.429), + cv::Vec3d(50.872, -0.059, -0.247), + cv::Vec3d(35.68, -0.22, -1.205), + cv::Vec3d(20.475, 0.049, -0.972)); + +/* *\ brief Macbeth ColorChecker with 2deg D50. +*/ +const Color Macbeth_D50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2); + +/* *\ brief Macbeth ColorChecker with 2deg D65. +*/ +const Color Macbeth_D65_2(ColorChecker2005_LAB_D65_2, Lab_D65_2); + +} // namespace ccm +} // namespace cv + + +#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp new file mode 100644 index 00000000000..8cf8c4b6713 --- /dev/null +++ b/modules/mcc/include/opencv2/mcc/colorspace.hpp @@ -0,0 +1,636 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +/* + * MIT License + * + * Copyright (c) 2018 Pedro Diamel Marrero Fernández + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __OPENCV_MCC_COLORSPACE_HPP__ +#define __OPENCV_MCC_COLORSPACE_HPP__ + +#include +#include +#include +#include "opencv2/mcc/io.hpp" +#include "opencv2/mcc/operations.hpp" +#include "opencv2/mcc/utils.hpp" + +namespace cv +{ +namespace ccm +{ + +/* *\ brief Basic class for ColorSpace. +*/ +class ColorSpace +{ +public: + IO io; + std::string type; + bool linear; + Operations to; + Operations from; + ColorSpace* l = 0; + ColorSpace* nl = 0; + + ColorSpace() {}; + + ColorSpace(IO io, std::string type, bool linear) :io(io), type(type), linear(linear) {}; + + virtual ~ColorSpace() + { + l = 0; + nl = 0; + }; + + virtual bool relate(const ColorSpace& other) const + { + return (type == other.type) && (io == other.io); + }; + + virtual Operations relation(const ColorSpace& other) const + { + return IDENTITY_OPS; + }; + + bool operator<(const ColorSpace& other)const + { + return (io < other.io || (io == other.io && type < other.type) || (io == other.io && type == other.type && linear < other.linear)); + } +}; + +/* *\ brief Base of RGB color space; + * the argument values are from AdobeRGB; + * Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space +*/ +class RGBBase_ : public ColorSpace +{ +public: + // primaries + double xr; + double yr; + double xg; + double yg; + double xb; + double yb; + MatFunc toL; + MatFunc fromL; + cv::Mat M_to; + cv::Mat M_from; + + using ColorSpace::ColorSpace; + + /* *\ brief There are 3 kinds of relationships for RGB: + * 1. Different types; - no operation + * 1. Same type, same linear; - copy + * 2. Same type, different linear, self is nonlinear; - 2 toL + * 3. Same type, different linear, self is linear - 3 fromL + *\ param other type of ColorSpace. + *\ return Operations. + */ + virtual Operations relation(const ColorSpace& other) const + { + if (linear == other.linear) + { + return IDENTITY_OPS; + } + if (linear) + { + return Operations({ Operation(fromL) }); + } + return Operations({ Operation(toL) }); + }; + + /* *\ brief Initial operations. + */ + void init() + { + setParameter(); + calLinear(); + calM(); + calOperations(); + } + + /* *\ brief Produce color space instance with linear and non-linear versions. + *\ param rgbl type of RGBBase_. + */ + void bind(RGBBase_& rgbl) + { + init(); + rgbl.init(); + l = &rgbl; + rgbl.l = &rgbl; + nl = this; + rgbl.nl = this; + } + +private: + virtual void setParameter() {}; + + /* *\ brief Calculation of M_RGBL2XYZ_base. + * see ColorSpace.pdf for details. + */ + virtual void calM() + { + cv::Mat XYZr, XYZg, XYZb, XYZ_rgbl, Srgb; + XYZr = cv::Mat(xyY2XYZ({ xr, yr }), true); + XYZg = cv::Mat(xyY2XYZ({ xg, yg }), true); + XYZb = cv::Mat(xyY2XYZ({ xb, yb }), true); + merge(std::vector{ XYZr, XYZg, XYZb }, XYZ_rgbl); + XYZ_rgbl = XYZ_rgbl.reshape(1, XYZ_rgbl.rows); + cv::Mat XYZw = cv::Mat(illuminants.find(io)->second, true); + solve(XYZ_rgbl, XYZw, Srgb); + merge(std::vector{ Srgb.at(0)* XYZr, + Srgb.at(1)* XYZg, + Srgb.at(2)* XYZb }, M_to); + M_to = M_to.reshape(1, M_to.rows); + M_from = M_to.inv(); + }; + + /* *\ brief operations to or from XYZ. + */ + virtual void calOperations() + { + // rgb -> rgbl + toL = [this](cv::Mat rgb)->cv::Mat {return toLFunc(rgb); }; + + // rgbl -> rgb + fromL = [this](cv::Mat rgbl)->cv::Mat {return fromLFunc(rgbl); }; + + if (linear) + { + to = Operations({ Operation(M_to.t()) }); + from = Operations({ Operation(M_from.t()) }); + } + else + { + to = Operations({ Operation(toL), Operation(M_to.t()) }); + from = Operations({ Operation(M_from.t()), Operation(fromL) }); + } + } + + virtual void calLinear() {} + + virtual cv::Mat toLFunc(cv::Mat& rgb) + { + return cv::Mat(); + }; + + virtual cv::Mat fromLFunc(cv::Mat& rgbl) + { + return cv::Mat(); + }; + +}; + +/* *\ brief Base of Adobe RGB color space; +*/ +class AdobeRGBBase_ : public RGBBase_ +{ +public: + using RGBBase_::RGBBase_; + double gamma; + +private: + virtual cv::Mat toLFunc(cv::Mat& rgb) + { + return gammaCorrection(rgb, gamma); + } + + virtual cv::Mat fromLFunc(cv::Mat& rgbl) + { + return gammaCorrection(rgbl, 1. / gamma); + } +}; + +/* *\ brief Base of sRGB color space; +*/ +class sRGBBase_ : public RGBBase_ +{ +public: + using RGBBase_::RGBBase_; + double a; + double gamma; + double alpha; + double beta; + double phi; + double K0; + +private: + /* *\ brief linearization parameters + * see ColorSpace.pdf for details; + */ + virtual void calLinear() + { + alpha = a + 1; + K0 = a / (gamma - 1); + phi = (pow(alpha, gamma) * pow(gamma - 1, gamma - 1)) / (pow(a, gamma - 1) * pow(gamma, gamma)); + beta = K0 / phi; + } + + /* *\ brief Used by toLFunc. + */ + double toLFuncEW(double& x) + { + if (x > K0) + { + return pow(((x + alpha - 1) / alpha), gamma); + } + else if (x >= -K0) + { + return x / phi; + } + else + { + return -(pow(((-x + alpha - 1) / alpha), gamma)); + } + } + + /* *\ brief Linearization. + * see ColorSpace.pdf for details. + *\ param rgb the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat. + */ + cv::Mat toLFunc(cv::Mat& rgb) + { + return elementWise(rgb, [this](double a)->double {return toLFuncEW(a); }); + } + + /* *\ brief Used by fromLFunc. + */ + double fromLFuncEW(double& x) + { + if (x > beta) + { + return alpha * pow(x, 1 / gamma) - (alpha - 1); + } + else if (x >= -beta) + { + return x * phi; + } + else { + return -(alpha * pow(-x, 1 / gamma) - (alpha - 1)); + } + } + + /* *\ brief Delinearization. + * see ColorSpace.pdf for details. + *\ param rgbl the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat. + */ + cv::Mat fromLFunc(cv::Mat& rgbl) + { + return elementWise(rgbl, [this](double a)->double {return fromLFuncEW(a); }); + } +}; + +/* *\ brief sRGB color space. + * data from https://en.wikipedia.org/wiki/SRGB. +*/ +class sRGB_ :public sRGBBase_ +{ +public: + sRGB_(bool linear) :sRGBBase_(D65_2, "sRGB", linear) {}; + +private: + void setParameter() + { + xr = 0.64; + yr = 0.33; + xg = 0.3; + yg = 0.6; + xb = 0.15; + yb = 0.06; + a = 0.055; + gamma = 2.4; + } +}; + +/* *\ brief Adobe RGB color space. +*/ +class AdobeRGB_ : public AdobeRGBBase_ +{ +public: + AdobeRGB_(bool linear = false) :AdobeRGBBase_(D65_2, "AdobeRGB", linear) {}; + +private: + void setParameter() + { + xr = 0.64; + yr = 0.33; + xg = 0.21; + yg = 0.71; + xb = 0.15; + yb = 0.06; + gamma = 2.2; + } +}; + +/* *\ brief Wide-gamut RGB color space. + * data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. +*/ +class WideGamutRGB_ : public AdobeRGBBase_ +{ +public: + WideGamutRGB_(bool linear = false) :AdobeRGBBase_(D50_2, "WideGamutRGB", linear) {}; + +private: + void setParameter() + { + xr = 0.7347; + yr = 0.2653; + xg = 0.1152; + yg = 0.8264; + xb = 0.1566; + yb = 0.0177; + gamma = 2.2; + } +}; + +/* *\ brief ProPhoto RGB color space. + * data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. +*/ +class ProPhotoRGB_ : public AdobeRGBBase_ +{ +public: + ProPhotoRGB_(bool linear = false) :AdobeRGBBase_(D50_2, "ProPhotoRGB", linear) {}; + +private: + void setParameter() + { + xr = 0.734699; + yr = 0.265301; + xg = 0.159597; + yg = 0.840403; + xb = 0.036598; + yb = 0.000105; + gamma = 1.8; + } +}; + +/* *\ brief DCI-P3 RGB color space. + * data from https://en.wikipedia.org/wiki/DCI-P3. +*/ +class DCI_P3_RGB_ : public AdobeRGBBase_ +{ +public: + DCI_P3_RGB_(bool linear = false) :AdobeRGBBase_(D65_2, "DCI_P3_RGB", linear) {}; + +private: + void setParameter() + { + xr = 0.68; + yr = 0.32; + xg = 0.265; + yg = 0.69; + xb = 0.15; + yb = 0.06; + gamma = 2.2; + } +}; + +/* *\ brief Apple RGB color space. + * data from http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. +*/ +class AppleRGB_ : public AdobeRGBBase_ +{ +public: + AppleRGB_(bool linear = false) :AdobeRGBBase_(D65_2, "AppleRGB", linear) {}; + +private: + void setParameter() + { + xr = 0.625; + yr = 0.34; + xg = 0.28; + yg = 0.595; + xb = 0.155; + yb = 0.07; + gamma = 1.8; + } +}; + +/* *\ brief REC_709 RGB color space. + * data from https://en.wikipedia.org/wiki/Rec._709. +*/ +class REC_709_RGB_ : public sRGBBase_ +{ +public: + REC_709_RGB_(bool linear) :sRGBBase_(D65_2, "REC_709_RGB", linear) {}; + +private: + void setParameter() + { + xr = 0.64; + yr = 0.33; + xg = 0.3; + yg = 0.6; + xb = 0.15; + yb = 0.06; + a = 0.099; + gamma = 1 / 0.45; + } +}; + +/* *\ brief REC_2020 RGB color space. + * data from https://en.wikipedia.org/wiki/Rec._2020. +*/ +class REC_2020_RGB_ : public sRGBBase_ +{ +public: + REC_2020_RGB_(bool linear) :sRGBBase_(D65_2, "REC_2020_RGB", linear) {}; + +private: + void setParameter() + { + xr = 0.708; + yr = 0.292; + xg = 0.17; + yg = 0.797; + xb = 0.131; + yb = 0.046; + a = 0.09929682680944; + gamma = 1 / 0.45; + } +}; + + +sRGB_ sRGB(false), sRGBL(true); +AdobeRGB_ AdobeRGB(false), AdobeRGBL(true); +WideGamutRGB_ WideGamutRGB(false), WideGamutRGBL(true); +ProPhotoRGB_ ProPhotoRGB(false), ProPhotoRGBL(true); +DCI_P3_RGB_ DCI_P3_RGB(false), DCI_P3_RGBL(true); +AppleRGB_ AppleRGB(false), AppleRGBL(true); +REC_709_RGB_ REC_709_RGB(false), REC_709_RGBL(true); +REC_2020_RGB_ REC_2020_RGB(false), REC_2020_RGBL(true); + +/* *\ brief Bind RGB with RGBL. +*/ +class ColorSpaceInitial +{ +public: + ColorSpaceInitial() + { + sRGB.bind(sRGBL); + AdobeRGB.bind(AdobeRGBL); + WideGamutRGB.bind(WideGamutRGBL); + ProPhotoRGB.bind(ProPhotoRGBL); + DCI_P3_RGB.bind(DCI_P3_RGBL); + AppleRGB.bind(AppleRGBL); + REC_709_RGB.bind(REC_709_RGBL); + REC_2020_RGB.bind(REC_2020_RGBL); + + } +}; + +ColorSpaceInitial color_space_initial; + + +/* *\ brief Enum of the possible types of CAMs. +*/ +enum CAM +{ + IDENTITY, + VON_KRIES, + BRADFORD +}; + +static std::map , cv::Mat > cams; +const static cv::Mat Von_Kries = (cv::Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); +const static cv::Mat Bradford = (cv::Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); +const static std::map > MAs = { + {IDENTITY , { cv::Mat::eye(cv::Size(3,3),CV_64FC1) , cv::Mat::eye(cv::Size(3,3),CV_64FC1)} }, + {VON_KRIES, { Von_Kries ,Von_Kries.inv() }}, + {BRADFORD, { Bradford ,Bradford.inv() }} +}; + +/* *\ brief XYZ color space. + * Chromatic adaption matrices. +*/ +class XYZ :public ColorSpace +{ +public: + XYZ(IO io) : ColorSpace(io, "XYZ", true) {}; + Operations cam(IO dio, CAM method = BRADFORD) + { + return (io == dio) ? Operations() : Operations({ Operation(cam_(io, dio, method).t()) }); + } + +private: + /* *\ brief Get cam. + *\ param sio the input IO of src. + *\ param dio the input IO of dst. + *\ param method type of CAM. + *\ return the output array, type of cv::Mat. + */ + cv::Mat cam_(IO sio, IO dio, CAM method = BRADFORD) const + { + if (sio == dio) + { + return cv::Mat::eye(cv::Size(3, 3), CV_64FC1); + } + if (cams.count(std::make_tuple(dio, sio, method)) == 1) + { + return cams[std::make_tuple(dio, sio, method)]; + } + + // Function from http ://www.brucelindbloom.com/index.html?ColorCheckerRGB.html. + cv::Mat XYZws = cv::Mat(illuminants.find(dio)->second); + cv::Mat XYZWd = cv::Mat(illuminants.find(sio)->second); + cv::Mat MA = MAs.at(method)[0]; + cv::Mat MA_inv = MAs.at(method)[1]; + cv::Mat M = MA_inv * cv::Mat::diag((MA * XYZws) / (MA * XYZWd)) * MA; + cams[std::make_tuple(dio, sio, method)] = M; + cams[std::make_tuple(sio, dio, method)] = M.inv(); + return M; + } +}; + +/* *\ brief Define XYZ_D65_2 and XYZ_D50_2. +*/ +const XYZ XYZ_D65_2(D65_2); +const XYZ XYZ_D50_2(D50_2); + + +/* *\ brief Lab color space. +*/ +class Lab :public ColorSpace +{ +public: + Lab(IO io) : ColorSpace(io, "XYZ", true) + { + to = { Operation([this](cv::Mat src)->cv::Mat {return tosrc(src); }) }; + from = { Operation([this](cv::Mat src)->cv::Mat {return fromsrc(src); }) }; + } + +private: + static constexpr double delta = (6. / 29.); + static constexpr double m = 1. / (3. * delta * delta); + static constexpr double t0 = delta * delta * delta; + static constexpr double c = 4. / 29.; + + cv::Vec3d fromxyz(cv::Vec3d& xyz) + { + double x = xyz[0] / illuminants.find(io)->second[0], y = xyz[1] / illuminants.find(io)->second[1], z = xyz[2] / illuminants.find(io)->second[2]; + auto f = [this](double t)->double { return t > t0 ? std::cbrtl(t) : (m * t + c); }; + double fx = f(x), fy = f(y), fz = f(z); + return { 116. * fy - 16. ,500 * (fx - fy),200 * (fy - fz) }; + } + + /* *\ brief Calculate From. + *\ param src the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat + */ + cv::Mat fromsrc(cv::Mat& src) + { + return channelWise(src, [this](cv::Vec3d a)->cv::Vec3d {return fromxyz(a); }); + } + + cv::Vec3d tolab(cv::Vec3d& lab) + { + auto f_inv = [this](double t)->double {return t > delta ? pow(t, 3.0) : (t - c) / m; }; + double L = (lab[0] + 16.) / 116., a = lab[1] / 500., b = lab[2] / 200.; + return { illuminants.find(io)->second[0] * f_inv(L + a),illuminants.find(io)->second[1] * f_inv(L),illuminants.find(io)->second[2] * f_inv(L - b) }; + } + + /* *\ brief Calculate To. + *\ param src the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat + */ + cv::Mat tosrc(cv::Mat& src) + { + return channelWise(src, [this](cv::Vec3d a)->cv::Vec3d {return tolab(a); }); + } +}; + +/* *\ brief Define Lab_D65_2 and Lab_D50_2. +*/ +const Lab Lab_D65_2(D65_2); +const Lab Lab_D50_2(D50_2); + +} // namespace ccm +} // namespace cv + + +#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/linearize.hpp b/modules/mcc/include/opencv2/mcc/linearize.hpp new file mode 100644 index 00000000000..6fb1393e6cf --- /dev/null +++ b/modules/mcc/include/opencv2/mcc/linearize.hpp @@ -0,0 +1,300 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +/* + * MIT License + * + * Copyright (c) 2018 Pedro Diamel Marrero Fernández + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __OPENCV_MCC_LINEARIZE_HPP__ +#define __OPENCV_MCC_LINEARIZE_HPP__ + +#include "opencv2/mcc/color.hpp" + +namespace cv +{ +namespace ccm +{ + +/* *\ brief Enum of the possible types of linearization. +*/ +enum LINEAR_TYPE +{ + IDENTITY_, + GAMMA, + COLORPOLYFIT, + COLORLOGPOLYFIT, + GRAYPOLYFIT, + GRAYLOGPOLYFIT +}; + +/* *\ brief Polyfit model. +*/ +class Polyfit +{ +public: + int deg; + cv::Mat p; + + Polyfit() {}; + + /* *\ brief Polyfit method. + */ + Polyfit(cv::Mat s, cv::Mat d, int deg) :deg(deg) + { + int npoints = s.checkVector(1); + int nypoints = d.checkVector(1); + cv::Mat_ srcX(s), srcY(d); + cv::Mat_ m = cv::Mat_::ones(npoints, deg + 1); + for (int y = 0; y < npoints; ++y) + { + for (int x = 1; x < m.cols; ++x) + { + m.at(y, x) = srcX.at(y) * m.at(y, x -1); + } + } + cv::solve(m, srcY, p, DECOMP_SVD); + } + + virtual ~Polyfit() {}; + + cv::Mat operator()(const cv::Mat& inp) + { + return elementWise(inp, [this](double a)->double {return fromEW(a); }); + }; + +private: + double fromEW(double x) + { + double res = 0; + for (int d = 0; d <= deg; ++d) + { + res += pow(x, d) * p.at(d, 0); + } + return res; + }; +}; + +/* *\ brief Logpolyfit model. +*/ +class LogPolyfit +{ +public: + int deg; + Polyfit p; + + LogPolyfit() {}; + + /* *\ brief Logpolyfit method. + */ + LogPolyfit(cv::Mat s, cv::Mat d, int deg) :deg(deg) + { + cv::Mat mask_ = (s > 0) & (d > 0); + cv::Mat src_, dst_, s_, d_; + src_ = maskCopyTo(s, mask_); + dst_ = maskCopyTo(d, mask_); + log(src_, s_); + log(dst_, d_); + p = Polyfit(s_, d_, deg); + } + + virtual ~LogPolyfit() {}; + + cv::Mat operator()(const cv::Mat& inp) + { + cv::Mat mask_ = inp >= 0; + cv::Mat y, y_, res; + log(inp, y); + y = p(y); + exp(y, y_); + y_.copyTo(res, mask_); + return res; + }; +}; + +/* *\ brief Linearization base. +*/ +class Linear +{ +public: + Linear() {}; + + virtual ~Linear() {}; + + /* *\ brief Inference. + *\ param inp the input array, type of cv::Mat. + */ + virtual cv::Mat linearize(cv::Mat inp) + { + return inp; + }; + + /* *\brief Evaluate linearization model. + */ + virtual void value(void) {}; +}; + + +/* *\ brief Linearization identity. + * make no change. +*/ +class LinearIdentity : public Linear {}; + +/* *\ brief Linearization gamma correction. +*/ +class LinearGamma : public Linear +{ +public: + double gamma; + + LinearGamma(double gamma) :gamma(gamma) {}; + + cv::Mat linearize(cv::Mat inp) + { + return gammaCorrection(inp, gamma); + }; +}; + +/* *\ brief Linearization. + * Grayscale polynomial fitting. +*/ +template +class LinearGray :public Linear +{ +public: + int deg; + T p; + + LinearGray(int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg) + { + dst.getGray(); + Mat lear_gray_mask = mask & dst.grays; + + // the grayscale function is approximate for src is in relative color space. + src = rgb2gray(maskCopyTo(src, lear_gray_mask)); + cv::Mat dst_ = maskCopyTo(dst.toGray(cs.io), lear_gray_mask); + calc(src, dst_); + } + + /* *\ brief monotonically increase is not guaranteed. + *\ param src the input array, type of cv::Mat. + *\ param dst the input array, type of cv::Mat. + */ + void calc(const cv::Mat& src, const cv::Mat& dst) + { + p = T(src, dst, deg); + }; + + cv::Mat linearize(cv::Mat inp) + { + return p(inp); + }; +}; + +/* *\ brief Linearization. + * Fitting channels respectively. +*/ +template +class LinearColor :public Linear +{ +public: + int deg; + T pr; + T pg; + T pb; + + LinearColor(int deg, cv::Mat src_, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg) + { + Mat src = maskCopyTo(src_, mask); + cv::Mat dst_ = maskCopyTo(dst.to(*cs.l).colors, mask); + calc(src, dst_); + } + + void calc(const cv::Mat& src, const cv::Mat& dst) + { + cv::Mat schannels[3]; + cv::Mat dchannels[3]; + split(src, schannels); + split(dst, dchannels); + pr = T(schannels[0], dchannels[0], deg); + pg = T(schannels[1], dchannels[1], deg); + pb = T(schannels[2], dchannels[2], deg); + }; + + cv::Mat linearize(cv::Mat inp) + { + cv::Mat channels[3]; + split(inp, channels); + std::vector channel; + cv::Mat res; + merge(std::vector{ pr(channels[0]), pr(channels[1]), pr(channels[2]) }, res); + return res; + }; +}; + + +/* *\ brief Get linearization method. + * used in ccm model. + *\ param gamma used in LinearGamma. + *\ param deg degrees. + *\ param src the input array, type of cv::Mat. + *\ param dst the input array, type of cv::Mat. + *\ param mask the input array, type of cv::Mat. + *\ param cs type of RGBBase_. + *\ param linear_type type of linear. +*/ +std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type) +{ + std::shared_ptr p = std::make_shared(); + switch (linear_type) + { + case cv::ccm::IDENTITY_: + p.reset(new LinearIdentity()); + break; + case cv::ccm::GAMMA: + p.reset(new LinearGamma(gamma)); + break; + case cv::ccm::COLORPOLYFIT: + p.reset(new LinearColor(deg, src, dst, mask, cs)); + break; + case cv::ccm::COLORLOGPOLYFIT: + p.reset(new LinearColor(deg, src, dst, mask, cs)); + break; + case cv::ccm::GRAYPOLYFIT: + p.reset(new LinearGray(deg, src, dst, mask, cs)); + break; + case cv::ccm::GRAYLOGPOLYFIT: + p.reset(new LinearGray(deg, src, dst, mask, cs)); + break; + default: + throw std::invalid_argument{ "Wrong linear_type!" }; + break; + } + return p; +}; + +} // namespace ccm +} // namespace cv + + +#endif \ No newline at end of file From 000e0c9759db25e255ce338a97318041fba5d805 Mon Sep 17 00:00:00 2001 From: Jinheng Zhang Date: Mon, 31 Aug 2020 03:50:06 +0000 Subject: [PATCH 03/71] Add sample code for color correction --- .../mcc/samples/color_correction_model.cpp | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 modules/mcc/samples/color_correction_model.cpp diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp new file mode 100644 index 00000000000..40c83c06088 --- /dev/null +++ b/modules/mcc/samples/color_correction_model.cpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include "opencv2/mcc/ccm.hpp" + +using namespace cv; +using namespace std; +using namespace ccm; + +// inp the input array, type of cv::Mat. +const Mat s = (Mat_(24, 1) << + Vec3d(214.11, 98.67, 37.97), + Vec3d(231.94, 153.1, 85.27), + Vec3d(204.08, 143.71, 78.46), + Vec3d(190.58, 122.99, 30.84), + Vec3d(230.93, 148.46, 100.84), + Vec3d(228.64, 206.97, 97.5), + Vec3d(229.09, 137.07, 55.29), + Vec3d(189.21, 111.22, 92.66), + Vec3d(223.5, 96.42, 75.45), + Vec3d(201.82, 69.71, 50.9), + Vec3d(240.52, 196.47, 59.3), + Vec3d(235.73, 172.13, 54.), + Vec3d(131.6, 75.04, 68.86), + Vec3d(189.04, 170.43, 42.05), + Vec3d(222.23, 74., 71.95), + Vec3d(241.01, 199.1, 61.15), + Vec3d(224.99, 101.4, 100.24), + Vec3d(174.58, 152.63, 91.52), + Vec3d(248.06, 227.69, 140.5), + Vec3d(241.15, 201.38, 115.58), + Vec3d(236.49, 175.87, 88.86), + Vec3d(212.19, 133.49, 54.79), + Vec3d(181.17, 102.94, 36.18), + Vec3d(115.1, 53.77, 15.23)); + +int main() { + + Color color = Macbeth_D65_2; + std::vector saturated_threshold = { 0, 0.98 }; + cv::Mat weight_list; + //std::string filename = "input1.png"; + + + ColorCorrectionModel p1(s / 255, color, sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, + saturated_threshold, weight_list, 0, LEAST_SQUARE, 5000, 1e-4); + //ColorCorrectionModel p2(s / 255, color, AdobeRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, + // saturated_threshold, weight_list, 0, LEAST_SQUARE, 5000, 1e-4); + //ColorCorrectionModel p3(s / 255, color, WideGamutRGB, CCM_4x3, CIE2000, GRAYPOLYFIT, 2.2, 3, + // saturated_threshold, weight_list, 0, LEAST_SQUARE, 5000, 1e-4); + //ColorCorrectionModel p4(s / 255, color, ProPhotoRGB, CCM_4x3, RGBL, GRAYLOGPOLYFIT, 2.2, 3, + // saturated_threshold, weight_list, 0, LEAST_SQUARE, 5000, 1e-4); + //ColorCorrectionModel p5(s / 255, color, DCI_P3_RGB, CCM_3x3, RGB, IDENTITY_, 2.2, 3, + // saturated_threshold, weight_list, 0, LEAST_SQUARE, 5000, 1e-4); + //ColorCorrectionModel p6(s / 255, color, AppleRGB, CCM_3x3, CIE2000, COLORPOLYFIT, 2.2, 2, + // saturated_threshold, weight_list, 2, LEAST_SQUARE, 5000, 1e-4); + //ColorCorrectionModel p7(s / 255, color, REC_2020_RGB, CCM_3x3, CIE94_GRAPHIC_ARTS, COLORLOGPOLYFIT, 2.2, 3, + // saturated_threshold, weight_list, 0, LEAST_SQUARE, 5000, 1e-4); + + + std::cout <<"ccm1"<< p1.ccm << std::endl; + //std::cout << "ccm2" << p2.ccm << std::endl; + //std::cout << "ccm3" << p3.ccm << std::endl; + //std::cout << "ccm4" << p4.ccm << std::endl; + //std::cout << "ccm5" << p5.ccm << std::endl; + //std::cout << "ccm6" << p6.ccm << std::endl; + //std::cout << "ccm7" << p7.ccm << std::endl; + + + //Mat img1 = p1.inferImage(filename); + //Mat img2 = p2.inferImage(filename); + //Mat img3 = p3.inferImage(filename); + //Mat img4 = p4.inferImage(filename); + //Mat img5 = p5.inferImage(filename, true); + //Mat img6 = p6.inferImage(filename); + //Mat img7 = p7.inferImage(filename); + + return 0; + +} \ No newline at end of file From daedbbc8fda8ceb416615ec7fb59aee4108b15db Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Mon, 31 Aug 2020 03:52:40 +0000 Subject: [PATCH 04/71] Add the dependency to opencv_imgcodes in CMakeLists.txt --- modules/mcc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mcc/CMakeLists.txt b/modules/mcc/CMakeLists.txt index 806303505f3..c45daaffab3 100644 --- a/modules/mcc/CMakeLists.txt +++ b/modules/mcc/CMakeLists.txt @@ -1,2 +1,2 @@ set(the_description "Macbeth Chart Detection") -ocv_define_module(mcc opencv_core opencv_imgproc opencv_calib3d opencv_photo opencv_dnn WRAP python) +ocv_define_module(mcc opencv_core opencv_imgproc opencv_imgcodecs opencv_calib3d opencv_photo opencv_dnn WRAP python) From 3987e825c9e0630c6027caeb72d1d755be36c22e Mon Sep 17 00:00:00 2001 From: Jinheng Zhang Date: Mon, 31 Aug 2020 04:01:27 +0000 Subject: [PATCH 05/71] Add the color correction tutorial, introducing build steps and parameters --- .../basic_ccm/color_correction_model.markdown | 167 ++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 modules/mcc/tutorials/basic_ccm/color_correction_model.markdown diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown new file mode 100644 index 00000000000..42bed258033 --- /dev/null +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -0,0 +1,167 @@ +Color Correction Model{#tutorial_ccm_color_correction_model} +=========================== + +In this tutorial you will learn how to use the 'Color Correction Model' to do a color correction in a image. + +Building +---- + +When building OpenCV, run the following command to build all the contrib module: + +```make +cmake -D OPENCV_EXTRA_MODULES_PATH=/modules/ +``` + +Or only build the mcc module: + +```make +cmake -D OPENCV_EXTRA_MODULES_PATH=/modules/mcc +``` + +Or make sure you check the mcc module in the GUI version of CMake: cmake-gui. + +Source Code of the sample +----------- + +Parameters + +``` +src : + detected colors of ColorChecker patches; + NOTICE: the color type is RGB not BGR, and the color values are in [0, 1]; + type: cv::Mat; +dst : + the reference colors; + NOTICE: Built-in color card or custom color card are supported; + Built-in: + Macbeth_D50_2: Macbeth ColorChecker with 2deg D50; + Macbeth_D65_2: Macbeth ColorChecker with 2deg D65; + Custom: + You should use Color + For the list of color spaces supported, see the notes below; + If the color type is some RGB, the format is RGB not BGR, and the color values are in [0, 1]; + type: Color; +colorspace : + the absolute color space that detected colors convert to; + NOTICE: it should be some RGB color space; + For the list of RGB color spaces supported, see the notes below; + type: ColorSpace; +ccm_type : + the shape of color correction matrix(CCM); + Supported list: + "CCM_3x3": 3x3 matrix; + "CCM_4x3": 4x3 matrix; + type: enum CCM_TYPE; +distance : + the type of color distance; + Supported list: + "CIE2000"; + "CIE94_GRAPHIC_ARTS"; + "CIE94_TEXTILES"; + "CIE76"; + "CMC_1TO1"; + "CMC_2TO1"; + "RGB" : Euclidean distance of rgb color space; + "RGBL" : Euclidean distance of rgbl color space; + type: enum DISTANCE_TYPE; +linear : + the method of linearization; + NOTICE: see Linearization.pdf for details; + Supported list: + "IDENTITY_" : no change is made; + "GAMMA": gamma correction; + Need assign a value to gamma simultaneously; + "COLORPOLYFIT": polynomial fitting channels respectively; + Need assign a value to deg simultaneously; + "GRAYPOLYFIT": grayscale polynomial fitting; + Need assign a value to deg and dst_whites simultaneously; + "COLORLOGPOLYFIT": logarithmic polynomial fitting channels respectively; + Need assign a value to deg simultaneously; + "GRAYLOGPOLYFIT": grayscale Logarithmic polynomial fitting; + Need assign a value to deg and dst_whites simultaneously; + type: enum LINEAR_TYPE; +gamma : + the gamma value of gamma correction; + NOTICE: only valid when linear is set to "gamma"; + type: double; + +deg : + the degree of linearization polynomial; + NOTICE: only valid when linear is set to "COLORPOLYFIT", "GRAYPOLYFIT", + "COLORLOGPOLYFIT" and "GRAYLOGPOLYFIT"; + type: int; +saturated_threshold : + the threshold to determine saturation; + NOTICE: it is a tuple of [low, up]; + The colors in the closed interval [low, up] are reserved to participate + in the calculation of the loss function and initialization parameters. + type: std::vector; +--------------------------------------------------- +There are some ways to set weights: + 1. set weights_list only; + 2. set weights_coeff only; +see CCM.pdf for details; + +weights_list : + the list of weight of each color; + type: cv::Mat; + +weights_coeff : + the exponent number of L* component of the reference color in CIE Lab color space; + type: double; +--------------------------------------------------- +initial_method_type : + the method of calculating CCM initial value; + see CCM.pdf for details; + Supported list: + 'LEAST_SQUARE': least-squre method; + 'WHITE_BALANCE': white balance method; + +max_count, epsilon : + used in MinProblemSolver-DownhillSolver; + Terminal criteria to the algorithm; + type: int, double; + + +--------------------------------------------------- +Supported Color Space: + Supported list of RGB color spaces: + sRGB; + AdobeRGB; + WideGamutRGB; + ProPhotoRGB; + DCI_P3_RGB; + AppleRGB; + REC_709_RGB; + REC_2020_RGB; + + Supported list of linear RGB color spaces: + sRGBL; + AdobeRGBL; + WideGamutRGBL; + ProPhotoRGBL; + DCI_P3_RGBL; + AppleRGBL; + REC_709_RGBL; + REC_2020_RGBL; + + Supported list of non-RGB color spaces: + Lab_D50_2; + Lab_D65_2; + XYZ_D50_2; + XYZ_D65_2; + + Supported IO (You can use Lab(io) or XYZ(io) to create color space): + A_2; + A_10; + D50_2; + D50_10; + D55_2; + D55_10; + D65_2; + D65_10; + D75_2; + D75_10; + E_2; + E_10; +``` From 6708cb1c2e5fb8f76b4458a1edb079e0ad2ead73 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Mon, 31 Aug 2020 04:02:13 +0000 Subject: [PATCH 06/71] Add sample code to color correction tutorial --- .../basic_ccm/color_correction_model.markdown | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index 42bed258033..e15613e912a 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -165,3 +165,54 @@ Supported Color Space: E_2; E_10; ``` + + +## Code + +@include mcc/samples/color_correction_model.cpp + +## Explanation + + @code{.cpp} + +\#include + +\#include "opencv2/mcc/ccm.hpp" + +using namespace cv; + +using namespace std; + +using namespace ccm; + + @endcode + +``` +Here is sets of header and namespaces. You can set other namespace like the code above. +``` + +@code{.cpp} + +const Mat s = (Mat_(24, 1) << Vec3d(214.11, 98.67, 37.97), Vec3d(231.94, 153.1, 85.27), Vec3d(204.08, 143.71, 78.46), Vec3d(190.58, 122.99, 30.84), Vec3d(230.93, 148.46, 100.84), Vec3d(228.64, 206.97, 97.5), Vec3d(229.09, 137.07, 55.29), Vec3d(189.21, 111.22, 92.66), Vec3d(223.5, 96.42, 75.45), Vec3d(201.82, 69.71, 50.9), Vec3d(240.52, 196.47, 59.3), Vec3d(235.73, 172.13, 54.), Vec3d(131.6, 75.04, 68.86), Vec3d(189.04, 170.43, 42.05), Vec3d(222.23, 74., 71.95), Vec3d(241.01, 199.1, 61.15), Vec3d(224.99, 101.4, 100.24), Vec3d(174.58, 152.63, 91.52), Vec3d(248.06, 227.69, 140.5), Vec3d(241.15, 201.38, 115.58), Vec3d(236.49, 175.87, 88.86), Vec3d(212.19, 133.49, 54.79), Vec3d(181.17, 102.94, 36.18), Vec3d(115.1, 53.77, 15.23)); + + @endcode + +``` +The Color Checker Matrix with the size of 24x1, type of cv::Mat. +``` + +@code{.cpp} + + Color color = Macbeth_D65_2; + + std::vector saturated_threshold = { 0, 0.98 }; + + cv::Mat weight_list; + + std::string filename = "input1.png"; + + @endcode + +``` +Some variables for computing ccm Matrix. The variable filename is the path of a picture to be corrected.See other parameters' detail at the Parameters. +``` From 7d4cc94c62e3e3a2157f885c4daf9284a528c36d Mon Sep 17 00:00:00 2001 From: Jinheng Zhang Date: Wed, 2 Sep 2020 18:44:33 +0800 Subject: [PATCH 07/71] Add color correction algorithms introductions --- .../tutorials/table_of_content_ccm.markdown | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 modules/mcc/tutorials/table_of_content_ccm.markdown diff --git a/modules/mcc/tutorials/table_of_content_ccm.markdown b/modules/mcc/tutorials/table_of_content_ccm.markdown new file mode 100644 index 00000000000..9dd14db11c2 --- /dev/null +++ b/modules/mcc/tutorials/table_of_content_ccm.markdown @@ -0,0 +1,38 @@ +Color Correction Model {#tutorial_table_of_content_ccm} +=========================== + +- @subpage tutorial_ccm_color_correction_model + + *Author:* shanchenqi, JinhengZhang + + How to do color correction, using Color Correction Model. + +- @subpage tutorial_ccm_algorithm + + *Author:* riskiest + + Introduction to color correction algorithm. + +- @subpage tutorial_ccm_ccm + + *Author:* riskiest + + Introduction to color correction model. + +- @subpage tutorial_ccm_color_spacce + + *Author:* riskiest + + Introduction to color space. + +- @subpage tutorial_ccm_linearization + + *Author:* riskiest + + Introduction to linearization. + +- @subpage tutorial_ccm_miscellaneous + + *Author:* riskiest + + Introduction to miscellaneous. \ No newline at end of file From c0ed14983ca1f351c7e7e8720b7b825fdd6a3001 Mon Sep 17 00:00:00 2001 From: JinhengZhang <49140379+JinhengZhang@users.noreply.github.com> Date: Mon, 31 Aug 2020 15:17:17 +0800 Subject: [PATCH 08/71] Update color_correction_model.markdown --- .../basic_ccm/color_correction_model.markdown | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index e15613e912a..fb36e6bc0ff 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -198,12 +198,16 @@ const Mat s = (Mat_(24, 1) << Vec3d(214.11, 98.67, 37.97), Vec3d(231.94, @endcode ``` -The Color Checker Matrix with the size of 24x1, type of cv::Mat. +The ColorChecker Matrix with the size of Nx1, type of cv::Mat. ``` @code{.cpp} Color color = Macbeth_D65_2; + + // If you use a customized ColorChecker, make sure to define the Color instance with your own reference color values and corresponding color space: + + // Color color(ref_color_values, color_space); std::vector saturated_threshold = { 0, 0.98 }; @@ -216,3 +220,34 @@ The Color Checker Matrix with the size of 24x1, type of cv::Mat. ``` Some variables for computing ccm Matrix. The variable filename is the path of a picture to be corrected.See other parameters' detail at the Parameters. ``` + +@code{.cpp} + +ColorCorrectionModel p1(s / 255., color, sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, saturated_threshold, weight_list, 0, LEAST_SQUARE, 5000, 1.e-4); + + @endcode + +``` +the object p1 is an object of ColorCorrectionModel class. The parameters should be changed to get the best effect of color correction. +``` + +@code{.cpp} + + std::cout <<"ccm1"<< p1.ccm << std::endl; + + @endcode + +``` +The object p1 has the member variable ccm which means ccm matrix. Then, ccm matrix can be used to make color correction. +``` + +@code{.cpp} + +Mat img1 = p1.inferImage(filename); + + @endcode + +``` +The object p1 has the member function infer_image to make correction correction using ccm matrix. Img1 is the result of correction correction. +``` + From 313165059b719171e1db89e774d009afc27038a5 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Wed, 2 Sep 2020 18:51:39 +0800 Subject: [PATCH 09/71] Fix warnings of whitespace, undeclared function, shadow variables. --- .../mcc/include/opencv2/mcc/colorspace.hpp | 8 +-- modules/mcc/include/opencv2/mcc/distance.hpp | 37 +++++++---- modules/mcc/include/opencv2/mcc/io.hpp | 25 ++++---- modules/mcc/include/opencv2/mcc/linearize.hpp | 5 +- .../mcc/include/opencv2/mcc/operations.hpp | 46 ++++++------- modules/mcc/include/opencv2/mcc/utils.hpp | 64 ++++++++++--------- .../basic_ccm/color_correction_model.markdown | 5 ++ .../tutorials/table_of_content_ccm.markdown | 34 +--------- 8 files changed, 110 insertions(+), 114 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp index 8cf8c4b6713..2bf0737dc94 100644 --- a/modules/mcc/include/opencv2/mcc/colorspace.hpp +++ b/modules/mcc/include/opencv2/mcc/colorspace.hpp @@ -311,7 +311,7 @@ class sRGBBase_ : public RGBBase_ class sRGB_ :public sRGBBase_ { public: - sRGB_(bool linear) :sRGBBase_(D65_2, "sRGB", linear) {}; + sRGB_(bool linear_) :sRGBBase_(D65_2, "sRGB", linear_) {}; private: void setParameter() @@ -332,7 +332,7 @@ class sRGB_ :public sRGBBase_ class AdobeRGB_ : public AdobeRGBBase_ { public: - AdobeRGB_(bool linear = false) :AdobeRGBBase_(D65_2, "AdobeRGB", linear) {}; + AdobeRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AdobeRGB", linear_) {}; private: void setParameter() @@ -437,7 +437,7 @@ class AppleRGB_ : public AdobeRGBBase_ class REC_709_RGB_ : public sRGBBase_ { public: - REC_709_RGB_(bool linear) :sRGBBase_(D65_2, "REC_709_RGB", linear) {}; + REC_709_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_709_RGB", linear_) {}; private: void setParameter() @@ -459,7 +459,7 @@ class REC_709_RGB_ : public sRGBBase_ class REC_2020_RGB_ : public sRGBBase_ { public: - REC_2020_RGB_(bool linear) :sRGBBase_(D65_2, "REC_2020_RGB", linear) {}; + REC_2020_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_2020_RGB", linear_) {}; private: void setParameter() diff --git a/modules/mcc/include/opencv2/mcc/distance.hpp b/modules/mcc/include/opencv2/mcc/distance.hpp index 83c431512f0..6a47fcaf15d 100644 --- a/modules/mcc/include/opencv2/mcc/distance.hpp +++ b/modules/mcc/include/opencv2/mcc/distance.hpp @@ -47,12 +47,28 @@ enum DISTANCE_TYPE { RGBL }; +double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH = 1.0, + double kC = 1.0, double kL = 1.0, double k1 = 0.045, + double k2 = 0.015); +double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2); +double toRad(double degree); +double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1.0, + double kC = 1.0, double kH = 1.0); +double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1, double kC = 1); +double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2); +cv::Mat distance(cv::Mat src, cv::Mat ref, DISTANCE_TYPE distance_type); + + /* *\ brief distance between two points in formula CIE76 *\ param lab1 a 3D vector *\ param lab2 a 3D vector *\ return distance between lab1 and lab2 */ -double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2) { return norm(lab1 - lab2); }; +double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2) { return norm(lab1 - lab2);}; /* *\ brief distance between two points in formula CIE94 *\ param lab1 a 3D vector @@ -64,9 +80,8 @@ double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2) { return norm(lab1 - lab2); }; *\ param k2 second scale parameter *\ return distance between lab1 and lab2 */ -double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH = 1.0, - double kC = 1.0, double kL = 1.0, double k1 = 0.045, - double k2 = 0.015) { +double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH, + double kC, double kL, double k1, double k2) { double dl = lab1[0] - lab2[0]; double c1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); double c2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); @@ -101,8 +116,8 @@ double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2) { *\ param kH Hue scale *\ return distance between lab1 and lab2 */ -double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1.0, - double kC = 1.0, double kH = 1.0) { +double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL, + double kC, double kH) { double delta_L_apo = lab2[0] - lab1[0]; double l_bar_apo = (lab1[0] + lab2[0]) / 2.0; double C1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); @@ -175,14 +190,14 @@ double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2) { return deltaCIEDE2000_(lab1, lab2); } -/* *\ brief distance between two points in formula CMC +/* *\ brief distance between two points in formula CMC *\ param lab1 a 3D vector *\ param lab2 a 3D vector *\ param kL Lightness scale *\ param kC Chroma scale *\ return distance between lab1 and lab2 */ -double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1, double kC = 1) { +double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL, double kC) { double dL = lab2[0] - lab1[0]; double da = lab2[1] - lab1[1]; double db = lab2[2] - lab1[2]; @@ -190,7 +205,7 @@ double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1, double kC = 1) { double C2 = sqrt(pow(lab2[1], 2.0) + pow(lab2[2], 2.0)); double dC = C2 - C1; double dH = sqrt(pow(da, 2) + pow(db, 2) - pow(dC, 2)); - + double H1; if (C1 == 0.) { H1 = 0.0; @@ -198,7 +213,7 @@ double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1, double kC = 1) { H1 = atan2(lab1[2], lab1[1]); if (H1 < 0.0) H1 += 2. * CV_PI; } - + double F = pow(C1, 2) / sqrt(pow(C1, 4) + 1900); double T = (H1 > toRad(164) && H1 <= toRad(345)) ? 0.56 + abs(0.2 * cos(H1 + toRad(168))) @@ -209,7 +224,7 @@ double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1, double kC = 1) { ; double sC = (0.0638 * C1) / (1.0 + 0.0131 * C1) + 0.638; double sH = sC * (F * T + 1.0 - F); - + return sqrt(pow(dL / (kL * sL), 2.0) + pow(dC / (kC * sC), 2.0) + pow(dH / sH, 2.0)); } diff --git a/modules/mcc/include/opencv2/mcc/io.hpp b/modules/mcc/include/opencv2/mcc/io.hpp index 5b9afa68697..9a8bba5c4ef 100644 --- a/modules/mcc/include/opencv2/mcc/io.hpp +++ b/modules/mcc/include/opencv2/mcc/io.hpp @@ -34,28 +34,30 @@ #include #include -namespace cv +namespace cv { -namespace ccm +namespace ccm { +std::vector xyY2XYZ(const std::vector& xyY); +static std::map > getIlluminant(); /* *\ brief Io is the meaning of illuminant and observer. See notes of ccm.hpp * for supported list for illuminant and observer*/ class IO { public: - + std::string illuminant; std::string observer; IO() {}; - IO(std::string illuminant, std::string observer) :illuminant(illuminant), observer(observer) {}; + IO(std::string illuminant_, std::string observer) :illuminant(illuminant_), observer(observer) {}; virtual ~IO() {}; - bool operator<(const IO& other) const - { - return (illuminant < other.illuminant || ((illuminant == other.illuminant) && (observer < other.observer))); + bool operator<(const IO& other) const + { + return (illuminant < other.illuminant || ((illuminant == other.illuminant) && (observer < other.observer))); } bool operator==(const IO& other) const @@ -72,7 +74,7 @@ const IO A_2("A", "2"), A_10("A", "10"), E_2("E", "2"), E_10("E", "10"); // data from https://en.wikipedia.org/wiki/Standard_illuminant. -const static std::map> illuminants_xy = +const static std::map> illuminants_xy = { {A_2, { 0.44757, 0.40745 }}, {A_10, { 0.45117, 0.40594 }}, {D50_2, { 0.34567, 0.35850 }}, {D50_10, { 0.34773, 0.35952 }}, @@ -82,14 +84,14 @@ const static std::map> illuminants_xy = {E_2, { 1 / 3, 1 / 3 }}, {E_10, { 1 / 3, 1 / 3 }}, }; -std::vector xyY2XYZ(const std::vector& xyY) +std::vector xyY2XYZ(const std::vector& xyY) { double Y = xyY.size() >= 3 ? xyY[2] : 1; return { Y * xyY[0] / xyY[1], Y, Y / xyY[1] * (1 - xyY[0] - xyY[1]) }; } /* *\ brief function to get illuminants*/ -static std::map > getIlluminant() +static std::map > getIlluminant() { std::map > illuminants; for (auto it = illuminants_xy.begin(); it != illuminants_xy.end(); ++it) @@ -99,8 +101,7 @@ static std::map > getIlluminant() return illuminants; } -const std::map > illuminants = getIlluminant(); - +const std::map > illuminants = getIlluminant(); } // namespace ccm } // namespace cv diff --git a/modules/mcc/include/opencv2/mcc/linearize.hpp b/modules/mcc/include/opencv2/mcc/linearize.hpp index 6fb1393e6cf..dde3de83cd5 100644 --- a/modules/mcc/include/opencv2/mcc/linearize.hpp +++ b/modules/mcc/include/opencv2/mcc/linearize.hpp @@ -77,8 +77,7 @@ class Polyfit } virtual ~Polyfit() {}; - - cv::Mat operator()(const cv::Mat& inp) + cv::Mat operator()(const cv::Mat& inp) { return elementWise(inp, [this](double a)->double {return fromEW(a); }); }; @@ -297,4 +296,4 @@ std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst } // namespace cv -#endif \ No newline at end of file +#endif diff --git a/modules/mcc/include/opencv2/mcc/operations.hpp b/modules/mcc/include/opencv2/mcc/operations.hpp index 14c3c77162f..dda1866dd10 100644 --- a/modules/mcc/include/opencv2/mcc/operations.hpp +++ b/modules/mcc/include/opencv2/mcc/operations.hpp @@ -33,9 +33,9 @@ #include #include "opencv2/mcc/utils.hpp" -namespace cv +namespace cv { -namespace ccm +namespace ccm { typedef std::function MatFunc; @@ -43,7 +43,7 @@ typedef std::function MatFunc; /* *\ brief Operation class contains some operarions used for color space * conversion containing linear transformation and non-linear transformation */ -class Operation +class Operation { public: bool linear; @@ -52,40 +52,40 @@ class Operation Operation() : linear(true), M(cv::Mat()) {}; - Operation(cv::Mat M) :linear(true), M( M ) {}; + Operation(cv::Mat M_) :linear(true), M( M_ ) {}; - Operation(MatFunc f) : linear(false), f(f) {}; + Operation(MatFunc f_) : linear(false), f(f_) {}; virtual ~Operation() {}; /* *\ brief operator function will run operation*/ - cv::Mat operator()(cv::Mat& abc) + cv::Mat operator()(cv::Mat& abc) { - if (!linear) - { - return f(abc); + if (!linear) + { + return f(abc); } - if (M.empty()) - { - return abc; + if (M.empty()) + { + return abc; } return multiple(abc, M); }; - /* *\ brief add function will conbine this operation + /* *\ brief add function will conbine this operation * with other linear transformation operation*/ - void add(const Operation& other) + void add(const Operation& other) { - if (M.empty()) + if (M.empty()) { M = other.M.clone(); } - else + else { M = M * other.M; } }; - void clear() + void clear() { M = cv::Mat(); }; @@ -93,7 +93,7 @@ class Operation const Operation IDENTITY_OP( [](cv::Mat x) {return x; } ); -class Operations +class Operations { public: std::vector ops; @@ -105,23 +105,23 @@ class Operations virtual ~Operations() {}; /* *\ brief add function will conbine this operation with other transformation operations*/ - Operations& add(const Operations& other) + Operations& add(const Operations& other) { ops.insert(ops.end(), other.ops.begin(), other.ops.end()); return *this; }; /* *\ brief run operations to make color conversion*/ - cv::Mat run(cv::Mat abc) + cv::Mat run(cv::Mat abc) { Operation hd; - for (auto& op : ops) + for (auto& op : ops) { - if (op.linear) + if (op.linear) { hd.add(op); } - else + else { abc = hd(abc); hd.clear(); diff --git a/modules/mcc/include/opencv2/mcc/utils.hpp b/modules/mcc/include/opencv2/mcc/utils.hpp index 8cb713200fd..0d67879a4a1 100644 --- a/modules/mcc/include/opencv2/mcc/utils.hpp +++ b/modules/mcc/include/opencv2/mcc/utils.hpp @@ -37,12 +37,18 @@ namespace cv { -namespace ccm +namespace ccm { +double gammaCorrection_(const double& element, const double& gamma); +cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma); +cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask); +cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm); +cv::Mat saturate(cv::Mat& src, const double& low, const double& up); +cv::Mat rgb2gray(cv::Mat rgb); /* *\ brief function for elementWise operation *\ param src the input array, type of cv::Mat - *\ lambda a for operation + *\ lambda a for operation */ template cv::Mat elementWise(const cv::Mat& src, F&& lambda) @@ -63,7 +69,7 @@ cv::Mat elementWise(const cv::Mat& src, F&& lambda) case 3: { cv::MatIterator_ it, end; - for (it = dst.begin(), end = dst.end(); it != end; ++it) + for (it = dst.begin(), end = dst.end(); it != end; ++it) { for (int j = 0; j < 3; j++) { @@ -81,14 +87,14 @@ cv::Mat elementWise(const cv::Mat& src, F&& lambda) /* *\ brief function for channel operation *\ param src the input array, type of cv::Mat - *\ lambda the function for operation + *\ lambda the function for operation */ template -cv::Mat channelWise(const cv::Mat& src, F&& lambda) +cv::Mat channelWise(const cv::Mat& src, F&& lambda) { cv::Mat dst = src.clone(); cv::MatIterator_ it, end; - for (it = dst.begin(), end = dst.end(); it != end; ++it) + for (it = dst.begin(), end = dst.end(); it != end; ++it) { *it = lambda(*it); } @@ -101,13 +107,13 @@ cv::Mat channelWise(const cv::Mat& src, F&& lambda) *\ param lambda the computing method for distance . */ template -cv::Mat distanceWise(cv::Mat& src, cv::Mat& ref, F&& lambda) +cv::Mat distanceWise(cv::Mat& src, cv::Mat& ref, F&& lambda) { cv::Mat dst = cv::Mat(src.size(), CV_64FC1); cv::MatIterator_ it_src = src.begin(), end_src = src.end(), it_ref = ref.begin(), end_ref = ref.end(); - cv::MatIterator_ it_dst = dst.begin(), end_dst = dst.end(); - for (; it_src != end_src; ++it_src, ++it_ref, ++it_dst) + cv::MatIterator_ it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_ref, ++it_dst) { *it_dst = lambda(*it_src, *it_ref); } @@ -115,25 +121,25 @@ cv::Mat distanceWise(cv::Mat& src, cv::Mat& ref, F&& lambda) } -double gammaCorrection_(const double& element, const double& gamma) +double gammaCorrection_(const double& element, const double& gamma) { return (element >= 0 ? pow(element, gamma) : -pow((-element), gamma)); } /* *\ brief gamma correction ,see ColorSpace.pdf for details. *\ param src the input array,type of cv::Mat. - *\ param gamma a constant for gamma correction . + *\ param gamma a constant for gamma correction. */ -cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma) +cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma) { return elementWise(src, [gamma](double element)->double {return gammaCorrection_(element, gamma); }); } -/* *\ brief maskCopyTo a function to delete unsatisfied elementwise . +/* *\ brief maskCopyTo a function to delete unsatisfied elementwise. *\ param src the input array, type of cv::Mat. *\ param mask operation mask that used to choose satisfided elementwise. */ -cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) +cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) { cv::Mat dst(countNonZero(mask), 1, src.type()); const int channel = src.channels(); @@ -143,10 +149,10 @@ cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) case 1: { auto it_src = src.begin(), end_src = src.end(); - auto it_dst = dst.begin(), end_dst = dst.end(); - for (; it_src != end_src; ++it_src, ++it_mask) + auto it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_mask) { - if (*it_mask) + if (*it_mask) { (*it_dst) = (*it_src); ++it_dst; @@ -157,10 +163,10 @@ cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) case 3: { auto it_src = src.begin(), end_src = src.end(); - auto it_dst = dst.begin(), end_dst = dst.end(); - for (; it_src != end_src; ++it_src, ++it_mask) + auto it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_mask) { - if (*it_mask) + if (*it_mask) { (*it_dst) = (*it_src); ++it_dst; @@ -175,11 +181,11 @@ cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) return dst; } -/* *\ brief multiple the function used to compute an array with n channels mulipied by ccm . +/* *\ brief multiple the function used to compute an array with n channels mulipied by ccm. *\ param src the input array, type of cv::Mat. - *\ param ccm the ccm matrix to make color correction. + *\ param ccm the ccm matrix to make color correction. */ -cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm) +cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm) { cv::Mat tmp = xyz.reshape(1, xyz.rows * xyz.cols); cv::Mat res = tmp * ccm; @@ -193,16 +199,16 @@ cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm) *\ param low the threshold to choose saturated colors *\ param up the threshold to choose saturated colors */ -cv::Mat saturate(cv::Mat& src, const double& low, const double& up) +cv::Mat saturate(cv::Mat& src, const double& low, const double& up) { cv::Mat dst = cv::Mat::ones(src.size(), CV_8UC1); cv::MatIterator_ it_src = src.begin(), end_src = src.end(); - cv::MatIterator_ it_dst = dst.begin(), end_dst = dst.end(); - for (; it_src != end_src; ++it_src, ++it_dst) + cv::MatIterator_ it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_dst) { - for (int i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) { - if ((*it_src)[i] > up || (*it_src)[i] < low) + if ((*it_src)[i] > up || (*it_src)[i] < low) { *it_dst = 0.; break; @@ -218,7 +224,7 @@ const static cv::Mat m_gray = (cv::Mat_(3, 1) << 0.2126, 0.7152, 0.0722) * see Miscellaneous.pdf for details; *\ param rgb the input array, type of cv::Mat. */ -cv::Mat rgb2gray(cv::Mat rgb) +cv::Mat rgb2gray(cv::Mat rgb) { return multiple(rgb, m_gray); } diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index fb36e6bc0ff..e345b589684 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -3,6 +3,11 @@ Color Correction Model{#tutorial_ccm_color_correction_model} In this tutorial you will learn how to use the 'Color Correction Model' to do a color correction in a image. +Reference +---- + +See details of ColorCorrection Algorithm at https://github.com/riskiest/color_calibration/tree/v4/doc/pdf/English/Algorithm. + Building ---- diff --git a/modules/mcc/tutorials/table_of_content_ccm.markdown b/modules/mcc/tutorials/table_of_content_ccm.markdown index 9dd14db11c2..178f309b993 100644 --- a/modules/mcc/tutorials/table_of_content_ccm.markdown +++ b/modules/mcc/tutorials/table_of_content_ccm.markdown @@ -3,36 +3,6 @@ Color Correction Model {#tutorial_table_of_content_ccm} - @subpage tutorial_ccm_color_correction_model - *Author:* shanchenqi, JinhengZhang + *Author:* riskiest, shanchenqi, JinhengZhang - How to do color correction, using Color Correction Model. - -- @subpage tutorial_ccm_algorithm - - *Author:* riskiest - - Introduction to color correction algorithm. - -- @subpage tutorial_ccm_ccm - - *Author:* riskiest - - Introduction to color correction model. - -- @subpage tutorial_ccm_color_spacce - - *Author:* riskiest - - Introduction to color space. - -- @subpage tutorial_ccm_linearization - - *Author:* riskiest - - Introduction to linearization. - -- @subpage tutorial_ccm_miscellaneous - - *Author:* riskiest - - Introduction to miscellaneous. \ No newline at end of file + How to do color correction, using Color Correction Model. \ No newline at end of file From 85fe73b83f41f4e8e81ede663b08bdc826f82656 Mon Sep 17 00:00:00 2001 From: Jinheng Zhang Date: Tue, 1 Sep 2020 20:33:05 +0800 Subject: [PATCH 10/71] Fix the warnings of shadow variables, unused variable in base class. Fix the error whitespace and 'EOF' on the docs. --- modules/mcc/include/opencv2/mcc/ccm.hpp | 27 ++- modules/mcc/include/opencv2/mcc/color.hpp | 12 +- .../mcc/include/opencv2/mcc/colorspace.hpp | 161 +++++++++--------- modules/mcc/include/opencv2/mcc/io.hpp | 7 +- modules/mcc/include/opencv2/mcc/linearize.hpp | 56 +++--- modules/mcc/include/opencv2/mcc/utils.hpp | 7 +- .../basic_ccm/color_correction_model.markdown | 21 ++- 7 files changed, 145 insertions(+), 146 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index a2038af02e5..21d47ba4cce 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -84,7 +84,7 @@ namespace ccm "RGBL" : Euclidean distance of rgbl color space; type: enum DISTANCE_TYPE; default: CIE2000; - linear : + linear_type : the method of linearization; NOTICE: see Linearization.pdf for details; Supported list: @@ -106,17 +106,16 @@ namespace ccm NOTICE: only valid when linear is set to "gamma"; type: double; default: 2.2; - deg : the degree of linearization polynomial; - NOTICE: only valid when linear is set to "COLORPOLYFIT", "GRAYPOLYFIT", + NOTICE: only valid when linear is set to "COLORPOLYFIT", "GRAYPOLYFIT", "COLORLOGPOLYFIT" and "GRAYLOGPOLYFIT"; type: int; default: 3; saturated_threshold : the threshold to determine saturation; - NOTICE: it is a tuple of [low, up]; - The colors in the closed interval [low, up] are reserved to participate + NOTICE: it is a tuple of [low, up]; + The colors in the closed interval [low, up] are reserved to participate in the calculation of the loss function and initialization parameters. type: std::vector; default: { 0, 0.98 }; @@ -130,7 +129,6 @@ namespace ccm the list of weight of each color; type: cv::Mat; default: empty array; - weights_coeff : the exponent number of L* component of the reference color in CIE Lab color space; type: double; @@ -143,7 +141,6 @@ namespace ccm 'LEAST_SQUARE': least-squre method; 'WHITE_BALANCE': white balance method; type: enum INITIAL_METHOD_TYPE; - max_count, epsilon : used in MinProblemSolver-DownhillSolver; Terminal criteria to the algorithm; @@ -178,7 +175,7 @@ namespace ccm Lab_D65_2; XYZ_D50_2; XYZ_D65_2; - + Supported IO (You can use Lab(io) or XYZ(io) to create color space): A_2; A_10; @@ -253,13 +250,13 @@ class ColorCorrectionModel int max_count; double epsilon; - ColorCorrectionModel(cv::Mat src, Color dst, RGBBase_ &cs, CCM_TYPE ccm_type, DISTANCE_TYPE distance, LINEAR_TYPE linear, + ColorCorrectionModel(cv::Mat src_, Color dst_, RGBBase_ &cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, double gamma, int deg, std::vector saturated_threshold, cv::Mat weights_list, double weights_coeff, - INITIAL_METHOD_TYPE initial_method_type, int max_count, double epsilon) : - src(src), dst(dst), cs(cs), ccm_type(ccm_type), distance(distance), max_count(max_count), epsilon(epsilon) + INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : + src(src_), dst(dst_), cs(cs_), ccm_type(ccm_type_), distance(distance_), max_count(max_count_), epsilon(epsilon_) { cv::Mat saturate_mask = saturate(src, saturated_threshold[0], saturated_threshold[1]); - this->linear = getLinear(gamma, deg, this->src, this->dst, saturate_mask, this->cs, linear); + this->linear = getLinear(gamma, deg, this->src, this->dst, saturate_mask, this->cs, linear_type); calWeightsMasks(weights_list, weights_coeff, saturate_mask); src_rgbl = this->linear->linearize(maskCopyTo(this->src, mask)); @@ -385,14 +382,14 @@ class ColorCorrectionModel /* *\ brief Reset dims to ccm->shape. */ - int getDims() const + int getDims() const CV_OVERRIDE { return ccm_loss->shape; } /* *\ brief Reset calculation. */ - double calc(const double *x) const + double calc(const double *x) const CV_OVERRIDE { cv::Mat ccm(ccm_loss->shape, 1, CV_64F); for (int i = 0; i < ccm_loss->shape; i++) @@ -429,7 +426,7 @@ class ColorCorrectionModel solver->setTermCriteria(termcrit);*/ double res = solver->minimize(reshapeccm); ccm = reshapeccm.reshape(0, shape); - double loss = pow((res / masked_len), 0.5); + loss = pow((res / masked_len), 0.5); //std::cout << " ccm " << ccm << std::endl; //std::cout << " loss " << loss << std::endl; }; diff --git a/modules/mcc/include/opencv2/mcc/color.hpp b/modules/mcc/include/opencv2/mcc/color.hpp index 05634c8cafd..37e29fb63a1 100644 --- a/modules/mcc/include/opencv2/mcc/color.hpp +++ b/modules/mcc/include/opencv2/mcc/color.hpp @@ -34,15 +34,15 @@ #include "opencv2/mcc/distance.hpp" #include "opencv2/mcc/utils.hpp" -namespace cv +namespace cv { -namespace ccm +namespace ccm { /* *\ brief Color defined by color_values and color space */ -class Color +class Color { public: @@ -56,7 +56,7 @@ class Color cv::Mat colored; std::map> history; - Color(cv::Mat colors, const ColorSpace& cs) :colors(colors), cs(cs) {}; + Color(cv::Mat colors_, const ColorSpace& cs_) :colors(colors_), cs(cs_) {}; virtual ~Color() {}; @@ -81,7 +81,7 @@ class Color Operations ops; ops.add(cs.to).add(XYZ(cs.io).cam(other.io, method)).add(other.from); std::shared_ptr color(new Color(ops.run(colors), other)); - if (save) + if (save) { history[other] = color; } @@ -102,7 +102,7 @@ class Color */ cv::Mat toGray(IO io, CAM method = BRADFORD, bool save = true) { - XYZ xyz(io); + XYZ xyz(io); return channel(this->to(xyz, method, save).colors, 1); } diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp index 2bf0737dc94..2ee7dbb189e 100644 --- a/modules/mcc/include/opencv2/mcc/colorspace.hpp +++ b/modules/mcc/include/opencv2/mcc/colorspace.hpp @@ -36,14 +36,14 @@ #include "opencv2/mcc/operations.hpp" #include "opencv2/mcc/utils.hpp" -namespace cv +namespace cv { -namespace ccm +namespace ccm { /* *\ brief Basic class for ColorSpace. */ -class ColorSpace +class ColorSpace { public: IO io; @@ -56,25 +56,25 @@ class ColorSpace ColorSpace() {}; - ColorSpace(IO io, std::string type, bool linear) :io(io), type(type), linear(linear) {}; + ColorSpace(IO io_, std::string type_, bool linear_) :io(io_), type(type_), linear(linear_) {}; - virtual ~ColorSpace() + virtual ~ColorSpace() { l = 0; nl = 0; }; - virtual bool relate(const ColorSpace& other) const + virtual bool relate(const ColorSpace& other) const { return (type == other.type) && (io == other.io); }; - virtual Operations relation(const ColorSpace& other) const + virtual Operations relation(const ColorSpace& /*other*/) const { return IDENTITY_OPS; }; - bool operator<(const ColorSpace& other)const + bool operator<(const ColorSpace& other)const { return (io < other.io || (io == other.io && type < other.type) || (io == other.io && type == other.type && linear < other.linear)); } @@ -84,7 +84,7 @@ class ColorSpace * the argument values are from AdobeRGB; * Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space */ -class RGBBase_ : public ColorSpace +class RGBBase_ : public ColorSpace { public: // primaries @@ -109,22 +109,22 @@ class RGBBase_ : public ColorSpace *\ param other type of ColorSpace. *\ return Operations. */ - virtual Operations relation(const ColorSpace& other) const + Operations relation(const ColorSpace& other) const CV_OVERRIDE { - if (linear == other.linear) - { - return IDENTITY_OPS; + if (linear == other.linear) + { + return IDENTITY_OPS; } - if (linear) - { - return Operations({ Operation(fromL) }); + if (linear) + { + return Operations({ Operation(fromL) }); } return Operations({ Operation(toL) }); }; /* *\ brief Initial operations. */ - void init() + void init() { setParameter(); calLinear(); @@ -135,7 +135,7 @@ class RGBBase_ : public ColorSpace /* *\ brief Produce color space instance with linear and non-linear versions. *\ param rgbl type of RGBBase_. */ - void bind(RGBBase_& rgbl) + void bind(RGBBase_& rgbl) { init(); rgbl.init(); @@ -151,7 +151,7 @@ class RGBBase_ : public ColorSpace /* *\ brief Calculation of M_RGBL2XYZ_base. * see ColorSpace.pdf for details. */ - virtual void calM() + virtual void calM() { cv::Mat XYZr, XYZg, XYZb, XYZ_rgbl, Srgb; XYZr = cv::Mat(xyY2XYZ({ xr, yr }), true); @@ -170,7 +170,7 @@ class RGBBase_ : public ColorSpace /* *\ brief operations to or from XYZ. */ - virtual void calOperations() + virtual void calOperations() { // rgb -> rgbl toL = [this](cv::Mat rgb)->cv::Mat {return toLFunc(rgb); }; @@ -178,12 +178,12 @@ class RGBBase_ : public ColorSpace // rgbl -> rgb fromL = [this](cv::Mat rgbl)->cv::Mat {return fromLFunc(rgbl); }; - if (linear) + if (linear) { to = Operations({ Operation(M_to.t()) }); from = Operations({ Operation(M_from.t()) }); } - else + else { to = Operations({ Operation(toL), Operation(M_to.t()) }); from = Operations({ Operation(M_from.t()), Operation(fromL) }); @@ -192,33 +192,33 @@ class RGBBase_ : public ColorSpace virtual void calLinear() {} - virtual cv::Mat toLFunc(cv::Mat& rgb) - { - return cv::Mat(); + virtual cv::Mat toLFunc(cv::Mat& /*rgb*/) + { + return cv::Mat(); }; - virtual cv::Mat fromLFunc(cv::Mat& rgbl) - { - return cv::Mat(); + virtual cv::Mat fromLFunc(cv::Mat& /*rgbl*/) + { + return cv::Mat(); }; }; /* *\ brief Base of Adobe RGB color space; */ -class AdobeRGBBase_ : public RGBBase_ +class AdobeRGBBase_ : public RGBBase_ { public: using RGBBase_::RGBBase_; double gamma; private: - virtual cv::Mat toLFunc(cv::Mat& rgb) + cv::Mat toLFunc(cv::Mat& rgb) CV_OVERRIDE { return gammaCorrection(rgb, gamma); } - virtual cv::Mat fromLFunc(cv::Mat& rgbl) + cv::Mat fromLFunc(cv::Mat& rgbl) CV_OVERRIDE { return gammaCorrection(rgbl, 1. / gamma); } @@ -226,7 +226,7 @@ class AdobeRGBBase_ : public RGBBase_ /* *\ brief Base of sRGB color space; */ -class sRGBBase_ : public RGBBase_ +class sRGBBase_ : public RGBBase_ { public: using RGBBase_::RGBBase_; @@ -241,7 +241,7 @@ class sRGBBase_ : public RGBBase_ /* *\ brief linearization parameters * see ColorSpace.pdf for details; */ - virtual void calLinear() + virtual void calLinear() CV_OVERRIDE { alpha = a + 1; K0 = a / (gamma - 1); @@ -251,17 +251,17 @@ class sRGBBase_ : public RGBBase_ /* *\ brief Used by toLFunc. */ - double toLFuncEW(double& x) + double toLFuncEW(double& x) { - if (x > K0) + if (x > K0) { return pow(((x + alpha - 1) / alpha), gamma); } - else if (x >= -K0) + else if (x >= -K0) { return x / phi; } - else + else { return -(pow(((-x + alpha - 1) / alpha), gamma)); } @@ -272,24 +272,25 @@ class sRGBBase_ : public RGBBase_ *\ param rgb the input array, type of cv::Mat. *\ return the output array, type of cv::Mat. */ - cv::Mat toLFunc(cv::Mat& rgb) + cv::Mat toLFunc(cv::Mat& rgb) CV_OVERRIDE { - return elementWise(rgb, [this](double a)->double {return toLFuncEW(a); }); + return elementWise(rgb, [this](double a_)->double {return toLFuncEW(a_); }); } /* *\ brief Used by fromLFunc. */ - double fromLFuncEW(double& x) + double fromLFuncEW(double& x) { - if (x > beta) + if (x > beta) { return alpha * pow(x, 1 / gamma) - (alpha - 1); } - else if (x >= -beta) + else if (x >= -beta) { return x * phi; } - else { + else + { return -(alpha * pow(-x, 1 / gamma) - (alpha - 1)); } } @@ -299,22 +300,22 @@ class sRGBBase_ : public RGBBase_ *\ param rgbl the input array, type of cv::Mat. *\ return the output array, type of cv::Mat. */ - cv::Mat fromLFunc(cv::Mat& rgbl) + cv::Mat fromLFunc(cv::Mat& rgbl) CV_OVERRIDE { - return elementWise(rgbl, [this](double a)->double {return fromLFuncEW(a); }); + return elementWise(rgbl, [this](double a_)->double {return fromLFuncEW(a_); }); } }; /* *\ brief sRGB color space. * data from https://en.wikipedia.org/wiki/SRGB. */ -class sRGB_ :public sRGBBase_ +class sRGB_ :public sRGBBase_ { public: sRGB_(bool linear_) :sRGBBase_(D65_2, "sRGB", linear_) {}; private: - void setParameter() + void setParameter() CV_OVERRIDE { xr = 0.64; yr = 0.33; @@ -329,13 +330,13 @@ class sRGB_ :public sRGBBase_ /* *\ brief Adobe RGB color space. */ -class AdobeRGB_ : public AdobeRGBBase_ +class AdobeRGB_ : public AdobeRGBBase_ { public: AdobeRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AdobeRGB", linear_) {}; private: - void setParameter() + void setParameter() CV_OVERRIDE { xr = 0.64; yr = 0.33; @@ -350,13 +351,13 @@ class AdobeRGB_ : public AdobeRGBBase_ /* *\ brief Wide-gamut RGB color space. * data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. */ -class WideGamutRGB_ : public AdobeRGBBase_ +class WideGamutRGB_ : public AdobeRGBBase_ { public: - WideGamutRGB_(bool linear = false) :AdobeRGBBase_(D50_2, "WideGamutRGB", linear) {}; + WideGamutRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "WideGamutRGB", linear_) {}; private: - void setParameter() + void setParameter() CV_OVERRIDE { xr = 0.7347; yr = 0.2653; @@ -371,13 +372,13 @@ class WideGamutRGB_ : public AdobeRGBBase_ /* *\ brief ProPhoto RGB color space. * data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. */ -class ProPhotoRGB_ : public AdobeRGBBase_ +class ProPhotoRGB_ : public AdobeRGBBase_ { public: - ProPhotoRGB_(bool linear = false) :AdobeRGBBase_(D50_2, "ProPhotoRGB", linear) {}; + ProPhotoRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "ProPhotoRGB", linear_) {}; private: - void setParameter() + void setParameter() CV_OVERRIDE { xr = 0.734699; yr = 0.265301; @@ -392,13 +393,13 @@ class ProPhotoRGB_ : public AdobeRGBBase_ /* *\ brief DCI-P3 RGB color space. * data from https://en.wikipedia.org/wiki/DCI-P3. */ -class DCI_P3_RGB_ : public AdobeRGBBase_ +class DCI_P3_RGB_ : public AdobeRGBBase_ { public: - DCI_P3_RGB_(bool linear = false) :AdobeRGBBase_(D65_2, "DCI_P3_RGB", linear) {}; + DCI_P3_RGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "DCI_P3_RGB", linear_) {}; private: - void setParameter() + void setParameter() CV_OVERRIDE { xr = 0.68; yr = 0.32; @@ -413,13 +414,13 @@ class DCI_P3_RGB_ : public AdobeRGBBase_ /* *\ brief Apple RGB color space. * data from http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. */ -class AppleRGB_ : public AdobeRGBBase_ +class AppleRGB_ : public AdobeRGBBase_ { public: - AppleRGB_(bool linear = false) :AdobeRGBBase_(D65_2, "AppleRGB", linear) {}; + AppleRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AppleRGB", linear_) {}; private: - void setParameter() + void setParameter() CV_OVERRIDE { xr = 0.625; yr = 0.34; @@ -434,13 +435,13 @@ class AppleRGB_ : public AdobeRGBBase_ /* *\ brief REC_709 RGB color space. * data from https://en.wikipedia.org/wiki/Rec._709. */ -class REC_709_RGB_ : public sRGBBase_ +class REC_709_RGB_ : public sRGBBase_ { public: REC_709_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_709_RGB", linear_) {}; private: - void setParameter() + void setParameter() CV_OVERRIDE { xr = 0.64; yr = 0.33; @@ -456,13 +457,13 @@ class REC_709_RGB_ : public sRGBBase_ /* *\ brief REC_2020 RGB color space. * data from https://en.wikipedia.org/wiki/Rec._2020. */ -class REC_2020_RGB_ : public sRGBBase_ +class REC_2020_RGB_ : public sRGBBase_ { public: REC_2020_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_2020_RGB", linear_) {}; private: - void setParameter() + void setParameter() CV_OVERRIDE { xr = 0.708; yr = 0.292; @@ -487,10 +488,10 @@ REC_2020_RGB_ REC_2020_RGB(false), REC_2020_RGBL(true); /* *\ brief Bind RGB with RGBL. */ -class ColorSpaceInitial +class ColorSpaceInitial { public: - ColorSpaceInitial() + ColorSpaceInitial() { sRGB.bind(sRGBL); AdobeRGB.bind(AdobeRGBL); @@ -509,7 +510,7 @@ ColorSpaceInitial color_space_initial; /* *\ brief Enum of the possible types of CAMs. */ -enum CAM +enum CAM { IDENTITY, VON_KRIES, @@ -528,11 +529,11 @@ const static std::map > MAs = { /* *\ brief XYZ color space. * Chromatic adaption matrices. */ -class XYZ :public ColorSpace +class XYZ :public ColorSpace { public: - XYZ(IO io) : ColorSpace(io, "XYZ", true) {}; - Operations cam(IO dio, CAM method = BRADFORD) + XYZ(IO io_) : ColorSpace(io_, "XYZ", true) {}; + Operations cam(IO dio, CAM method = BRADFORD) { return (io == dio) ? Operations() : Operations({ Operation(cam_(io, dio, method).t()) }); } @@ -544,13 +545,13 @@ class XYZ :public ColorSpace *\ param method type of CAM. *\ return the output array, type of cv::Mat. */ - cv::Mat cam_(IO sio, IO dio, CAM method = BRADFORD) const + cv::Mat cam_(IO sio, IO dio, CAM method = BRADFORD) const { - if (sio == dio) + if (sio == dio) { return cv::Mat::eye(cv::Size(3, 3), CV_64FC1); } - if (cams.count(std::make_tuple(dio, sio, method)) == 1) + if (cams.count(std::make_tuple(dio, sio, method)) == 1) { return cams[std::make_tuple(dio, sio, method)]; } @@ -575,10 +576,10 @@ const XYZ XYZ_D50_2(D50_2); /* *\ brief Lab color space. */ -class Lab :public ColorSpace +class Lab :public ColorSpace { public: - Lab(IO io) : ColorSpace(io, "XYZ", true) + Lab(IO io_) : ColorSpace(io_, "XYZ", true) { to = { Operation([this](cv::Mat src)->cv::Mat {return tosrc(src); }) }; from = { Operation([this](cv::Mat src)->cv::Mat {return fromsrc(src); }) }; @@ -590,7 +591,7 @@ class Lab :public ColorSpace static constexpr double t0 = delta * delta * delta; static constexpr double c = 4. / 29.; - cv::Vec3d fromxyz(cv::Vec3d& xyz) + cv::Vec3d fromxyz(cv::Vec3d& xyz) { double x = xyz[0] / illuminants.find(io)->second[0], y = xyz[1] / illuminants.find(io)->second[1], z = xyz[2] / illuminants.find(io)->second[2]; auto f = [this](double t)->double { return t > t0 ? std::cbrtl(t) : (m * t + c); }; @@ -602,12 +603,12 @@ class Lab :public ColorSpace *\ param src the input array, type of cv::Mat. *\ return the output array, type of cv::Mat */ - cv::Mat fromsrc(cv::Mat& src) + cv::Mat fromsrc(cv::Mat& src) { return channelWise(src, [this](cv::Vec3d a)->cv::Vec3d {return fromxyz(a); }); } - cv::Vec3d tolab(cv::Vec3d& lab) + cv::Vec3d tolab(cv::Vec3d& lab) { auto f_inv = [this](double t)->double {return t > delta ? pow(t, 3.0) : (t - c) / m; }; double L = (lab[0] + 16.) / 116., a = lab[1] / 500., b = lab[2] / 200.; @@ -618,7 +619,7 @@ class Lab :public ColorSpace *\ param src the input array, type of cv::Mat. *\ return the output array, type of cv::Mat */ - cv::Mat tosrc(cv::Mat& src) + cv::Mat tosrc(cv::Mat& src) { return channelWise(src, [this](cv::Vec3d a)->cv::Vec3d {return tolab(a); }); } diff --git a/modules/mcc/include/opencv2/mcc/io.hpp b/modules/mcc/include/opencv2/mcc/io.hpp index 9a8bba5c4ef..ddd06bea540 100644 --- a/modules/mcc/include/opencv2/mcc/io.hpp +++ b/modules/mcc/include/opencv2/mcc/io.hpp @@ -38,8 +38,7 @@ namespace cv { namespace ccm { -std::vector xyY2XYZ(const std::vector& xyY); -static std::map > getIlluminant(); + /* *\ brief Io is the meaning of illuminant and observer. See notes of ccm.hpp * for supported list for illuminant and observer*/ class IO @@ -51,7 +50,7 @@ class IO IO() {}; - IO(std::string illuminant_, std::string observer) :illuminant(illuminant_), observer(observer) {}; + IO(std::string illuminant_, std::string observer_) :illuminant(illuminant_), observer(observer_) {}; virtual ~IO() {}; @@ -84,6 +83,7 @@ const static std::map> illuminants_xy = {E_2, { 1 / 3, 1 / 3 }}, {E_10, { 1 / 3, 1 / 3 }}, }; +std::vector xyY2XYZ(const std::vector& xyY); std::vector xyY2XYZ(const std::vector& xyY) { double Y = xyY.size() >= 3 ? xyY[2] : 1; @@ -91,6 +91,7 @@ std::vector xyY2XYZ(const std::vector& xyY) } /* *\ brief function to get illuminants*/ +static std::map > getIlluminant(); static std::map > getIlluminant() { std::map > illuminants; diff --git a/modules/mcc/include/opencv2/mcc/linearize.hpp b/modules/mcc/include/opencv2/mcc/linearize.hpp index dde3de83cd5..9f5cb75d9f4 100644 --- a/modules/mcc/include/opencv2/mcc/linearize.hpp +++ b/modules/mcc/include/opencv2/mcc/linearize.hpp @@ -31,14 +31,14 @@ #include "opencv2/mcc/color.hpp" -namespace cv +namespace cv { -namespace ccm +namespace ccm { /* *\ brief Enum of the possible types of linearization. */ -enum LINEAR_TYPE +enum LINEAR_TYPE { IDENTITY_, GAMMA, @@ -50,7 +50,7 @@ enum LINEAR_TYPE /* *\ brief Polyfit model. */ -class Polyfit +class Polyfit { public: int deg; @@ -60,15 +60,14 @@ class Polyfit /* *\ brief Polyfit method. */ - Polyfit(cv::Mat s, cv::Mat d, int deg) :deg(deg) + Polyfit(cv::Mat s, cv::Mat d, int deg_) :deg(deg_) { - int npoints = s.checkVector(1); - int nypoints = d.checkVector(1); + int npoints = s.checkVector(1); cv::Mat_ srcX(s), srcY(d); cv::Mat_ m = cv::Mat_::ones(npoints, deg + 1); - for (int y = 0; y < npoints; ++y) + for (int y = 0; y < npoints; ++y) { - for (int x = 1; x < m.cols; ++x) + for (int x = 1; x < m.cols; ++x) { m.at(y, x) = srcX.at(y) * m.at(y, x -1); } @@ -83,10 +82,10 @@ class Polyfit }; private: - double fromEW(double x) + double fromEW(double x) { double res = 0; - for (int d = 0; d <= deg; ++d) + for (int d = 0; d <= deg; ++d) { res += pow(x, d) * p.at(d, 0); } @@ -96,7 +95,7 @@ class Polyfit /* *\ brief Logpolyfit model. */ -class LogPolyfit +class LogPolyfit { public: int deg; @@ -106,7 +105,7 @@ class LogPolyfit /* *\ brief Logpolyfit method. */ - LogPolyfit(cv::Mat s, cv::Mat d, int deg) :deg(deg) + LogPolyfit(cv::Mat s, cv::Mat d, int deg_) :deg(deg_) { cv::Mat mask_ = (s > 0) & (d > 0); cv::Mat src_, dst_, s_, d_; @@ -119,7 +118,7 @@ class LogPolyfit virtual ~LogPolyfit() {}; - cv::Mat operator()(const cv::Mat& inp) + cv::Mat operator()(const cv::Mat& inp) { cv::Mat mask_ = inp >= 0; cv::Mat y, y_, res; @@ -143,9 +142,9 @@ class Linear /* *\ brief Inference. *\ param inp the input array, type of cv::Mat. */ - virtual cv::Mat linearize(cv::Mat inp) - { - return inp; + virtual cv::Mat linearize(cv::Mat inp) + { + return inp; }; /* *\brief Evaluate linearization model. @@ -166,9 +165,9 @@ class LinearGamma : public Linear public: double gamma; - LinearGamma(double gamma) :gamma(gamma) {}; + LinearGamma(double gamma_) :gamma(gamma_) {}; - cv::Mat linearize(cv::Mat inp) + cv::Mat linearize(cv::Mat inp) CV_OVERRIDE { return gammaCorrection(inp, gamma); }; @@ -178,13 +177,13 @@ class LinearGamma : public Linear * Grayscale polynomial fitting. */ template -class LinearGray :public Linear +class LinearGray :public Linear { public: int deg; T p; - LinearGray(int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg) + LinearGray(int deg_, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg_) { dst.getGray(); Mat lear_gray_mask = mask & dst.grays; @@ -199,12 +198,12 @@ class LinearGray :public Linear *\ param src the input array, type of cv::Mat. *\ param dst the input array, type of cv::Mat. */ - void calc(const cv::Mat& src, const cv::Mat& dst) + void calc(const cv::Mat& src, const cv::Mat& dst) { p = T(src, dst, deg); }; - cv::Mat linearize(cv::Mat inp) + cv::Mat linearize(cv::Mat inp) CV_OVERRIDE { return p(inp); }; @@ -214,7 +213,7 @@ class LinearGray :public Linear * Fitting channels respectively. */ template -class LinearColor :public Linear +class LinearColor :public Linear { public: int deg; @@ -222,14 +221,14 @@ class LinearColor :public Linear T pg; T pb; - LinearColor(int deg, cv::Mat src_, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg) + LinearColor(int deg_, cv::Mat src_, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg_) { Mat src = maskCopyTo(src_, mask); cv::Mat dst_ = maskCopyTo(dst.to(*cs.l).colors, mask); calc(src, dst_); } - void calc(const cv::Mat& src, const cv::Mat& dst) + void calc(const cv::Mat& src, const cv::Mat& dst) { cv::Mat schannels[3]; cv::Mat dchannels[3]; @@ -240,7 +239,7 @@ class LinearColor :public Linear pb = T(schannels[2], dchannels[2], deg); }; - cv::Mat linearize(cv::Mat inp) + cv::Mat linearize(cv::Mat inp) CV_OVERRIDE { cv::Mat channels[3]; split(inp, channels); @@ -262,7 +261,8 @@ class LinearColor :public Linear *\ param cs type of RGBBase_. *\ param linear_type type of linear. */ -std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type) +std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type); +std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type) { std::shared_ptr p = std::make_shared(); switch (linear_type) diff --git a/modules/mcc/include/opencv2/mcc/utils.hpp b/modules/mcc/include/opencv2/mcc/utils.hpp index 0d67879a4a1..26f97442195 100644 --- a/modules/mcc/include/opencv2/mcc/utils.hpp +++ b/modules/mcc/include/opencv2/mcc/utils.hpp @@ -39,6 +39,7 @@ namespace cv { namespace ccm { + double gammaCorrection_(const double& element, const double& gamma); cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma); cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask); @@ -111,7 +112,7 @@ cv::Mat distanceWise(cv::Mat& src, cv::Mat& ref, F&& lambda) { cv::Mat dst = cv::Mat(src.size(), CV_64FC1); cv::MatIterator_ it_src = src.begin(), end_src = src.end(), - it_ref = ref.begin(), end_ref = ref.end(); + it_ref = ref.begin(); cv::MatIterator_ it_dst = dst.begin(); for (; it_src != end_src; ++it_src, ++it_ref, ++it_dst) { @@ -143,7 +144,7 @@ cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) { cv::Mat dst(countNonZero(mask), 1, src.type()); const int channel = src.channels(); - auto it_mask = mask.begin(), end_mask = mask.end(); + auto it_mask = mask.begin(); switch (channel) { case 1: @@ -233,4 +234,4 @@ cv::Mat rgb2gray(cv::Mat rgb) } // namespace cv -#endif +#endif \ No newline at end of file diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index e345b589684..59ca15d72ef 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -69,7 +69,7 @@ distance : "RGB" : Euclidean distance of rgb color space; "RGBL" : Euclidean distance of rgbl color space; type: enum DISTANCE_TYPE; -linear : +linear_type : the method of linearization; NOTICE: see Linearization.pdf for details; Supported list: @@ -92,13 +92,13 @@ gamma : deg : the degree of linearization polynomial; - NOTICE: only valid when linear is set to "COLORPOLYFIT", "GRAYPOLYFIT", + NOTICE: only valid when linear is set to "COLORPOLYFIT", "GRAYPOLYFIT", "COLORLOGPOLYFIT" and "GRAYLOGPOLYFIT"; type: int; saturated_threshold : the threshold to determine saturation; - NOTICE: it is a tuple of [low, up]; - The colors in the closed interval [low, up] are reserved to participate + NOTICE: it is a tuple of [low, up]; + The colors in the closed interval [low, up] are reserved to participate in the calculation of the loss function and initialization parameters. type: std::vector; --------------------------------------------------- @@ -155,7 +155,7 @@ Supported Color Space: Lab_D65_2; XYZ_D50_2; XYZ_D65_2; - + Supported IO (You can use Lab(io) or XYZ(io) to create color space): A_2; A_10; @@ -192,7 +192,7 @@ using namespace ccm; @endcode -``` +``` Here is sets of header and namespaces. You can set other namespace like the code above. ``` @@ -202,16 +202,16 @@ const Mat s = (Mat_(24, 1) << Vec3d(214.11, 98.67, 37.97), Vec3d(231.94, @endcode -``` +``` The ColorChecker Matrix with the size of Nx1, type of cv::Mat. ``` @code{.cpp} Color color = Macbeth_D65_2; - + // If you use a customized ColorChecker, make sure to define the Color instance with your own reference color values and corresponding color space: - + // Color color(ref_color_values, color_space); std::vector saturated_threshold = { 0, 0.98 }; @@ -254,5 +254,4 @@ Mat img1 = p1.inferImage(filename); ``` The object p1 has the member function infer_image to make correction correction using ccm matrix. Img1 is the result of correction correction. -``` - +``` \ No newline at end of file From 40b0d1b75054b04517eed2a3e62a5fb3bef72b2f Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Sat, 5 Sep 2020 14:53:30 +0800 Subject: [PATCH 11/71] Fix the warnnings on win & macos --- modules/mcc/include/opencv2/mcc/ccm.hpp | 14 +++++++------- modules/mcc/include/opencv2/mcc/colorspace.hpp | 6 +++--- modules/mcc/include/opencv2/mcc/utils.hpp | 2 +- modules/mcc/samples/color_correction_model.cpp | 7 ++++--- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 21d47ba4cce..9727cfde921 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -391,16 +391,16 @@ class ColorCorrectionModel */ double calc(const double *x) const CV_OVERRIDE { - cv::Mat ccm(ccm_loss->shape, 1, CV_64F); + cv::Mat ccm_(ccm_loss->shape, 1, CV_64F); for (int i = 0; i < ccm_loss->shape; i++) { - ccm.at(i, 0) = x[i]; + ccm_.at(i, 0) = x[i]; } - ccm = ccm.reshape(0, ccm_loss->shape / 3); - Mat reshapecolor = ccm_loss->src_rgbl.reshape(1, 0) * ccm; - cv::Mat dist = Color(reshapecolor.reshape(3, 0), ccm_loss->cs).diff(ccm_loss->dst, ccm_loss->distance); + ccm_ = ccm_.reshape(0, ccm_loss->shape / 3); + Mat reshapecolor = ccm_loss->src_rgbl.reshape(1, 0) * ccm_; + cv::Mat dist_calc = Color(reshapecolor.reshape(3, 0), ccm_loss->cs).diff(ccm_loss->dst, ccm_loss->distance); cv::Mat dist_; - pow(dist, 2, dist_); + pow(dist_calc, 2, dist_); if (!ccm_loss->weights.empty()) { dist_ = ccm_loss->weights.mul(dist_); @@ -518,7 +518,7 @@ class ColorCorrectionModel cv::Mat weights_masked = maskCopyTo(this->weights, this->mask); weights = weights_masked / mean(weights_masked); } - masked_len = sum(mask)[0]; + masked_len = (int) sum(mask)[0]; }; }; diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp index 2ee7dbb189e..3f94298bca6 100644 --- a/modules/mcc/include/opencv2/mcc/colorspace.hpp +++ b/modules/mcc/include/opencv2/mcc/colorspace.hpp @@ -594,7 +594,7 @@ class Lab :public ColorSpace cv::Vec3d fromxyz(cv::Vec3d& xyz) { double x = xyz[0] / illuminants.find(io)->second[0], y = xyz[1] / illuminants.find(io)->second[1], z = xyz[2] / illuminants.find(io)->second[2]; - auto f = [this](double t)->double { return t > t0 ? std::cbrtl(t) : (m * t + c); }; + auto f = [](double t)->double { return t > t0 ? std::cbrt(t) : (m * t + c); }; double fx = f(x), fy = f(y), fz = f(z); return { 116. * fy - 16. ,500 * (fx - fy),200 * (fy - fz) }; } @@ -610,7 +610,7 @@ class Lab :public ColorSpace cv::Vec3d tolab(cv::Vec3d& lab) { - auto f_inv = [this](double t)->double {return t > delta ? pow(t, 3.0) : (t - c) / m; }; + auto f_inv = [](double t)->double {return t > delta ? pow(t, 3.0) : (t - c) / m; }; double L = (lab[0] + 16.) / 116., a = lab[1] / 500., b = lab[2] / 200.; return { illuminants.find(io)->second[0] * f_inv(L + a),illuminants.find(io)->second[1] * f_inv(L),illuminants.find(io)->second[2] * f_inv(L - b) }; } @@ -634,4 +634,4 @@ const Lab Lab_D50_2(D50_2); } // namespace cv -#endif \ No newline at end of file +#endif diff --git a/modules/mcc/include/opencv2/mcc/utils.hpp b/modules/mcc/include/opencv2/mcc/utils.hpp index 26f97442195..6528e4284ab 100644 --- a/modules/mcc/include/opencv2/mcc/utils.hpp +++ b/modules/mcc/include/opencv2/mcc/utils.hpp @@ -211,7 +211,7 @@ cv::Mat saturate(cv::Mat& src, const double& low, const double& up) { if ((*it_src)[i] > up || (*it_src)[i] < low) { - *it_dst = 0.; + *it_dst = 0; break; } } diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp index 40c83c06088..5be8c631d23 100644 --- a/modules/mcc/samples/color_correction_model.cpp +++ b/modules/mcc/samples/color_correction_model.cpp @@ -8,6 +8,10 @@ using namespace std; using namespace ccm; // inp the input array, type of cv::Mat. + + +int main() { + const Mat s = (Mat_(24, 1) << Vec3d(214.11, 98.67, 37.97), Vec3d(231.94, 153.1, 85.27), @@ -33,9 +37,6 @@ const Mat s = (Mat_(24, 1) << Vec3d(212.19, 133.49, 54.79), Vec3d(181.17, 102.94, 36.18), Vec3d(115.1, 53.77, 15.23)); - -int main() { - Color color = Macbeth_D65_2; std::vector saturated_threshold = { 0, 0.98 }; cv::Mat weight_list; From acb3398482d12e62228b767d4f5883a07ef38854 Mon Sep 17 00:00:00 2001 From: Zhen Ju Date: Mon, 7 Sep 2020 22:38:17 +0800 Subject: [PATCH 12/71] Fix bugs & support Vinyl ColorChecker --- modules/mcc/include/opencv2/mcc/ccm.hpp | 181 ++- modules/mcc/include/opencv2/mcc/color.hpp | 450 ++++--- .../mcc/include/opencv2/mcc/colorspace.hpp | 1158 ++++++++--------- modules/mcc/include/opencv2/mcc/distance.hpp | 416 +++--- modules/mcc/include/opencv2/mcc/io.hpp | 134 +- modules/mcc/include/opencv2/mcc/linearize.hpp | 476 +++---- .../mcc/include/opencv2/mcc/operations.hpp | 172 +-- modules/mcc/include/opencv2/mcc/utils.hpp | 345 +++-- 8 files changed, 1717 insertions(+), 1615 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 9727cfde921..36594b46704 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -124,7 +124,6 @@ namespace ccm 1. set weights_list only; 2. set weights_coeff only; see CCM.pdf for details; - weights_list : the list of weight of each color; type: cv::Mat; @@ -146,8 +145,6 @@ namespace ccm Terminal criteria to the algorithm; type: int, double; default: 5000, 1e-4; - - --------------------------------------------------- Supported Color Space: Supported list of RGB color spaces: @@ -159,7 +156,6 @@ namespace ccm AppleRGB; REC_709_RGB; REC_2020_RGB; - Supported list of linear RGB color spaces: sRGBL; AdobeRGBL; @@ -169,13 +165,11 @@ namespace ccm AppleRGBL; REC_709_RGBL; REC_2020_RGBL; - Supported list of non-RGB color spaces: Lab_D50_2; Lab_D65_2; XYZ_D50_2; XYZ_D65_2; - Supported IO (You can use Lab(io) or XYZ(io) to create color space): A_2; A_10; @@ -189,8 +183,6 @@ namespace ccm D75_10; E_2; E_10; - - --------------------------------------------------- Abbr. src, s: source; @@ -203,7 +195,6 @@ namespace ccm M, m: matrix ccm: color correction matrix; cam: chromatic adaption matrix; - */ @@ -225,7 +216,7 @@ enum INITIAL_METHOD_TYPE /* *\ brief Core class of ccm model. - * produce a ColorCorrectionModel instance for inference. + * produce a ColorCorrectionModel instance for inference. */ class ColorCorrectionModel { @@ -233,7 +224,9 @@ class ColorCorrectionModel // detected colors, the referenceand the RGB colorspace for conversion cv::Mat src; Color dst; - RGBBase_ &cs; + + RGBBase_& cs; + cv::Mat mask; // ccm type and shape CCM_TYPE ccm_type; @@ -246,26 +239,35 @@ class ColorCorrectionModel cv::Mat weights; cv::Mat ccm; cv::Mat ccm0; + double loss; + //double loss0; int max_count; double epsilon; - ColorCorrectionModel(cv::Mat src_, Color dst_, RGBBase_ &cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, - double gamma, int deg, std::vector saturated_threshold, cv::Mat weights_list, double weights_coeff, - INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : - src(src_), dst(dst_), cs(cs_), ccm_type(ccm_type_), distance(distance_), max_count(max_count_), epsilon(epsilon_) + ColorCorrectionModel(cv::Mat src_, cv::Mat colors_, const ColorSpace& ref_cs_, RGBBase_& cs_=sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, cv::Mat weights_list = Mat(), double weights_coeff = 0, + INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4) : + ColorCorrectionModel(src_, Color(colors_, ref_cs_), cs_, ccm_type_, distance_, linear_type, + gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} + + ColorCorrectionModel(cv::Mat src_, Color dst_, RGBBase_& cs_= sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, cv::Mat weights_list = Mat(), double weights_coeff = 0, + INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4) : + src(src_), dst(dst_), cs(cs_), ccm_type(ccm_type_), distance(distance_), max_count(max_count_), epsilon(epsilon_) { cv::Mat saturate_mask = saturate(src, saturated_threshold[0], saturated_threshold[1]); this->linear = getLinear(gamma, deg, this->src, this->dst, saturate_mask, this->cs, linear_type); calWeightsMasks(weights_list, weights_coeff, saturate_mask); src_rgbl = this->linear->linearize(maskCopyTo(this->src, mask)); - this->dst = this->dst[mask]; - dst_rgbl = maskCopyTo(this->dst.to(*(this->cs.l)).colors, mask); + dst.colors = maskCopyTo(dst.colors, mask); + dst_rgbl =this->dst.to(*(this->cs.l)).colors; // make no change for CCM_3x3, make change for CCM_4x3. src_rgbl = prepare(src_rgbl); + // distance function may affect the loss function and the fitting function switch (this->distance) { @@ -282,7 +284,7 @@ class ColorCorrectionModel initialLeastSquare(); break; default: - throw std::invalid_argument{"Wrong initial_methoddistance_type!"}; + throw std::invalid_argument{ "Wrong initial_methoddistance_type!" }; break; } break; @@ -292,11 +294,11 @@ class ColorCorrectionModel } /* *\ brief Make no change for CCM_3x3. - * convert cv::Mat A to [A, 1] in CCM_4x3. - *\ param inp the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat + * convert cv::Mat A to [A, 1] in CCM_4x3. + *\ param inp the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat */ - cv::Mat prepare(const cv::Mat &inp) + cv::Mat prepare(const cv::Mat& inp) { switch (ccm_type) { @@ -314,14 +316,14 @@ class ColorCorrectionModel return arr_out; } default: - throw std::invalid_argument{"Wrong ccm_type!"}; + throw std::invalid_argument{ "Wrong ccm_type!" }; break; } }; /* *\ brief Fitting nonlinear - optimization initial value by white balance. - * see CCM.pdf for details. - *\ return the output array, type of cv::Mat + * see CCM.pdf for details. + *\ return the output array, type of cv::Mat */ cv::Mat initialWhiteBalance(void) { @@ -339,8 +341,8 @@ class ColorCorrectionModel }; /* *\ brief Fitting nonlinear-optimization initial value by least square. - * see CCM.pdf for details - *\ param fit if fit is True, return optimalization for rgbl distance function. + * see CCM.pdf for details + *\ param fit if fit is True, return optimalization for rgbl distance function. */ void initialLeastSquare(bool fit = false) { @@ -372,13 +374,13 @@ class ColorCorrectionModel }; /* *\ brief Loss function base on cv::MinProblemSolver::Function. - * see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp + * see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp */ class LossFunction : public cv::MinProblemSolver::Function { public: - ColorCorrectionModel *ccm_loss; - LossFunction(ColorCorrectionModel *ccm) : ccm_loss(ccm){}; + ColorCorrectionModel* ccm_loss; + LossFunction(ColorCorrectionModel* ccm) : ccm_loss(ccm) {}; /* *\ brief Reset dims to ccm->shape. */ @@ -389,7 +391,7 @@ class ColorCorrectionModel /* *\ brief Reset calculation. */ - double calc(const double *x) const CV_OVERRIDE + double calc(const double* x) const CV_OVERRIDE { cv::Mat ccm_(ccm_loss->shape, 1, CV_64F); for (int i = 0; i < ccm_loss->shape; i++) @@ -397,45 +399,84 @@ class ColorCorrectionModel ccm_.at(i, 0) = x[i]; } ccm_ = ccm_.reshape(0, ccm_loss->shape / 3); - Mat reshapecolor = ccm_loss->src_rgbl.reshape(1, 0) * ccm_; - cv::Mat dist_calc = Color(reshapecolor.reshape(3, 0), ccm_loss->cs).diff(ccm_loss->dst, ccm_loss->distance); - cv::Mat dist_; - pow(dist_calc, 2, dist_); - if (!ccm_loss->weights.empty()) - { - dist_ = ccm_loss->weights.mul(dist_); - } - Scalar ss = sum(dist_); - return ss[0]; + return ccm_loss->calc_loss(ccm_); + //Mat reshapecolor = ccm_loss->src_rgbl.reshape(1, 0) * ccm; + //cv::Mat dist = Color(reshapecolor.reshape(3, 0), ccm_loss->cs).diff(ccm_loss->dst, ccm_loss->distance); + //cv::Mat dist_; + //pow(dist, 2, dist_); + //if (!ccm_loss->weights.empty()) + //{ + // dist_ = ccm_loss->weights.mul(dist_); + //} + //Scalar ss = sum(dist_); + //return ss[0]; } }; + double calc_loss_(Color color, bool DEBUG = false) { + cv::Mat dist = color.diff(dst, distance, DEBUG); + // std::cout << "dist" << dist<< std::endl; + Color lab = color.to(Lab_D50_2); + if (DEBUG) { + std::cout << "dist: " << dist << std::endl; + std::cout << "colors: " << color.colors << std::endl; + std::cout << "TYPE: " << color.cs.type << std::endl; + std::cout << "linear: " << color.cs.linear << std::endl; + std::cout << "colors_lab: " << lab.colors << std::endl; + //std::cout << "ccm_: " << ccm_ << std::endl; + //std::cout << "converted: " << converted.reshape(3, 0) << std::endl; + } + cv::Mat dist_; + //std::cout<<"dist_"<< dist_ < solver = cv::DownhillSolver::create(); cv::Ptr ptr_F(new LossFunction(this)); solver->setFunction(ptr_F); - cv::Mat reshapeccm = ccm0.reshape(0, 1); - cv::Mat step = cv::Mat::ones(reshapeccm.size(), CV_64F); - solver->setInitStep(step * 10); + cv::Mat reshapeccm = ccm0.clone().reshape(0, 1); + cv::Mat step = cv::Mat::ones(reshapeccm.size(), CV_64F) * 0.1; + solver->setInitStep(step ); /* TermCriteria termcrit = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, max_count, epsilon); solver->setTermCriteria(termcrit);*/ double res = solver->minimize(reshapeccm); - ccm = reshapeccm.reshape(0, shape); + ccm = reshapeccm.reshape(0, shape/3); loss = pow((res / masked_len), 0.5); - //std::cout << " ccm " << ccm << std::endl; - //std::cout << " loss " << loss << std::endl; + std::cout << " ccm " << ccm << std::endl; + std::cout << " loss " << loss << std::endl; }; /* *\ brief Infer using fitting ccm. - *\ param img the input image, type of cv::Mat. - *\ return the output array, type of cv::Mat. + *\ param img the input image, type of cv::Mat. + *\ return the output array, type of cv::Mat. */ - cv::Mat infer(const cv::Mat &img, bool islinear = false) + cv::Mat infer(const cv::Mat& img, bool islinear = false) { if (!ccm.data) { @@ -453,11 +494,11 @@ class ColorCorrectionModel }; /* *\ brief Infer image and output as an BGR image with uint8 type. - * mainly for test or debug. - * input size and output size should be 255. - *\ param imgfile path name of image to infer. - *\ param islinear if linearize or not. - *\ return the output array, type of cv::Mat. + * mainly for test or debug. + * input size and output size should be 255. + *\ param imgfile path name of image to infer. + *\ param islinear if linearize or not. + *\ return the output array, type of cv::Mat. */ cv::Mat inferImage(std::string imgfile, bool islinear = false) { @@ -477,20 +518,26 @@ class ColorCorrectionModel return out_img; }; + void report() { + std::cout << "CCM0: " << ccm0 << std::endl; + //std::cout << "Loss0: " << loss0 << std::endl; + std::cout << "CCM: " << ccm << std::endl; + std::cout << "Loss: " << loss << std::endl; + // std::cout << "mask: " << mask << std::endl; + } + private: - cv::Mat mask; cv::Mat dist; int masked_len; - double loss; // RGBl of detected data and the reference cv::Mat src_rgbl; cv::Mat dst_rgbl; /* *\ brief Calculate weights and mask. - *\ param weights_list the input array, type of cv::Mat. - *\ param weights_coeff type of double. - *\ param saturate_list the input array, type of cv::Mat. + *\ param weights_list the input array, type of cv::Mat. + *\ param weights_coeff type of double. + *\ param saturate_list the input array, type of cv::Mat. */ void calWeightsMasks(cv::Mat weights_list, double weights_coeff, cv::Mat saturate_mask) { @@ -515,10 +562,14 @@ class ColorCorrectionModel // weights' mask if (!weights.empty()) { + + cv::Mat weights_masked = maskCopyTo(this->weights, this->mask); - weights = weights_masked / mean(weights_masked); + std::cout << weights_masked << std::endl; + weights = weights_masked / mean(weights_masked)[0]; + } - masked_len = (int) sum(mask)[0]; + masked_len = (int)sum(mask)[0]; }; }; @@ -526,4 +577,4 @@ class ColorCorrectionModel } // namespace cv -#endif \ No newline at end of file +#endif diff --git a/modules/mcc/include/opencv2/mcc/color.hpp b/modules/mcc/include/opencv2/mcc/color.hpp index 37e29fb63a1..0937e3ad2f2 100644 --- a/modules/mcc/include/opencv2/mcc/color.hpp +++ b/modules/mcc/include/opencv2/mcc/color.hpp @@ -32,218 +32,262 @@ #include #include "opencv2/mcc/colorspace.hpp" #include "opencv2/mcc/distance.hpp" -#include "opencv2/mcc/utils.hpp" namespace cv { -namespace ccm -{ + namespace ccm + { -/* *\ brief Color defined by color_values and color space -*/ + /* *\ brief Color defined by color_values and color space + */ -class Color -{ -public: - - /* *\ param grays mask of grayscale color - *\ param colored mask of colored color - *\ param history storage of historical conversion - */ - cv::Mat colors; - const ColorSpace& cs; - cv::Mat grays; - cv::Mat colored; - std::map> history; - - Color(cv::Mat colors_, const ColorSpace& cs_) :colors(colors_), cs(cs_) {}; - - virtual ~Color() {}; - - /* *\ brief Change to other color space. - * The conversion process incorporates linear transformations to speed up. - * method is chromatic adapation method. - * when save if True, get data from history first. - *\ param other type of ColorSpace. - *\ return Color. - */ - Color to(const ColorSpace& other, CAM method = BRADFORD, bool save = true) - { - if (history.count(other) == 1) + class Color { + public: - return *history[other]; - } - if (cs.relate(other)) - { - return Color(cs.relation(other).run(colors), other); - } - Operations ops; - ops.add(cs.to).add(XYZ(cs.io).cam(other.io, method)).add(other.from); - std::shared_ptr color(new Color(ops.run(colors), other)); - if (save) - { - history[other] = color; - } - return *color; - } - - /* *\ brief Channels split. - *\ return each channel. - */ - cv::Mat channel(cv::Mat m, int i) - { - cv::Mat dchannels[3]; - split(m, dchannels); - return dchannels[i]; - } - - /* *\ brief To Gray. - */ - cv::Mat toGray(IO io, CAM method = BRADFORD, bool save = true) - { - XYZ xyz(io); - return channel(this->to(xyz, method, save).colors, 1); - } + /* *\ param grays mask of grayscale color + *\ param colored mask of colored color + *\ param history storage of historical conversion + */ + cv::Mat colors; + const ColorSpace& cs; + cv::Mat grays; + cv::Mat colored; + std::map> history; - /* *\ brief To Luminant. - */ - cv::Mat toLuminant(IO io, CAM method = BRADFORD, bool save = true) - { - Lab lab(io); - return channel(this->to(lab, method, save).colors, 0); - } - - /* *\ brief Diff without IO. - *\ param other type of Color. - *\ param method type of distance. - *\ return distance between self and other - */ - cv::Mat diff(Color& other, DISTANCE_TYPE method = CIE2000) - { - return diff(other, cs.io, method); - } - - /* *\ brief Diff with IO. - *\ param other type of Color. - *\ param io type of IO. - *\ param method type of distance. - *\ return distance between self and other - */ - cv::Mat diff(Color& other, IO io, DISTANCE_TYPE method = CIE2000) - { - Lab lab(io); - switch (method) - { - case cv::ccm::CIE76: - case cv::ccm::CIE94_GRAPHIC_ARTS: - case cv::ccm::CIE94_TEXTILES: - case cv::ccm::CIE2000: - case cv::ccm::CMC_1TO1: - case cv::ccm::CMC_2TO1: - return distance(to(lab).colors, other.to(lab).colors, method); - case cv::ccm::RGB: - return distance(to(*cs.nl).colors, other.to(*cs.nl).colors, method); - case cv::ccm::RGBL: - return distance(to(*cs.l).colors, other.to(*cs.l).colors, method); - default: - throw std::invalid_argument { "Wrong method!" }; - break; - } - } - - /* *\ brief Calculate gray mask. - */ - void getGray(double JDN = 2.0) - { - cv::Mat lab = to(Lab_D65_2).colors; - cv::Mat gray(colors.size(), colors.type()); - int fromto[] = { 0,0, -1,1, -1,2 }; - mixChannels(&lab, 1, &gray, 1, fromto, 3); - cv::Mat d = distance(lab, gray, CIE2000); - this->grays = d < JDN; - this->colored = ~grays; - } - - /* *\ brief Operator for mask copy. - */ - Color operator[](cv::Mat mask) - { - return Color(maskCopyTo(colors, mask), cs); - } + Color(cv::Mat colors_, const ColorSpace& cs_, cv::Mat grays) : colors(colors_), cs(cs_), grays(grays) { + colored = ~grays; + } + Color(cv::Mat colors_, const ColorSpace& cs_) :colors(colors_), cs(cs_) {}; - Color operator=(Color inp) - { - return inp; - } -}; - - -/* *\ brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls - * see Miscellaneous.md for details. -*/ -const cv::Mat ColorChecker2005_LAB_D50_2 = (cv::Mat_(24, 1) << - cv::Vec3d(37.986, 13.555, 14.059), - cv::Vec3d(65.711, 18.13, 17.81), - cv::Vec3d(49.927, -4.88, -21.925), - cv::Vec3d(43.139, -13.095, 21.905), - cv::Vec3d(55.112, 8.844, -25.399), - cv::Vec3d(70.719, -33.397, -0.199), - cv::Vec3d(62.661, 36.067, 57.096), - cv::Vec3d(40.02, 10.41, -45.964), - cv::Vec3d(51.124, 48.239, 16.248), - cv::Vec3d(30.325, 22.976, -21.587), - cv::Vec3d(72.532, -23.709, 57.255), - cv::Vec3d(71.941, 19.363, 67.857), - cv::Vec3d(28.778, 14.179, -50.297), - cv::Vec3d(55.261, -38.342, 31.37), - cv::Vec3d(42.101, 53.378, 28.19), - cv::Vec3d(81.733, 4.039, 79.819), - cv::Vec3d(51.935, 49.986, -14.574), - cv::Vec3d(51.038, -28.631, -28.638), - cv::Vec3d(96.539, -0.425, 1.186), - cv::Vec3d(81.257, -0.638, -0.335), - cv::Vec3d(66.766, -0.734, -0.504), - cv::Vec3d(50.867, -0.153, -0.27), - cv::Vec3d(35.656, -0.421, -1.231), - cv::Vec3d(20.461, -0.079, -0.973)); - -const cv::Mat ColorChecker2005_LAB_D65_2 = (cv::Mat_(24, 1) << - cv::Vec3d(37.542, 12.018, 13.33), - cv::Vec3d(65.2, 14.821, 17.545), - cv::Vec3d(50.366, -1.573, -21.431), - cv::Vec3d(43.125, -14.63, 22.12), - cv::Vec3d(55.343, 11.449, -25.289), - cv::Vec3d(71.36, -32.718, 1.636), - cv::Vec3d(61.365, 32.885, 55.155), - cv::Vec3d(40.712, 16.908, -45.085), - cv::Vec3d(49.86, 45.934, 13.876), - cv::Vec3d(30.15, 24.915, -22.606), - cv::Vec3d(72.438, -27.464, 58.469), - cv::Vec3d(70.916, 15.583, 66.543), - cv::Vec3d(29.624, 21.425, -49.031), - cv::Vec3d(55.643, -40.76, 33.274), - cv::Vec3d(40.554, 49.972, 25.46), - cv::Vec3d(80.982, -1.037, 80.03), - cv::Vec3d(51.006, 49.876, -16.93), - cv::Vec3d(52.121, -24.61, -26.176), - cv::Vec3d(96.536, -0.694, 1.354), - cv::Vec3d(81.274, -0.61, -0.24), - cv::Vec3d(66.787, -0.647, -0.429), - cv::Vec3d(50.872, -0.059, -0.247), - cv::Vec3d(35.68, -0.22, -1.205), - cv::Vec3d(20.475, 0.049, -0.972)); - -/* *\ brief Macbeth ColorChecker with 2deg D50. -*/ -const Color Macbeth_D50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2); - -/* *\ brief Macbeth ColorChecker with 2deg D65. -*/ -const Color Macbeth_D65_2(ColorChecker2005_LAB_D65_2, Lab_D65_2); - -} // namespace ccm + virtual ~Color() {}; + + /* *\ brief Change to other color space. + * The conversion process incorporates linear transformations to speed up. + * method is chromatic adapation method. + * when save if True, get data from history first. + *\ param other type of ColorSpace. + *\ return Color. + */ + Color to(const ColorSpace& other, CAM method = BRADFORD, bool save = true) + { + if (history.count(other) == 1) + { + + return *history[other]; + } + if (cs.relate(other)) + { + return Color(cs.relation(other).run(colors), other); + } + Operations ops; + ops.add(cs.to).add(XYZ(cs.io).cam(other.io, method)).add(other.from); + std::shared_ptr color(new Color(ops.run(colors), other)); + if (save) + { + history[other] = color; + } + return *color; + } + + /* *\ brief Channels split. + *\ return each channel. + */ + cv::Mat channel(cv::Mat m, int i) + { + cv::Mat dchannels[3]; + split(m, dchannels); + return dchannels[i]; + } + + /* *\ brief To Gray. + */ + cv::Mat toGray(IO io, CAM method = BRADFORD, bool save = true) + { + XYZ xyz(io); + return channel(this->to(xyz, method, save).colors, 1); + } + + /* *\ brief To Luminant. + */ + cv::Mat toLuminant(IO io, CAM method = BRADFORD, bool save = true) + { + Lab lab(io); + return channel(this->to(lab, method, save).colors, 0); + } + + /* *\ brief Diff without IO. + *\ param other type of Color. + *\ param method type of distance. + *\ return distance between self and other + */ + cv::Mat diff(Color& other, DISTANCE_TYPE method = CIE2000, bool DEBUG = false) + { + return diff(other, cs.io, method, DEBUG); + } + + /* *\ brief Diff with IO. + *\ param other type of Color. + *\ param io type of IO. + *\ param method type of distance. + *\ return distance between self and other + */ + cv::Mat diff(Color& other, IO io, DISTANCE_TYPE method = CIE2000, bool DEBUG = false) + { + Lab lab(io); + switch (method) + { + case cv::ccm::CIE76: + case cv::ccm::CIE94_GRAPHIC_ARTS: + case cv::ccm::CIE94_TEXTILES: + case cv::ccm::CIE2000: + case cv::ccm::CMC_1TO1: + case cv::ccm::CMC_2TO1: + if (DEBUG) { + std::cout <<"to_lab: " <grays = d < JDN; + this->colored = ~grays; + } + + /* *\ brief Operator for mask copy. + */ + Color operator[](cv::Mat mask) + { + std::cout << "[]colors: " << colors << std::endl; + std::cout <<"[]mask: " << mask << std::endl; + std::cout << "[]maskcopyto: " << maskCopyTo(colors, mask) << std::endl; + return Color(maskCopyTo(colors, mask), cs); + } + + + }; + + + /* *\ brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls + * see Miscellaneous.md for details. + */ + const cv::Mat ColorChecker2005_LAB_D50_2 = (cv::Mat_(24, 1) << + cv::Vec3d(37.986, 13.555, 14.059), + cv::Vec3d(65.711, 18.13, 17.81), + cv::Vec3d(49.927, -4.88, -21.925), + cv::Vec3d(43.139, -13.095, 21.905), + cv::Vec3d(55.112, 8.844, -25.399), + cv::Vec3d(70.719, -33.397, -0.199), + cv::Vec3d(62.661, 36.067, 57.096), + cv::Vec3d(40.02, 10.41, -45.964), + cv::Vec3d(51.124, 48.239, 16.248), + cv::Vec3d(30.325, 22.976, -21.587), + cv::Vec3d(72.532, -23.709, 57.255), + cv::Vec3d(71.941, 19.363, 67.857), + cv::Vec3d(28.778, 14.179, -50.297), + cv::Vec3d(55.261, -38.342, 31.37), + cv::Vec3d(42.101, 53.378, 28.19), + cv::Vec3d(81.733, 4.039, 79.819), + cv::Vec3d(51.935, 49.986, -14.574), + cv::Vec3d(51.038, -28.631, -28.638), + cv::Vec3d(96.539, -0.425, 1.186), + cv::Vec3d(81.257, -0.638, -0.335), + cv::Vec3d(66.766, -0.734, -0.504), + cv::Vec3d(50.867, -0.153, -0.27), + cv::Vec3d(35.656, -0.421, -1.231), + cv::Vec3d(20.461, -0.079, -0.973)); + + const cv::Mat ColorChecker2005_LAB_D65_2 = (cv::Mat_(24, 1) << + cv::Vec3d(37.542, 12.018, 13.33), + cv::Vec3d(65.2, 14.821, 17.545), + cv::Vec3d(50.366, -1.573, -21.431), + cv::Vec3d(43.125, -14.63, 22.12), + cv::Vec3d(55.343, 11.449, -25.289), + cv::Vec3d(71.36, -32.718, 1.636), + cv::Vec3d(61.365, 32.885, 55.155), + cv::Vec3d(40.712, 16.908, -45.085), + cv::Vec3d(49.86, 45.934, 13.876), + cv::Vec3d(30.15, 24.915, -22.606), + cv::Vec3d(72.438, -27.464, 58.469), + cv::Vec3d(70.916, 15.583, 66.543), + cv::Vec3d(29.624, 21.425, -49.031), + cv::Vec3d(55.643, -40.76, 33.274), + cv::Vec3d(40.554, 49.972, 25.46), + cv::Vec3d(80.982, -1.037, 80.03), + cv::Vec3d(51.006, 49.876, -16.93), + cv::Vec3d(52.121, -24.61, -26.176), + cv::Vec3d(96.536, -0.694, 1.354), + cv::Vec3d(81.274, -0.61, -0.24), + cv::Vec3d(66.787, -0.647, -0.429), + cv::Vec3d(50.872, -0.059, -0.247), + cv::Vec3d(35.68, -0.22, -1.205), + cv::Vec3d(20.475, 0.049, -0.972)); + + const cv::Mat ColorChecker2005_GRAY_MASK = (cv::Mat_(24, 1) << + 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0); + + const cv::Mat Vinyl_LAB_D50_2 = (Mat_(18, 1) << + Vec3d(1.00000000e+02, 5.20000001e-03, -1.04000000e-02), + Vec3d(7.30833969e+01, -8.19999993e-01, -2.02099991e+00), + Vec3d(6.24930000e+01, 4.25999999e-01, -2.23099995e+00), + Vec3d(5.04640007e+01, 4.46999997e-01, -2.32399988e+00), + Vec3d(3.77970009e+01, 3.59999985e-02, -1.29700005e+00), + Vec3d(0.00000000e+00, 0.00000000e+00, 0.00000000e+00), + Vec3d(5.15880013e+01, 7.35179977e+01, 5.15690002e+01), + Vec3d(9.36989975e+01, -1.57340002e+01, 9.19420013e+01), + Vec3d(6.94079971e+01, -4.65940018e+01, 5.04869995e+01), + Vec3d(6.66100006e+01, -1.36789999e+01, -4.31720009e+01), + Vec3d(1.17110004e+01, 1.69799995e+01, -3.71759987e+01), + Vec3d(5.19739990e+01, 8.19440002e+01, -8.40699959e+00), + Vec3d(4.05489998e+01, 5.04399986e+01, 2.48490009e+01), + Vec3d(6.08160019e+01, 2.60690002e+01, 4.94420013e+01), + Vec3d(5.22529984e+01, -1.99500008e+01, -2.39960003e+01), + Vec3d(5.12859993e+01, 4.84700012e+01, -1.50579996e+01), + Vec3d(6.87070007e+01, 1.22959995e+01, 1.62129993e+01), + Vec3d(6.36839981e+01, 1.02930002e+01, 1.67639999e+01)); + + const cv::Mat Vinyl_GRAY_MASK = (cv::Mat_(18, 1) << + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1); + + /* *\ brief Macbeth ColorChecker with 2deg D50. + */ + Color Macbeth_D50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2, ColorChecker2005_GRAY_MASK); + + /* *\ brief Macbeth ColorChecker with 2deg D65. + */ + Color Macbeth_D65_2(ColorChecker2005_LAB_D65_2, Lab_D65_2, ColorChecker2005_GRAY_MASK); + + Color Vinyl_D50_2(Vinyl_LAB_D50_2, Lab_D50_2, Vinyl_GRAY_MASK); + + + } // namespace ccm } // namespace cv -#endif \ No newline at end of file +#endif diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp index 3f94298bca6..cebeb3db60b 100644 --- a/modules/mcc/include/opencv2/mcc/colorspace.hpp +++ b/modules/mcc/include/opencv2/mcc/colorspace.hpp @@ -38,599 +38,599 @@ namespace cv { -namespace ccm -{ - -/* *\ brief Basic class for ColorSpace. -*/ -class ColorSpace -{ -public: - IO io; - std::string type; - bool linear; - Operations to; - Operations from; - ColorSpace* l = 0; - ColorSpace* nl = 0; - - ColorSpace() {}; - - ColorSpace(IO io_, std::string type_, bool linear_) :io(io_), type(type_), linear(linear_) {}; - - virtual ~ColorSpace() + namespace ccm { - l = 0; - nl = 0; - }; - virtual bool relate(const ColorSpace& other) const - { - return (type == other.type) && (io == other.io); - }; - - virtual Operations relation(const ColorSpace& /*other*/) const - { - return IDENTITY_OPS; - }; - - bool operator<(const ColorSpace& other)const - { - return (io < other.io || (io == other.io && type < other.type) || (io == other.io && type == other.type && linear < other.linear)); - } -}; - -/* *\ brief Base of RGB color space; - * the argument values are from AdobeRGB; - * Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space -*/ -class RGBBase_ : public ColorSpace -{ -public: - // primaries - double xr; - double yr; - double xg; - double yg; - double xb; - double yb; - MatFunc toL; - MatFunc fromL; - cv::Mat M_to; - cv::Mat M_from; - - using ColorSpace::ColorSpace; - - /* *\ brief There are 3 kinds of relationships for RGB: - * 1. Different types; - no operation - * 1. Same type, same linear; - copy - * 2. Same type, different linear, self is nonlinear; - 2 toL - * 3. Same type, different linear, self is linear - 3 fromL - *\ param other type of ColorSpace. - *\ return Operations. - */ - Operations relation(const ColorSpace& other) const CV_OVERRIDE - { - if (linear == other.linear) + /* *\ brief Basic class for ColorSpace. + */ + class ColorSpace { - return IDENTITY_OPS; - } - if (linear) + public: + IO io; + std::string type; + bool linear; + Operations to; + Operations from; + ColorSpace* l; + ColorSpace* nl; + + ColorSpace() {}; + + ColorSpace(IO io_, std::string type_, bool linear_) :io(io_), type(type_), linear(linear_) {}; + + virtual ~ColorSpace() + { + l = 0; + nl = 0; + }; + + virtual bool relate(const ColorSpace& other) const + { + return (type == other.type) && (io == other.io); + }; + + virtual Operations relation(const ColorSpace& /*other*/) const + { + return IDENTITY_OPS; + }; + + bool operator<(const ColorSpace& other)const + { + return (io < other.io || (io == other.io && type < other.type) || (io == other.io && type == other.type && linear < other.linear)); + } + }; + + /* *\ brief Base of RGB color space; + * the argument values are from AdobeRGB; + * Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space + */ + class RGBBase_ : public ColorSpace { - return Operations({ Operation(fromL) }); - } - return Operations({ Operation(toL) }); - }; - - /* *\ brief Initial operations. - */ - void init() - { - setParameter(); - calLinear(); - calM(); - calOperations(); - } - - /* *\ brief Produce color space instance with linear and non-linear versions. - *\ param rgbl type of RGBBase_. - */ - void bind(RGBBase_& rgbl) - { - init(); - rgbl.init(); - l = &rgbl; - rgbl.l = &rgbl; - nl = this; - rgbl.nl = this; - } - -private: - virtual void setParameter() {}; - - /* *\ brief Calculation of M_RGBL2XYZ_base. - * see ColorSpace.pdf for details. - */ - virtual void calM() - { - cv::Mat XYZr, XYZg, XYZb, XYZ_rgbl, Srgb; - XYZr = cv::Mat(xyY2XYZ({ xr, yr }), true); - XYZg = cv::Mat(xyY2XYZ({ xg, yg }), true); - XYZb = cv::Mat(xyY2XYZ({ xb, yb }), true); - merge(std::vector{ XYZr, XYZg, XYZb }, XYZ_rgbl); - XYZ_rgbl = XYZ_rgbl.reshape(1, XYZ_rgbl.rows); - cv::Mat XYZw = cv::Mat(illuminants.find(io)->second, true); - solve(XYZ_rgbl, XYZw, Srgb); - merge(std::vector{ Srgb.at(0)* XYZr, - Srgb.at(1)* XYZg, - Srgb.at(2)* XYZb }, M_to); - M_to = M_to.reshape(1, M_to.rows); - M_from = M_to.inv(); - }; - - /* *\ brief operations to or from XYZ. - */ - virtual void calOperations() - { - // rgb -> rgbl - toL = [this](cv::Mat rgb)->cv::Mat {return toLFunc(rgb); }; - - // rgbl -> rgb - fromL = [this](cv::Mat rgbl)->cv::Mat {return fromLFunc(rgbl); }; - - if (linear) + public: + // primaries + double xr; + double yr; + double xg; + double yg; + double xb; + double yb; + MatFunc toL; + MatFunc fromL; + cv::Mat M_to; + cv::Mat M_from; + + using ColorSpace::ColorSpace; + + /* *\ brief There are 3 kinds of relationships for RGB: + * 1. Different types; - no operation + * 1. Same type, same linear; - copy + * 2. Same type, different linear, self is nonlinear; - 2 toL + * 3. Same type, different linear, self is linear - 3 fromL + *\ param other type of ColorSpace. + *\ return Operations. + */ + Operations relation(const ColorSpace& other) const CV_OVERRIDE + { + if (linear == other.linear) + { + return IDENTITY_OPS; + } + if (linear) + { + return Operations({ Operation(fromL) }); + } + return Operations({ Operation(toL) }); + }; + + /* *\ brief Initial operations. + */ + void init() + { + setParameter(); + calLinear(); + calM(); + calOperations(); + } + + /* *\ brief Produce color space instance with linear and non-linear versions. + *\ param rgbl type of RGBBase_. + */ + void bind(RGBBase_& rgbl) + { + init(); + rgbl.init(); + l = &rgbl; + rgbl.l = &rgbl; + nl = this; + rgbl.nl = this; + } + + private: + virtual void setParameter() {}; + + /* *\ brief Calculation of M_RGBL2XYZ_base. + * see ColorSpace.pdf for details. + */ + virtual void calM() + { + cv::Mat XYZr, XYZg, XYZb, XYZ_rgbl, Srgb; + XYZr = cv::Mat(xyY2XYZ({ xr, yr }), true); + XYZg = cv::Mat(xyY2XYZ({ xg, yg }), true); + XYZb = cv::Mat(xyY2XYZ({ xb, yb }), true); + merge(std::vector{ XYZr, XYZg, XYZb }, XYZ_rgbl); + XYZ_rgbl = XYZ_rgbl.reshape(1, XYZ_rgbl.rows); + cv::Mat XYZw = cv::Mat(illuminants.find(io)->second, true); + solve(XYZ_rgbl, XYZw, Srgb); + merge(std::vector{ Srgb.at(0)* XYZr, + Srgb.at(1)* XYZg, + Srgb.at(2)* XYZb }, M_to); + M_to = M_to.reshape(1, M_to.rows); + M_from = M_to.inv(); + }; + + /* *\ brief operations to or from XYZ. + */ + virtual void calOperations() + { + // rgb -> rgbl + toL = [this](cv::Mat rgb)->cv::Mat {return toLFunc(rgb); }; + + // rgbl -> rgb + fromL = [this](cv::Mat rgbl)->cv::Mat {return fromLFunc(rgbl); }; + + if (linear) + { + to = Operations({ Operation(M_to.t()) }); + from = Operations({ Operation(M_from.t()) }); + } + else + { + to = Operations({ Operation(toL), Operation(M_to.t()) }); + from = Operations({ Operation(M_from.t()), Operation(fromL) }); + } + } + + virtual void calLinear() {} + + virtual cv::Mat toLFunc(cv::Mat& /*rgb*/) + { + return cv::Mat(); + }; + + virtual cv::Mat fromLFunc(cv::Mat& /*rgbl*/) + { + return cv::Mat(); + }; + + }; + + /* *\ brief Base of Adobe RGB color space; + */ + class AdobeRGBBase_ : public RGBBase_ { - to = Operations({ Operation(M_to.t()) }); - from = Operations({ Operation(M_from.t()) }); - } - else + public: + using RGBBase_::RGBBase_; + double gamma; + + private: + cv::Mat toLFunc(cv::Mat& rgb) CV_OVERRIDE + { + return gammaCorrection(rgb, gamma); + } + + cv::Mat fromLFunc(cv::Mat& rgbl) CV_OVERRIDE + { + return gammaCorrection(rgbl, 1. / gamma); + } + }; + + /* *\ brief Base of sRGB color space; + */ + class sRGBBase_ : public RGBBase_ { - to = Operations({ Operation(toL), Operation(M_to.t()) }); - from = Operations({ Operation(M_from.t()), Operation(fromL) }); - } - } - - virtual void calLinear() {} - - virtual cv::Mat toLFunc(cv::Mat& /*rgb*/) - { - return cv::Mat(); - }; - - virtual cv::Mat fromLFunc(cv::Mat& /*rgbl*/) - { - return cv::Mat(); - }; - -}; - -/* *\ brief Base of Adobe RGB color space; -*/ -class AdobeRGBBase_ : public RGBBase_ -{ -public: - using RGBBase_::RGBBase_; - double gamma; - -private: - cv::Mat toLFunc(cv::Mat& rgb) CV_OVERRIDE - { - return gammaCorrection(rgb, gamma); - } - - cv::Mat fromLFunc(cv::Mat& rgbl) CV_OVERRIDE - { - return gammaCorrection(rgbl, 1. / gamma); - } -}; - -/* *\ brief Base of sRGB color space; -*/ -class sRGBBase_ : public RGBBase_ -{ -public: - using RGBBase_::RGBBase_; - double a; - double gamma; - double alpha; - double beta; - double phi; - double K0; - -private: - /* *\ brief linearization parameters - * see ColorSpace.pdf for details; - */ - virtual void calLinear() CV_OVERRIDE - { - alpha = a + 1; - K0 = a / (gamma - 1); - phi = (pow(alpha, gamma) * pow(gamma - 1, gamma - 1)) / (pow(a, gamma - 1) * pow(gamma, gamma)); - beta = K0 / phi; - } - - /* *\ brief Used by toLFunc. - */ - double toLFuncEW(double& x) - { - if (x > K0) + public: + using RGBBase_::RGBBase_; + double a; + double gamma; + double alpha; + double beta; + double phi; + double K0; + + private: + /* *\ brief linearization parameters + * see ColorSpace.pdf for details; + */ + virtual void calLinear() CV_OVERRIDE + { + alpha = a + 1; + K0 = a / (gamma - 1); + phi = (pow(alpha, gamma) * pow(gamma - 1, gamma - 1)) / (pow(a, gamma - 1) * pow(gamma, gamma)); + beta = K0 / phi; + } + + /* *\ brief Used by toLFunc. + */ + double toLFuncEW(double& x) + { + if (x > K0) + { + return pow(((x + alpha - 1) / alpha), gamma); + } + else if (x >= -K0) + { + return x / phi; + } + else + { + return -(pow(((-x + alpha - 1) / alpha), gamma)); + } + } + + /* *\ brief Linearization. + * see ColorSpace.pdf for details. + *\ param rgb the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat. + */ + cv::Mat toLFunc(cv::Mat& rgb) CV_OVERRIDE + { + return elementWise(rgb, [this](double a_)->double {return toLFuncEW(a_); }); + } + + /* *\ brief Used by fromLFunc. + */ + double fromLFuncEW(double& x) + { + if (x > beta) + { + return alpha * pow(x, 1 / gamma) - (alpha - 1); + } + else if (x >= -beta) + { + return x * phi; + } + else + { + return -(alpha * pow(-x, 1 / gamma) - (alpha - 1)); + } + } + + /* *\ brief Delinearization. + * see ColorSpace.pdf for details. + *\ param rgbl the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat. + */ + cv::Mat fromLFunc(cv::Mat& rgbl) CV_OVERRIDE + { + return elementWise(rgbl, [this](double a_)->double {return fromLFuncEW(a_); }); + } + }; + + /* *\ brief sRGB color space. + * data from https://en.wikipedia.org/wiki/SRGB. + */ + class sRGB_ :public sRGBBase_ { - return pow(((x + alpha - 1) / alpha), gamma); - } - else if (x >= -K0) + public: + sRGB_(bool linear_) :sRGBBase_(D65_2, "sRGB", linear_) {}; + + private: + void setParameter() CV_OVERRIDE + { + xr = 0.64; + yr = 0.33; + xg = 0.3; + yg = 0.6; + xb = 0.15; + yb = 0.06; + a = 0.055; + gamma = 2.4; + } + }; + + /* *\ brief Adobe RGB color space. + */ + class AdobeRGB_ : public AdobeRGBBase_ { - return x / phi; - } - else + public: + AdobeRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AdobeRGB", linear_) {}; + + private: + void setParameter() CV_OVERRIDE + { + xr = 0.64; + yr = 0.33; + xg = 0.21; + yg = 0.71; + xb = 0.15; + yb = 0.06; + gamma = 2.2; + } + }; + + /* *\ brief Wide-gamut RGB color space. + * data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. + */ + class WideGamutRGB_ : public AdobeRGBBase_ { - return -(pow(((-x + alpha - 1) / alpha), gamma)); - } - } - - /* *\ brief Linearization. - * see ColorSpace.pdf for details. - *\ param rgb the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat. - */ - cv::Mat toLFunc(cv::Mat& rgb) CV_OVERRIDE - { - return elementWise(rgb, [this](double a_)->double {return toLFuncEW(a_); }); - } - - /* *\ brief Used by fromLFunc. - */ - double fromLFuncEW(double& x) - { - if (x > beta) + public: + WideGamutRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "WideGamutRGB", linear_) {}; + + private: + void setParameter() CV_OVERRIDE + { + xr = 0.7347; + yr = 0.2653; + xg = 0.1152; + yg = 0.8264; + xb = 0.1566; + yb = 0.0177; + gamma = 2.2; + } + }; + + /* *\ brief ProPhoto RGB color space. + * data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. + */ + class ProPhotoRGB_ : public AdobeRGBBase_ { - return alpha * pow(x, 1 / gamma) - (alpha - 1); - } - else if (x >= -beta) + public: + ProPhotoRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "ProPhotoRGB", linear_) {}; + + private: + void setParameter() CV_OVERRIDE + { + xr = 0.734699; + yr = 0.265301; + xg = 0.159597; + yg = 0.840403; + xb = 0.036598; + yb = 0.000105; + gamma = 1.8; + } + }; + + /* *\ brief DCI-P3 RGB color space. + * data from https://en.wikipedia.org/wiki/DCI-P3. + */ + class DCI_P3_RGB_ : public AdobeRGBBase_ { - return x * phi; - } - else + public: + DCI_P3_RGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "DCI_P3_RGB", linear_) {}; + + private: + void setParameter() CV_OVERRIDE + { + xr = 0.68; + yr = 0.32; + xg = 0.265; + yg = 0.69; + xb = 0.15; + yb = 0.06; + gamma = 2.2; + } + }; + + /* *\ brief Apple RGB color space. + * data from http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. + */ + class AppleRGB_ : public AdobeRGBBase_ { - return -(alpha * pow(-x, 1 / gamma) - (alpha - 1)); - } - } - - /* *\ brief Delinearization. - * see ColorSpace.pdf for details. - *\ param rgbl the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat. - */ - cv::Mat fromLFunc(cv::Mat& rgbl) CV_OVERRIDE - { - return elementWise(rgbl, [this](double a_)->double {return fromLFuncEW(a_); }); - } -}; - -/* *\ brief sRGB color space. - * data from https://en.wikipedia.org/wiki/SRGB. -*/ -class sRGB_ :public sRGBBase_ -{ -public: - sRGB_(bool linear_) :sRGBBase_(D65_2, "sRGB", linear_) {}; - -private: - void setParameter() CV_OVERRIDE - { - xr = 0.64; - yr = 0.33; - xg = 0.3; - yg = 0.6; - xb = 0.15; - yb = 0.06; - a = 0.055; - gamma = 2.4; - } -}; - -/* *\ brief Adobe RGB color space. -*/ -class AdobeRGB_ : public AdobeRGBBase_ -{ -public: - AdobeRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AdobeRGB", linear_) {}; - -private: - void setParameter() CV_OVERRIDE - { - xr = 0.64; - yr = 0.33; - xg = 0.21; - yg = 0.71; - xb = 0.15; - yb = 0.06; - gamma = 2.2; - } -}; - -/* *\ brief Wide-gamut RGB color space. - * data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. -*/ -class WideGamutRGB_ : public AdobeRGBBase_ -{ -public: - WideGamutRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "WideGamutRGB", linear_) {}; - -private: - void setParameter() CV_OVERRIDE - { - xr = 0.7347; - yr = 0.2653; - xg = 0.1152; - yg = 0.8264; - xb = 0.1566; - yb = 0.0177; - gamma = 2.2; - } -}; - -/* *\ brief ProPhoto RGB color space. - * data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. -*/ -class ProPhotoRGB_ : public AdobeRGBBase_ -{ -public: - ProPhotoRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "ProPhotoRGB", linear_) {}; - -private: - void setParameter() CV_OVERRIDE - { - xr = 0.734699; - yr = 0.265301; - xg = 0.159597; - yg = 0.840403; - xb = 0.036598; - yb = 0.000105; - gamma = 1.8; - } -}; - -/* *\ brief DCI-P3 RGB color space. - * data from https://en.wikipedia.org/wiki/DCI-P3. -*/ -class DCI_P3_RGB_ : public AdobeRGBBase_ -{ -public: - DCI_P3_RGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "DCI_P3_RGB", linear_) {}; - -private: - void setParameter() CV_OVERRIDE - { - xr = 0.68; - yr = 0.32; - xg = 0.265; - yg = 0.69; - xb = 0.15; - yb = 0.06; - gamma = 2.2; - } -}; - -/* *\ brief Apple RGB color space. - * data from http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. -*/ -class AppleRGB_ : public AdobeRGBBase_ -{ -public: - AppleRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AppleRGB", linear_) {}; - -private: - void setParameter() CV_OVERRIDE - { - xr = 0.625; - yr = 0.34; - xg = 0.28; - yg = 0.595; - xb = 0.155; - yb = 0.07; - gamma = 1.8; - } -}; - -/* *\ brief REC_709 RGB color space. - * data from https://en.wikipedia.org/wiki/Rec._709. -*/ -class REC_709_RGB_ : public sRGBBase_ -{ -public: - REC_709_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_709_RGB", linear_) {}; - -private: - void setParameter() CV_OVERRIDE - { - xr = 0.64; - yr = 0.33; - xg = 0.3; - yg = 0.6; - xb = 0.15; - yb = 0.06; - a = 0.099; - gamma = 1 / 0.45; - } -}; - -/* *\ brief REC_2020 RGB color space. - * data from https://en.wikipedia.org/wiki/Rec._2020. -*/ -class REC_2020_RGB_ : public sRGBBase_ -{ -public: - REC_2020_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_2020_RGB", linear_) {}; - -private: - void setParameter() CV_OVERRIDE - { - xr = 0.708; - yr = 0.292; - xg = 0.17; - yg = 0.797; - xb = 0.131; - yb = 0.046; - a = 0.09929682680944; - gamma = 1 / 0.45; - } -}; - - -sRGB_ sRGB(false), sRGBL(true); -AdobeRGB_ AdobeRGB(false), AdobeRGBL(true); -WideGamutRGB_ WideGamutRGB(false), WideGamutRGBL(true); -ProPhotoRGB_ ProPhotoRGB(false), ProPhotoRGBL(true); -DCI_P3_RGB_ DCI_P3_RGB(false), DCI_P3_RGBL(true); -AppleRGB_ AppleRGB(false), AppleRGBL(true); -REC_709_RGB_ REC_709_RGB(false), REC_709_RGBL(true); -REC_2020_RGB_ REC_2020_RGB(false), REC_2020_RGBL(true); - -/* *\ brief Bind RGB with RGBL. -*/ -class ColorSpaceInitial -{ -public: - ColorSpaceInitial() - { - sRGB.bind(sRGBL); - AdobeRGB.bind(AdobeRGBL); - WideGamutRGB.bind(WideGamutRGBL); - ProPhotoRGB.bind(ProPhotoRGBL); - DCI_P3_RGB.bind(DCI_P3_RGBL); - AppleRGB.bind(AppleRGBL); - REC_709_RGB.bind(REC_709_RGBL); - REC_2020_RGB.bind(REC_2020_RGBL); - - } -}; - -ColorSpaceInitial color_space_initial; - - -/* *\ brief Enum of the possible types of CAMs. -*/ -enum CAM -{ - IDENTITY, - VON_KRIES, - BRADFORD -}; - -static std::map , cv::Mat > cams; -const static cv::Mat Von_Kries = (cv::Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); -const static cv::Mat Bradford = (cv::Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); -const static std::map > MAs = { - {IDENTITY , { cv::Mat::eye(cv::Size(3,3),CV_64FC1) , cv::Mat::eye(cv::Size(3,3),CV_64FC1)} }, - {VON_KRIES, { Von_Kries ,Von_Kries.inv() }}, - {BRADFORD, { Bradford ,Bradford.inv() }} -}; - -/* *\ brief XYZ color space. - * Chromatic adaption matrices. -*/ -class XYZ :public ColorSpace -{ -public: - XYZ(IO io_) : ColorSpace(io_, "XYZ", true) {}; - Operations cam(IO dio, CAM method = BRADFORD) - { - return (io == dio) ? Operations() : Operations({ Operation(cam_(io, dio, method).t()) }); - } - -private: - /* *\ brief Get cam. - *\ param sio the input IO of src. - *\ param dio the input IO of dst. - *\ param method type of CAM. - *\ return the output array, type of cv::Mat. - */ - cv::Mat cam_(IO sio, IO dio, CAM method = BRADFORD) const - { - if (sio == dio) + public: + AppleRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AppleRGB", linear_) {}; + + private: + void setParameter() CV_OVERRIDE + { + xr = 0.625; + yr = 0.34; + xg = 0.28; + yg = 0.595; + xb = 0.155; + yb = 0.07; + gamma = 1.8; + } + }; + + /* *\ brief REC_709 RGB color space. + * data from https://en.wikipedia.org/wiki/Rec._709. + */ + class REC_709_RGB_ : public sRGBBase_ { - return cv::Mat::eye(cv::Size(3, 3), CV_64FC1); - } - if (cams.count(std::make_tuple(dio, sio, method)) == 1) + public: + REC_709_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_709_RGB", linear_) {}; + + private: + void setParameter() CV_OVERRIDE + { + xr = 0.64; + yr = 0.33; + xg = 0.3; + yg = 0.6; + xb = 0.15; + yb = 0.06; + a = 0.099; + gamma = 1 / 0.45; + } + }; + + /* *\ brief REC_2020 RGB color space. + * data from https://en.wikipedia.org/wiki/Rec._2020. + */ + class REC_2020_RGB_ : public sRGBBase_ { - return cams[std::make_tuple(dio, sio, method)]; - } - - // Function from http ://www.brucelindbloom.com/index.html?ColorCheckerRGB.html. - cv::Mat XYZws = cv::Mat(illuminants.find(dio)->second); - cv::Mat XYZWd = cv::Mat(illuminants.find(sio)->second); - cv::Mat MA = MAs.at(method)[0]; - cv::Mat MA_inv = MAs.at(method)[1]; - cv::Mat M = MA_inv * cv::Mat::diag((MA * XYZws) / (MA * XYZWd)) * MA; - cams[std::make_tuple(dio, sio, method)] = M; - cams[std::make_tuple(sio, dio, method)] = M.inv(); - return M; - } -}; - -/* *\ brief Define XYZ_D65_2 and XYZ_D50_2. -*/ -const XYZ XYZ_D65_2(D65_2); -const XYZ XYZ_D50_2(D50_2); - - -/* *\ brief Lab color space. -*/ -class Lab :public ColorSpace -{ -public: - Lab(IO io_) : ColorSpace(io_, "XYZ", true) - { - to = { Operation([this](cv::Mat src)->cv::Mat {return tosrc(src); }) }; - from = { Operation([this](cv::Mat src)->cv::Mat {return fromsrc(src); }) }; - } - -private: - static constexpr double delta = (6. / 29.); - static constexpr double m = 1. / (3. * delta * delta); - static constexpr double t0 = delta * delta * delta; - static constexpr double c = 4. / 29.; - - cv::Vec3d fromxyz(cv::Vec3d& xyz) - { - double x = xyz[0] / illuminants.find(io)->second[0], y = xyz[1] / illuminants.find(io)->second[1], z = xyz[2] / illuminants.find(io)->second[2]; - auto f = [](double t)->double { return t > t0 ? std::cbrt(t) : (m * t + c); }; - double fx = f(x), fy = f(y), fz = f(z); - return { 116. * fy - 16. ,500 * (fx - fy),200 * (fy - fz) }; - } - - /* *\ brief Calculate From. - *\ param src the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat - */ - cv::Mat fromsrc(cv::Mat& src) - { - return channelWise(src, [this](cv::Vec3d a)->cv::Vec3d {return fromxyz(a); }); - } - - cv::Vec3d tolab(cv::Vec3d& lab) - { - auto f_inv = [](double t)->double {return t > delta ? pow(t, 3.0) : (t - c) / m; }; - double L = (lab[0] + 16.) / 116., a = lab[1] / 500., b = lab[2] / 200.; - return { illuminants.find(io)->second[0] * f_inv(L + a),illuminants.find(io)->second[1] * f_inv(L),illuminants.find(io)->second[2] * f_inv(L - b) }; - } - - /* *\ brief Calculate To. - *\ param src the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat - */ - cv::Mat tosrc(cv::Mat& src) - { - return channelWise(src, [this](cv::Vec3d a)->cv::Vec3d {return tolab(a); }); - } -}; - -/* *\ brief Define Lab_D65_2 and Lab_D50_2. -*/ -const Lab Lab_D65_2(D65_2); -const Lab Lab_D50_2(D50_2); - -} // namespace ccm + public: + REC_2020_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_2020_RGB", linear_) {}; + + private: + void setParameter() CV_OVERRIDE + { + xr = 0.708; + yr = 0.292; + xg = 0.17; + yg = 0.797; + xb = 0.131; + yb = 0.046; + a = 0.09929682680944; + gamma = 1 / 0.45; + } + }; + + + sRGB_ sRGB(false), sRGBL(true); + AdobeRGB_ AdobeRGB(false), AdobeRGBL(true); + WideGamutRGB_ WideGamutRGB(false), WideGamutRGBL(true); + ProPhotoRGB_ ProPhotoRGB(false), ProPhotoRGBL(true); + DCI_P3_RGB_ DCI_P3_RGB(false), DCI_P3_RGBL(true); + AppleRGB_ AppleRGB(false), AppleRGBL(true); + REC_709_RGB_ REC_709_RGB(false), REC_709_RGBL(true); + REC_2020_RGB_ REC_2020_RGB(false), REC_2020_RGBL(true); + + /* *\ brief Bind RGB with RGBL. + */ + class ColorSpaceInitial + { + public: + ColorSpaceInitial() + { + sRGB.bind(sRGBL); + AdobeRGB.bind(AdobeRGBL); + WideGamutRGB.bind(WideGamutRGBL); + ProPhotoRGB.bind(ProPhotoRGBL); + DCI_P3_RGB.bind(DCI_P3_RGBL); + AppleRGB.bind(AppleRGBL); + REC_709_RGB.bind(REC_709_RGBL); + REC_2020_RGB.bind(REC_2020_RGBL); + + } + }; + + ColorSpaceInitial color_space_initial; + + + /* *\ brief Enum of the possible types of CAMs. + */ + enum CAM + { + IDENTITY, + VON_KRIES, + BRADFORD + }; + + static std::map , cv::Mat > cams; + const static cv::Mat Von_Kries = (cv::Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); + const static cv::Mat Bradford = (cv::Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); + const static std::map > MAs = { + {IDENTITY , { cv::Mat::eye(cv::Size(3,3),CV_64FC1) , cv::Mat::eye(cv::Size(3,3),CV_64FC1)} }, + {VON_KRIES, { Von_Kries ,Von_Kries.inv() }}, + {BRADFORD, { Bradford ,Bradford.inv() }} + }; + + /* *\ brief XYZ color space. + * Chromatic adaption matrices. + */ + class XYZ :public ColorSpace + { + public: + XYZ(IO io_) : ColorSpace(io_, "XYZ", true) {}; + Operations cam(IO dio, CAM method = BRADFORD) + { + return (io == dio) ? Operations() : Operations({ Operation(cam_(io, dio, method).t()) }); + } + + private: + /* *\ brief Get cam. + *\ param sio the input IO of src. + *\ param dio the input IO of dst. + *\ param method type of CAM. + *\ return the output array, type of cv::Mat. + */ + cv::Mat cam_(IO sio, IO dio, CAM method = BRADFORD) const + { + if (sio == dio) + { + return cv::Mat::eye(cv::Size(3, 3), CV_64FC1); + } + if (cams.count(std::make_tuple(dio, sio, method)) == 1) + { + return cams[std::make_tuple(dio, sio, method)]; + } + + // Function from http ://www.brucelindbloom.com/index.html?ColorCheckerRGB.html. + cv::Mat XYZws = cv::Mat(illuminants.find(dio)->second); + cv::Mat XYZWd = cv::Mat(illuminants.find(sio)->second); + cv::Mat MA = MAs.at(method)[0]; + cv::Mat MA_inv = MAs.at(method)[1]; + cv::Mat M = MA_inv * cv::Mat::diag((MA * XYZws) / (MA * XYZWd)) * MA; + cams[std::make_tuple(dio, sio, method)] = M; + cams[std::make_tuple(sio, dio, method)] = M.inv(); + return M; + } + }; + + /* *\ brief Define XYZ_D65_2 and XYZ_D50_2. + */ + const XYZ XYZ_D65_2(D65_2); + const XYZ XYZ_D50_2(D50_2); + + + /* *\ brief Lab color space. + */ + class Lab :public ColorSpace + { + public: + Lab(IO io_) : ColorSpace(io_, "Lab", true) + { + to = { Operation([this](cv::Mat src)->cv::Mat {return tosrc(src); }) }; + from = { Operation([this](cv::Mat src)->cv::Mat {return fromsrc(src); }) }; + } + + private: + static constexpr double delta = (6. / 29.); + static constexpr double m = 1. / (3. * delta * delta); + static constexpr double t0 = delta * delta * delta; + static constexpr double c = 4. / 29.; + + cv::Vec3d fromxyz(cv::Vec3d& xyz) + { + double x = xyz[0] / illuminants.find(io)->second[0], y = xyz[1] / illuminants.find(io)->second[1], z = xyz[2] / illuminants.find(io)->second[2]; + auto f = [](double t)->double { return t > t0 ? std::cbrt(t) : (m * t + c); }; + double fx = f(x), fy = f(y), fz = f(z); + return { 116. * fy - 16. ,500 * (fx - fy),200 * (fy - fz) }; + } + + /* *\ brief Calculate From. + *\ param src the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat + */ + cv::Mat fromsrc(cv::Mat& src) + { + return channelWise(src, [this](cv::Vec3d a)->cv::Vec3d {return fromxyz(a); }); + } + + cv::Vec3d tolab(cv::Vec3d& lab) + { + auto f_inv = [](double t)->double {return t > delta ? pow(t, 3.0) : (t - c) / m; }; + double L = (lab[0] + 16.) / 116., a = lab[1] / 500., b = lab[2] / 200.; + return { illuminants.find(io)->second[0] * f_inv(L + a),illuminants.find(io)->second[1] * f_inv(L),illuminants.find(io)->second[2] * f_inv(L - b) }; + } + + /* *\ brief Calculate To. + *\ param src the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat + */ + cv::Mat tosrc(cv::Mat& src) + { + return channelWise(src, [this](cv::Vec3d a)->cv::Vec3d {return tolab(a); }); + } + }; + + /* *\ brief Define Lab_D65_2 and Lab_D50_2. + */ + const Lab Lab_D65_2(D65_2); + const Lab Lab_D50_2(D50_2); + + } // namespace ccm } // namespace cv diff --git a/modules/mcc/include/opencv2/mcc/distance.hpp b/modules/mcc/include/opencv2/mcc/distance.hpp index 6a47fcaf15d..ea2257c0eac 100644 --- a/modules/mcc/include/opencv2/mcc/distance.hpp +++ b/modules/mcc/include/opencv2/mcc/distance.hpp @@ -32,236 +32,244 @@ #include "opencv2/mcc/utils.hpp" namespace cv { -namespace ccm { + namespace ccm { -/* *\brief Enum of possibale functions to calculate the distance between - * colors.see https://en.wikipedia.org/wiki/Color_difference for details;*/ -enum DISTANCE_TYPE { - CIE76, - CIE94_GRAPHIC_ARTS, - CIE94_TEXTILES, - CIE2000, - CMC_1TO1, - CMC_2TO1, - RGB, - RGBL -}; + /* *\brief Enum of possibale functions to calculate the distance between + * colors.see https://en.wikipedia.org/wiki/Color_difference for details;*/ + enum DISTANCE_TYPE { + CIE76, + CIE94_GRAPHIC_ARTS, + CIE94_TEXTILES, + CIE2000, + CMC_1TO1, + CMC_2TO1, + RGB, + RGBL + }; -double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2); -double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH = 1.0, - double kC = 1.0, double kL = 1.0, double k1 = 0.045, - double k2 = 0.015); -double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2); -double toRad(double degree); -double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2); -double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1.0, - double kC = 1.0, double kH = 1.0); -double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2); -double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1, double kC = 1); -double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2); -double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2); -cv::Mat distance(cv::Mat src, cv::Mat ref, DISTANCE_TYPE distance_type); + double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2); + double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH = 1.0, + double kC = 1.0, double kL = 1.0, double k1 = 0.045, + double k2 = 0.015); + double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2); + double toRad(double degree); + double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2); + double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1.0, + double kC = 1.0, double kH = 1.0); + double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2); + double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1, double kC = 1); + double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2); + double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2); + cv::Mat distance(cv::Mat src, cv::Mat ref, DISTANCE_TYPE distance_type); -/* *\ brief distance between two points in formula CIE76 - *\ param lab1 a 3D vector - *\ param lab2 a 3D vector - *\ return distance between lab1 and lab2 -*/ -double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2) { return norm(lab1 - lab2);}; + /* *\ brief distance between two points in formula CIE76 + *\ param lab1 a 3D vector + *\ param lab2 a 3D vector + *\ return distance between lab1 and lab2 + */ + double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2) { return norm(lab1 - lab2); }; -/* *\ brief distance between two points in formula CIE94 - *\ param lab1 a 3D vector - *\ param lab2 a 3D vector - *\ param kH Hue scale - *\ param kC Chroma scale - *\ param kL Lightness scale - *\ param k1 first scale parameter - *\ param k2 second scale parameter - *\ return distance between lab1 and lab2 -*/ -double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH, - double kC, double kL, double k1, double k2) { - double dl = lab1[0] - lab2[0]; - double c1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); - double c2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); - double dc = c1 - c2; - double da = lab1[1] - lab2[1]; - double db = lab1[2] - lab2[2]; - double dh = pow(da, 2) + pow(db, 2) - pow(dc, 2); - double sc = 1.0 + k1 * c1; - double sh = 1.0 + k2 * c1; - double sl = 1.0; - double res = - pow(dl / (kL * sl), 2) + pow(dc / (kC * sc), 2) + dh / pow(kH * sh, 2); + /* *\ brief distance between two points in formula CIE94 + *\ param lab1 a 3D vector + *\ param lab2 a 3D vector + *\ param kH Hue scale + *\ param kC Chroma scale + *\ param kL Lightness scale + *\ param k1 first scale parameter + *\ param k2 second scale parameter + *\ return distance between lab1 and lab2 + */ + double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH, + double kC, double kL, double k1, double k2) { + double dl = lab1[0] - lab2[0]; + double c1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); + double c2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); + double dc = c1 - c2; + double da = lab1[1] - lab2[1]; + double db = lab1[2] - lab2[2]; + double dh = pow(da, 2) + pow(db, 2) - pow(dc, 2); + double sc = 1.0 + k1 * c1; + double sh = 1.0 + k2 * c1; + double sl = 1.0; + double res = + pow(dl / (kL * sl), 2) + pow(dc / (kC * sc), 2) + dh / pow(kH * sh, 2); - return res > 0 ? sqrt(res) : 0; -} + return res > 0 ? sqrt(res) : 0; + } -double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2) { - return deltaCIE94(lab1, lab2); -} + double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2) { + return deltaCIE94(lab1, lab2); + } -double toRad(double degree) { return degree / 180 * CV_PI; }; + double toRad(double degree) { return degree / 180 * CV_PI; }; -double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2) { - return deltaCIE94(lab1, lab2, 1.0, 1.0, 2.0, 0.048, 0.014); -} + double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2) { + return deltaCIE94(lab1, lab2, 1.0, 1.0, 2.0, 0.048, 0.014); + } -/* *\ brief distance between two points in formula CIE2000 - *\ param lab1 a 3D vector - *\ param lab2 a 3D vector - *\ param kL Lightness scale - *\ param kC Chroma scale - *\ param kH Hue scale - *\ return distance between lab1 and lab2 -*/ -double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL, - double kC, double kH) { - double delta_L_apo = lab2[0] - lab1[0]; - double l_bar_apo = (lab1[0] + lab2[0]) / 2.0; - double C1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); - double C2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); - double C_bar = (C1 + C2) / 2.0; - double G = sqrt(pow(C_bar, 7) / (pow(C_bar, 7) + pow(25, 7))); - double a1_apo = lab1[1] + lab1[1] / 2.0 * (1.0 - G); - double a2_apo = lab2[1] + lab2[1] / 2.0 * (1.0 - G); - double C1_apo = sqrt(pow(a1_apo, 2) + pow(lab1[2], 2)); - double C2_apo = sqrt(pow(a2_apo, 2) + pow(lab2[2], 2)); - double C_bar_apo = (C1_apo + C2_apo) / 2.0; - double delta_C_apo = C2_apo - C1_apo; + /* *\ brief distance between two points in formula CIE2000 + *\ param lab1 a 3D vector + *\ param lab2 a 3D vector + *\ param kL Lightness scale + *\ param kC Chroma scale + *\ param kH Hue scale + *\ return distance between lab1 and lab2 + */ + double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL, + double kC, double kH) { + double delta_L_apo = lab2[0] - lab1[0]; + double l_bar_apo = (lab1[0] + lab2[0]) / 2.0; + double C1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); + double C2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); + double C_bar = (C1 + C2) / 2.0; + double G = sqrt(pow(C_bar, 7) / (pow(C_bar, 7) + pow(25, 7))); + double a1_apo = lab1[1] + lab1[1] / 2.0 * (1.0 - G); + double a2_apo = lab2[1] + lab2[1] / 2.0 * (1.0 - G); + double C1_apo = sqrt(pow(a1_apo, 2) + pow(lab1[2], 2)); + double C2_apo = sqrt(pow(a2_apo, 2) + pow(lab2[2], 2)); + double C_bar_apo = (C1_apo + C2_apo) / 2.0; + double delta_C_apo = C2_apo - C1_apo; - double h1_apo; - if (C1_apo == 0) { - h1_apo = 0.0; - } else { - h1_apo = atan2(lab1[2], a1_apo); - if (h1_apo < 0.0) h1_apo += 2. * CV_PI; - } + double h1_apo; + if (C1_apo == 0) { + h1_apo = 0.0; + } + else { + h1_apo = atan2(lab1[2], a1_apo); + if (h1_apo < 0.0) h1_apo += 2. * CV_PI; + } - double h2_apo; - if (C2_apo == 0) { - h2_apo = 0.0; - } else { - h2_apo = atan2(lab2[2], a2_apo); - if (h2_apo < 0.0) h2_apo += 2. * CV_PI; - } + double h2_apo; + if (C2_apo == 0) { + h2_apo = 0.0; + } + else { + h2_apo = atan2(lab2[2], a2_apo); + if (h2_apo < 0.0) h2_apo += 2. * CV_PI; + } - double delta_h_apo; - if (abs(h2_apo - h1_apo) <= CV_PI) { - delta_h_apo = h2_apo - h1_apo; - } else if (h2_apo <= h1_apo) { - delta_h_apo = h2_apo - h1_apo + 2. * CV_PI; - } else { - delta_h_apo = h2_apo - h1_apo - 2. * CV_PI; - } + double delta_h_apo; + if (abs(h2_apo - h1_apo) <= CV_PI) { + delta_h_apo = h2_apo - h1_apo; + } + else if (h2_apo <= h1_apo) { + delta_h_apo = h2_apo - h1_apo + 2. * CV_PI; + } + else { + delta_h_apo = h2_apo - h1_apo - 2. * CV_PI; + } - double H_bar_apo; - if (C1_apo == 0 || C2_apo == 0) { - H_bar_apo = h1_apo + h2_apo; - } else if (abs(h1_apo - h2_apo) <= CV_PI) { - H_bar_apo = (h1_apo + h2_apo) / 2.0; - } else if (h1_apo + h2_apo < 2. * CV_PI) { - H_bar_apo = (h1_apo + h2_apo + 2. * CV_PI) / 2.0; - } else { - H_bar_apo = (h1_apo + h2_apo - 2. * CV_PI) / 2.0; - } + double H_bar_apo; + if (C1_apo == 0 || C2_apo == 0) { + H_bar_apo = h1_apo + h2_apo; + } + else if (abs(h1_apo - h2_apo) <= CV_PI) { + H_bar_apo = (h1_apo + h2_apo) / 2.0; + } + else if (h1_apo + h2_apo < 2. * CV_PI) { + H_bar_apo = (h1_apo + h2_apo + 2. * CV_PI) / 2.0; + } + else { + H_bar_apo = (h1_apo + h2_apo - 2. * CV_PI) / 2.0; + } - double delta_H_apo = 2.0 * sqrt(C1_apo * C2_apo) * sin(delta_h_apo / 2.0); - double T = 1.0 - 0.17 * cos(H_bar_apo - toRad(30.)) + - 0.24 * cos(2.0 * H_bar_apo) + - 0.32 * cos(3.0 * H_bar_apo + toRad(6.0)) - - 0.2 * cos(4.0 * H_bar_apo - toRad(63.0)); - double sC = 1.0 + 0.045 * C_bar_apo; - double sH = 1.0 + 0.015 * C_bar_apo * T; - double sL = 1.0 + ((0.015 * pow(l_bar_apo - 50.0, 2.0)) / - sqrt(20.0 + pow(l_bar_apo - 50.0, 2.0))); - double RT = -2.0 * G * + double delta_H_apo = 2.0 * sqrt(C1_apo * C2_apo) * sin(delta_h_apo / 2.0); + double T = 1.0 - 0.17 * cos(H_bar_apo - toRad(30.)) + + 0.24 * cos(2.0 * H_bar_apo) + + 0.32 * cos(3.0 * H_bar_apo + toRad(6.0)) - + 0.2 * cos(4.0 * H_bar_apo - toRad(63.0)); + double sC = 1.0 + 0.045 * C_bar_apo; + double sH = 1.0 + 0.015 * C_bar_apo * T; + double sL = 1.0 + ((0.015 * pow(l_bar_apo - 50.0, 2.0)) / + sqrt(20.0 + pow(l_bar_apo - 50.0, 2.0))); + double RT = -2.0 * G * sin(toRad(60.0) * exp(-pow((H_bar_apo - toRad(275.0)) / toRad(25.0), 2.0))); - double res = - (pow(delta_L_apo / (kL * sL), 2.0) + pow(delta_C_apo / (kC * sC), 2.0) + - pow(delta_H_apo / (kH * sH), 2.0) + - RT * (delta_C_apo / (kC * sC)) * (delta_H_apo / (kH * sH))); - return res > 0 ? sqrt(res) : 0; -} + double res = + (pow(delta_L_apo / (kL * sL), 2.0) + pow(delta_C_apo / (kC * sC), 2.0) + + pow(delta_H_apo / (kH * sH), 2.0) + + RT * (delta_C_apo / (kC * sC)) * (delta_H_apo / (kH * sH))); + return res > 0 ? sqrt(res) : 0; + } -double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2) { - return deltaCIEDE2000_(lab1, lab2); -} + double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2) { + return deltaCIEDE2000_(lab1, lab2); + } -/* *\ brief distance between two points in formula CMC - *\ param lab1 a 3D vector - *\ param lab2 a 3D vector - *\ param kL Lightness scale - *\ param kC Chroma scale - *\ return distance between lab1 and lab2 -*/ -double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL, double kC) { - double dL = lab2[0] - lab1[0]; - double da = lab2[1] - lab1[1]; - double db = lab2[2] - lab1[2]; - double C1 = sqrt(pow(lab1[1], 2.0) + pow(lab1[2], 2.0)); - double C2 = sqrt(pow(lab2[1], 2.0) + pow(lab2[2], 2.0)); - double dC = C2 - C1; - double dH = sqrt(pow(da, 2) + pow(db, 2) - pow(dC, 2)); + /* *\ brief distance between two points in formula CMC + *\ param lab1 a 3D vector + *\ param lab2 a 3D vector + *\ param kL Lightness scale + *\ param kC Chroma scale + *\ return distance between lab1 and lab2 + */ + double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL, double kC) { + double dL = lab2[0] - lab1[0]; + double da = lab2[1] - lab1[1]; + double db = lab2[2] - lab1[2]; + double C1 = sqrt(pow(lab1[1], 2.0) + pow(lab1[2], 2.0)); + double C2 = sqrt(pow(lab2[1], 2.0) + pow(lab2[2], 2.0)); + double dC = C2 - C1; + double dH = sqrt(pow(da, 2) + pow(db, 2) - pow(dC, 2)); - double H1; - if (C1 == 0.) { - H1 = 0.0; - } else { - H1 = atan2(lab1[2], lab1[1]); - if (H1 < 0.0) H1 += 2. * CV_PI; - } + double H1; + if (C1 == 0.) { + H1 = 0.0; + } + else { + H1 = atan2(lab1[2], lab1[1]); + if (H1 < 0.0) H1 += 2. * CV_PI; + } - double F = pow(C1, 2) / sqrt(pow(C1, 4) + 1900); - double T = (H1 > toRad(164) && H1 <= toRad(345)) - ? 0.56 + abs(0.2 * cos(H1 + toRad(168))) - : 0.36 + abs(0.4 * cos(H1 + toRad(35))); - ; - double sL = - lab1[0] < 16. ? 0.511 : (0.040975 * lab1[0]) / (1.0 + 0.01765 * lab1[0]); - ; - double sC = (0.0638 * C1) / (1.0 + 0.0131 * C1) + 0.638; - double sH = sC * (F * T + 1.0 - F); + double F = pow(C1, 2) / sqrt(pow(C1, 4) + 1900); + double T = (H1 > toRad(164) && H1 <= toRad(345)) + ? 0.56 + abs(0.2 * cos(H1 + toRad(168))) + : 0.36 + abs(0.4 * cos(H1 + toRad(35))); + ; + double sL = + lab1[0] < 16. ? 0.511 : (0.040975 * lab1[0]) / (1.0 + 0.01765 * lab1[0]); + ; + double sC = (0.0638 * C1) / (1.0 + 0.0131 * C1) + 0.638; + double sH = sC * (F * T + 1.0 - F); - return sqrt(pow(dL / (kL * sL), 2.0) + pow(dC / (kC * sC), 2.0) + + return sqrt(pow(dL / (kL * sL), 2.0) + pow(dC / (kC * sC), 2.0) + pow(dH / sH, 2.0)); -} + } -double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2) { - return deltaCMC(lab1, lab2); -} + double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2) { + return deltaCMC(lab1, lab2); + } -double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2) { - return deltaCMC(lab1, lab2, 2, 1); -} + double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2) { + return deltaCMC(lab1, lab2, 2, 1); + } -cv::Mat distance(cv::Mat src, cv::Mat ref, DISTANCE_TYPE distance_type) { - switch (distance_type) { - case cv::ccm::CIE76: - return distanceWise(src, ref, deltaCIE76); - case cv::ccm::CIE94_GRAPHIC_ARTS: - return distanceWise(src, ref, deltaCIE94GraphicArts); - case cv::ccm::CIE94_TEXTILES: - return distanceWise(src, ref, deltaCIE94Textiles); - case cv::ccm::CIE2000: - return distanceWise(src, ref, deltaCIEDE2000); - case cv::ccm::CMC_1TO1: - return distanceWise(src, ref, deltaCMC1To1); - case cv::ccm::CMC_2TO1: - return distanceWise(src, ref, deltaCMC2To1); - case cv::ccm::RGB: - return distanceWise(src, ref, deltaCIE76); - case cv::ccm::RGBL: - return distanceWise(src, ref, deltaCIE76); - default: - throw std::invalid_argument{"Wrong distance_type!"}; - break; - } -}; + cv::Mat distance(cv::Mat src, cv::Mat ref, DISTANCE_TYPE distance_type) { + switch (distance_type) { + case cv::ccm::CIE76: + return distanceWise(src, ref, deltaCIE76); + case cv::ccm::CIE94_GRAPHIC_ARTS: + return distanceWise(src, ref, deltaCIE94GraphicArts); + case cv::ccm::CIE94_TEXTILES: + return distanceWise(src, ref, deltaCIE94Textiles); + case cv::ccm::CIE2000: + return distanceWise(src, ref, deltaCIEDE2000); + case cv::ccm::CMC_1TO1: + return distanceWise(src, ref, deltaCMC1To1); + case cv::ccm::CMC_2TO1: + return distanceWise(src, ref, deltaCMC2To1); + case cv::ccm::RGB: + return distanceWise(src, ref, deltaCIE76); + case cv::ccm::RGBL: + return distanceWise(src, ref, deltaCIE76); + default: + throw std::invalid_argument{ "Wrong distance_type!" }; + break; + } + }; -} // namespace ccm + } // namespace ccm } // namespace cv -#endif \ No newline at end of file +#endif diff --git a/modules/mcc/include/opencv2/mcc/io.hpp b/modules/mcc/include/opencv2/mcc/io.hpp index ddd06bea540..fe7736bb01f 100644 --- a/modules/mcc/include/opencv2/mcc/io.hpp +++ b/modules/mcc/include/opencv2/mcc/io.hpp @@ -36,75 +36,75 @@ namespace cv { -namespace ccm -{ - -/* *\ brief Io is the meaning of illuminant and observer. See notes of ccm.hpp - * for supported list for illuminant and observer*/ -class IO -{ -public: - - std::string illuminant; - std::string observer; - - IO() {}; - - IO(std::string illuminant_, std::string observer_) :illuminant(illuminant_), observer(observer_) {}; - - virtual ~IO() {}; - - bool operator<(const IO& other) const - { - return (illuminant < other.illuminant || ((illuminant == other.illuminant) && (observer < other.observer))); - } - - bool operator==(const IO& other) const - { - return illuminant == other.illuminant && observer == other.observer; - }; -}; - -const IO A_2("A", "2"), A_10("A", "10"), - D50_2("D50", "2"), D50_10("D50", "10"), - D55_2("D55", "2"), D55_10("D55", "10"), - D65_2("D65", "2"), D65_10("D65", "10"), - D75_2("D75", "2"), D75_10("D75", "10"), - E_2("E", "2"), E_10("E", "10"); - -// data from https://en.wikipedia.org/wiki/Standard_illuminant. -const static std::map> illuminants_xy = -{ - {A_2, { 0.44757, 0.40745 }}, {A_10, { 0.45117, 0.40594 }}, - {D50_2, { 0.34567, 0.35850 }}, {D50_10, { 0.34773, 0.35952 }}, - {D55_2, { 0.33242, 0.34743 }}, {D55_10, { 0.33411, 0.34877 }}, - {D65_2, { 0.31271, 0.32902 }}, {D65_10, { 0.31382, 0.33100 }}, - {D75_2, { 0.29902, 0.31485 }}, {D75_10, { 0.45117, 0.40594 }}, - {E_2, { 1 / 3, 1 / 3 }}, {E_10, { 1 / 3, 1 / 3 }}, -}; - -std::vector xyY2XYZ(const std::vector& xyY); -std::vector xyY2XYZ(const std::vector& xyY) -{ - double Y = xyY.size() >= 3 ? xyY[2] : 1; - return { Y * xyY[0] / xyY[1], Y, Y / xyY[1] * (1 - xyY[0] - xyY[1]) }; -} - -/* *\ brief function to get illuminants*/ -static std::map > getIlluminant(); -static std::map > getIlluminant() -{ - std::map > illuminants; - for (auto it = illuminants_xy.begin(); it != illuminants_xy.end(); ++it) + namespace ccm { - illuminants[it->first] = xyY2XYZ(it->second); - } - return illuminants; -} -const std::map > illuminants = getIlluminant(); -} // namespace ccm + /* *\ brief Io is the meaning of illuminant and observer. See notes of ccm.hpp + * for supported list for illuminant and observer*/ + class IO + { + public: + + std::string illuminant; + std::string observer; + + IO() {}; + + IO(std::string illuminant_, std::string observer_) :illuminant(illuminant_), observer(observer_) {}; + + virtual ~IO() {}; + + bool operator<(const IO& other) const + { + return (illuminant < other.illuminant || ((illuminant == other.illuminant) && (observer < other.observer))); + } + + bool operator==(const IO& other) const + { + return illuminant == other.illuminant && observer == other.observer; + }; + }; + + const IO A_2("A", "2"), A_10("A", "10"), + D50_2("D50", "2"), D50_10("D50", "10"), + D55_2("D55", "2"), D55_10("D55", "10"), + D65_2("D65", "2"), D65_10("D65", "10"), + D75_2("D75", "2"), D75_10("D75", "10"), + E_2("E", "2"), E_10("E", "10"); + + // data from https://en.wikipedia.org/wiki/Standard_illuminant. + const static std::map> illuminants_xy = + { + {A_2, { 0.44757, 0.40745 }}, {A_10, { 0.45117, 0.40594 }}, + {D50_2, { 0.34567, 0.35850 }}, {D50_10, { 0.34773, 0.35952 }}, + {D55_2, { 0.33242, 0.34743 }}, {D55_10, { 0.33411, 0.34877 }}, + {D65_2, { 0.31271, 0.32902 }}, {D65_10, { 0.31382, 0.33100 }}, + {D75_2, { 0.29902, 0.31485 }}, {D75_10, { 0.45117, 0.40594 }}, + {E_2, { 1 / 3, 1 / 3 }}, {E_10, { 1 / 3, 1 / 3 }}, + }; + + std::vector xyY2XYZ(const std::vector& xyY); + std::vector xyY2XYZ(const std::vector& xyY) + { + double Y = xyY.size() >= 3 ? xyY[2] : 1; + return { Y * xyY[0] / xyY[1], Y, Y / xyY[1] * (1 - xyY[0] - xyY[1]) }; + } + + /* *\ brief function to get illuminants*/ + static std::map > getIlluminant(); + static std::map > getIlluminant() + { + std::map > illuminants; + for (auto it = illuminants_xy.begin(); it != illuminants_xy.end(); ++it) + { + illuminants[it->first] = xyY2XYZ(it->second); + } + return illuminants; + } + + const std::map > illuminants = getIlluminant(); + } // namespace ccm } // namespace cv -#endif \ No newline at end of file +#endif diff --git a/modules/mcc/include/opencv2/mcc/linearize.hpp b/modules/mcc/include/opencv2/mcc/linearize.hpp index 9f5cb75d9f4..ecc6227a87b 100644 --- a/modules/mcc/include/opencv2/mcc/linearize.hpp +++ b/modules/mcc/include/opencv2/mcc/linearize.hpp @@ -33,267 +33,267 @@ namespace cv { -namespace ccm -{ + namespace ccm + { -/* *\ brief Enum of the possible types of linearization. -*/ -enum LINEAR_TYPE -{ - IDENTITY_, - GAMMA, - COLORPOLYFIT, - COLORLOGPOLYFIT, - GRAYPOLYFIT, - GRAYLOGPOLYFIT -}; - -/* *\ brief Polyfit model. -*/ -class Polyfit -{ -public: - int deg; - cv::Mat p; + /* *\ brief Enum of the possible types of linearization. + */ + enum LINEAR_TYPE + { + IDENTITY_, + GAMMA, + COLORPOLYFIT, + COLORLOGPOLYFIT, + GRAYPOLYFIT, + GRAYLOGPOLYFIT + }; + + /* *\ brief Polyfit model. + */ + class Polyfit + { + public: + int deg; + cv::Mat p; - Polyfit() {}; + Polyfit() {}; - /* *\ brief Polyfit method. - */ - Polyfit(cv::Mat s, cv::Mat d, int deg_) :deg(deg_) - { - int npoints = s.checkVector(1); - cv::Mat_ srcX(s), srcY(d); - cv::Mat_ m = cv::Mat_::ones(npoints, deg + 1); - for (int y = 0; y < npoints; ++y) + /* *\ brief Polyfit method. + */ + Polyfit(cv::Mat s, cv::Mat d, int deg_) :deg(deg_) + { + int npoints = s.checkVector(1); + cv::Mat_ srcX(s), srcY(d); + cv::Mat_ m = cv::Mat_::ones(npoints, deg + 1); + for (int y = 0; y < npoints; ++y) + { + for (int x = 1; x < m.cols; ++x) + { + m.at(y, x) = srcX.at(y) * m.at(y, x - 1); + } + } + cv::solve(m, srcY, p, DECOMP_SVD); + } + + virtual ~Polyfit() {}; + cv::Mat operator()(const cv::Mat& inp) + { + return elementWise(inp, [this](double a)->double {return fromEW(a); }); + }; + + private: + double fromEW(double x) + { + double res = 0; + for (int d = 0; d <= deg; ++d) + { + res += pow(x, d) * p.at(d, 0); + } + return res; + }; + }; + + /* *\ brief Logpolyfit model. + */ + class LogPolyfit { - for (int x = 1; x < m.cols; ++x) + public: + int deg; + Polyfit p; + + LogPolyfit() {}; + + /* *\ brief Logpolyfit method. + */ + LogPolyfit(cv::Mat s, cv::Mat d, int deg_) :deg(deg_) { - m.at(y, x) = srcX.at(y) * m.at(y, x -1); + cv::Mat mask_ = (s > 0) & (d > 0); + cv::Mat src_, dst_, s_, d_; + src_ = maskCopyTo(s, mask_); + dst_ = maskCopyTo(d, mask_); + log(src_, s_); + log(dst_, d_); + p = Polyfit(s_, d_, deg); } - } - cv::solve(m, srcY, p, DECOMP_SVD); - } - virtual ~Polyfit() {}; - cv::Mat operator()(const cv::Mat& inp) - { - return elementWise(inp, [this](double a)->double {return fromEW(a); }); - }; + virtual ~LogPolyfit() {}; -private: - double fromEW(double x) - { - double res = 0; - for (int d = 0; d <= deg; ++d) + cv::Mat operator()(const cv::Mat& inp) + { + cv::Mat mask_ = inp >= 0; + cv::Mat y, y_, res; + log(inp, y); + y = p(y); + exp(y, y_); + y_.copyTo(res, mask_); + return res; + }; + }; + + /* *\ brief Linearization base. + */ + class Linear { - res += pow(x, d) * p.at(d, 0); - } - return res; - }; -}; - -/* *\ brief Logpolyfit model. -*/ -class LogPolyfit -{ -public: - int deg; - Polyfit p; + public: + Linear() {}; - LogPolyfit() {}; + virtual ~Linear() {}; - /* *\ brief Logpolyfit method. - */ - LogPolyfit(cv::Mat s, cv::Mat d, int deg_) :deg(deg_) - { - cv::Mat mask_ = (s > 0) & (d > 0); - cv::Mat src_, dst_, s_, d_; - src_ = maskCopyTo(s, mask_); - dst_ = maskCopyTo(d, mask_); - log(src_, s_); - log(dst_, d_); - p = Polyfit(s_, d_, deg); - } - - virtual ~LogPolyfit() {}; - - cv::Mat operator()(const cv::Mat& inp) - { - cv::Mat mask_ = inp >= 0; - cv::Mat y, y_, res; - log(inp, y); - y = p(y); - exp(y, y_); - y_.copyTo(res, mask_); - return res; - }; -}; - -/* *\ brief Linearization base. -*/ -class Linear -{ -public: - Linear() {}; + /* *\ brief Inference. + *\ param inp the input array, type of cv::Mat. + */ + virtual cv::Mat linearize(cv::Mat inp) + { + return inp; + }; - virtual ~Linear() {}; + /* *\brief Evaluate linearization model. + */ + virtual void value(void) {}; + }; - /* *\ brief Inference. - *\ param inp the input array, type of cv::Mat. - */ - virtual cv::Mat linearize(cv::Mat inp) - { - return inp; - }; - /* *\brief Evaluate linearization model. - */ - virtual void value(void) {}; -}; + /* *\ brief Linearization identity. + * make no change. + */ + class LinearIdentity : public Linear {}; + /* *\ brief Linearization gamma correction. + */ + class LinearGamma : public Linear + { + public: + double gamma; -/* *\ brief Linearization identity. - * make no change. -*/ -class LinearIdentity : public Linear {}; + LinearGamma(double gamma_) :gamma(gamma_) {}; -/* *\ brief Linearization gamma correction. -*/ -class LinearGamma : public Linear -{ -public: - double gamma; + cv::Mat linearize(cv::Mat inp) CV_OVERRIDE + { + return gammaCorrection(inp, gamma); + }; + }; + + /* *\ brief Linearization. + * Grayscale polynomial fitting. + */ + template + class LinearGray :public Linear + { + public: + int deg; + T p; - LinearGamma(double gamma_) :gamma(gamma_) {}; + LinearGray(int deg_, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg_) + { + dst.getGray(); + Mat lear_gray_mask = mask & dst.grays; - cv::Mat linearize(cv::Mat inp) CV_OVERRIDE - { - return gammaCorrection(inp, gamma); - }; -}; - -/* *\ brief Linearization. - * Grayscale polynomial fitting. -*/ -template -class LinearGray :public Linear -{ -public: - int deg; - T p; + // the grayscale function is approximate for src is in relative color space. + src = rgb2gray(maskCopyTo(src, lear_gray_mask)); + cv::Mat dst_ = maskCopyTo(dst.toGray(cs.io), lear_gray_mask); + calc(src, dst_); + } - LinearGray(int deg_, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg_) - { - dst.getGray(); - Mat lear_gray_mask = mask & dst.grays; - - // the grayscale function is approximate for src is in relative color space. - src = rgb2gray(maskCopyTo(src, lear_gray_mask)); - cv::Mat dst_ = maskCopyTo(dst.toGray(cs.io), lear_gray_mask); - calc(src, dst_); - } - - /* *\ brief monotonically increase is not guaranteed. - *\ param src the input array, type of cv::Mat. - *\ param dst the input array, type of cv::Mat. - */ - void calc(const cv::Mat& src, const cv::Mat& dst) - { - p = T(src, dst, deg); - }; + /* *\ brief monotonically increase is not guaranteed. + *\ param src the input array, type of cv::Mat. + *\ param dst the input array, type of cv::Mat. + */ + void calc(const cv::Mat& src, const cv::Mat& dst) + { + p = T(src, dst, deg); + }; - cv::Mat linearize(cv::Mat inp) CV_OVERRIDE - { - return p(inp); - }; -}; - -/* *\ brief Linearization. - * Fitting channels respectively. -*/ -template -class LinearColor :public Linear -{ -public: - int deg; - T pr; - T pg; - T pb; + cv::Mat linearize(cv::Mat inp) CV_OVERRIDE + { + return p(inp); + }; + }; + + /* *\ brief Linearization. + * Fitting channels respectively. + */ + template + class LinearColor :public Linear + { + public: + int deg; + T pr; + T pg; + T pb; - LinearColor(int deg_, cv::Mat src_, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg_) - { - Mat src = maskCopyTo(src_, mask); - cv::Mat dst_ = maskCopyTo(dst.to(*cs.l).colors, mask); - calc(src, dst_); - } + LinearColor(int deg_, cv::Mat src_, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg_) + { + Mat src = maskCopyTo(src_, mask); + cv::Mat dst_ = maskCopyTo(dst.to(*cs.l).colors, mask); + calc(src, dst_); + } - void calc(const cv::Mat& src, const cv::Mat& dst) - { - cv::Mat schannels[3]; - cv::Mat dchannels[3]; - split(src, schannels); - split(dst, dchannels); - pr = T(schannels[0], dchannels[0], deg); - pg = T(schannels[1], dchannels[1], deg); - pb = T(schannels[2], dchannels[2], deg); - }; - - cv::Mat linearize(cv::Mat inp) CV_OVERRIDE - { - cv::Mat channels[3]; - split(inp, channels); - std::vector channel; - cv::Mat res; - merge(std::vector{ pr(channels[0]), pr(channels[1]), pr(channels[2]) }, res); - return res; - }; -}; - - -/* *\ brief Get linearization method. - * used in ccm model. - *\ param gamma used in LinearGamma. - *\ param deg degrees. - *\ param src the input array, type of cv::Mat. - *\ param dst the input array, type of cv::Mat. - *\ param mask the input array, type of cv::Mat. - *\ param cs type of RGBBase_. - *\ param linear_type type of linear. -*/ -std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type); -std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type) -{ - std::shared_ptr p = std::make_shared(); - switch (linear_type) - { - case cv::ccm::IDENTITY_: - p.reset(new LinearIdentity()); - break; - case cv::ccm::GAMMA: - p.reset(new LinearGamma(gamma)); - break; - case cv::ccm::COLORPOLYFIT: - p.reset(new LinearColor(deg, src, dst, mask, cs)); - break; - case cv::ccm::COLORLOGPOLYFIT: - p.reset(new LinearColor(deg, src, dst, mask, cs)); - break; - case cv::ccm::GRAYPOLYFIT: - p.reset(new LinearGray(deg, src, dst, mask, cs)); - break; - case cv::ccm::GRAYLOGPOLYFIT: - p.reset(new LinearGray(deg, src, dst, mask, cs)); - break; - default: - throw std::invalid_argument{ "Wrong linear_type!" }; - break; - } - return p; -}; - -} // namespace ccm + void calc(const cv::Mat& src, const cv::Mat& dst) + { + cv::Mat schannels[3]; + cv::Mat dchannels[3]; + split(src, schannels); + split(dst, dchannels); + pr = T(schannels[0], dchannels[0], deg); + pg = T(schannels[1], dchannels[1], deg); + pb = T(schannels[2], dchannels[2], deg); + }; + + cv::Mat linearize(cv::Mat inp) CV_OVERRIDE + { + cv::Mat channels[3]; + split(inp, channels); + std::vector channel; + cv::Mat res; + merge(std::vector{ pr(channels[0]), pg(channels[1]), pb(channels[2]) }, res); + return res; + }; + }; + + + /* *\ brief Get linearization method. + * used in ccm model. + *\ param gamma used in LinearGamma. + *\ param deg degrees. + *\ param src the input array, type of cv::Mat. + *\ param dst the input array, type of cv::Mat. + *\ param mask the input array, type of cv::Mat. + *\ param cs type of RGBBase_. + *\ param linear_type type of linear. + */ + std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type); + std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type) + { + std::shared_ptr p = std::make_shared(); + switch (linear_type) + { + case cv::ccm::IDENTITY_: + p.reset(new LinearIdentity()); + break; + case cv::ccm::GAMMA: + p.reset(new LinearGamma(gamma)); + break; + case cv::ccm::COLORPOLYFIT: + p.reset(new LinearColor(deg, src, dst, mask, cs)); + break; + case cv::ccm::COLORLOGPOLYFIT: + p.reset(new LinearColor(deg, src, dst, mask, cs)); + break; + case cv::ccm::GRAYPOLYFIT: + p.reset(new LinearGray(deg, src, dst, mask, cs)); + break; + case cv::ccm::GRAYLOGPOLYFIT: + p.reset(new LinearGray(deg, src, dst, mask, cs)); + break; + default: + throw std::invalid_argument{ "Wrong linear_type!" }; + break; + } + return p; + }; + + } // namespace ccm } // namespace cv -#endif +#endif#pragma once diff --git a/modules/mcc/include/opencv2/mcc/operations.hpp b/modules/mcc/include/opencv2/mcc/operations.hpp index dda1866dd10..783eb64eb1b 100644 --- a/modules/mcc/include/opencv2/mcc/operations.hpp +++ b/modules/mcc/include/opencv2/mcc/operations.hpp @@ -35,107 +35,107 @@ namespace cv { -namespace ccm -{ + namespace ccm + { -typedef std::function MatFunc; + typedef std::function MatFunc; -/* *\ brief Operation class contains some operarions used for color space - * conversion containing linear transformation and non-linear transformation - */ -class Operation -{ -public: - bool linear; - cv::Mat M; - MatFunc f; + /* *\ brief Operation class contains some operarions used for color space + * conversion containing linear transformation and non-linear transformation + */ + class Operation + { + public: + bool linear; + cv::Mat M; + MatFunc f; - Operation() : linear(true), M(cv::Mat()) {}; + Operation() : linear(true), M(cv::Mat()) {}; - Operation(cv::Mat M_) :linear(true), M( M_ ) {}; + Operation(cv::Mat M_) :linear(true), M(M_) {}; - Operation(MatFunc f_) : linear(false), f(f_) {}; + Operation(MatFunc f_) : linear(false), f(f_) {}; - virtual ~Operation() {}; - /* *\ brief operator function will run operation*/ - cv::Mat operator()(cv::Mat& abc) - { - if (!linear) - { - return f(abc); - } - if (M.empty()) - { - return abc; - } - return multiple(abc, M); - }; - - /* *\ brief add function will conbine this operation - * with other linear transformation operation*/ - void add(const Operation& other) - { - if (M.empty()) - { - M = other.M.clone(); - } - else - { - M = M * other.M; - } - }; - - void clear() - { - M = cv::Mat(); - }; -}; - -const Operation IDENTITY_OP( [](cv::Mat x) {return x; } ); + virtual ~Operation() {}; + /* *\ brief operator function will run operation*/ + cv::Mat operator()(cv::Mat& abc) + { + if (!linear) + { + return f(abc); + } + if (M.empty()) + { + return abc; + } + return multiple(abc, M); + }; + + /* *\ brief add function will conbine this operation + * with other linear transformation operation*/ + void add(const Operation& other) + { + if (M.empty()) + { + M = other.M.clone(); + } + else + { + M = M * other.M; + } + }; + + void clear() + { + M = cv::Mat(); + }; + }; -class Operations -{ -public: - std::vector ops; + const Operation IDENTITY_OP([](cv::Mat x) {return x; }); - Operations() :ops{ } {}; + class Operations + { + public: + std::vector ops; - Operations(std::initializer_list op) :ops{ op } {}; + Operations() :ops{ } {}; - virtual ~Operations() {}; + Operations(std::initializer_list op) :ops{ op } {}; - /* *\ brief add function will conbine this operation with other transformation operations*/ - Operations& add(const Operations& other) - { - ops.insert(ops.end(), other.ops.begin(), other.ops.end()); - return *this; - }; + virtual ~Operations() {}; - /* *\ brief run operations to make color conversion*/ - cv::Mat run(cv::Mat abc) - { - Operation hd; - for (auto& op : ops) - { - if (op.linear) + /* *\ brief add function will conbine this operation with other transformation operations*/ + Operations& add(const Operations& other) { - hd.add(op); - } - else + ops.insert(ops.end(), other.ops.begin(), other.ops.end()); + return *this; + }; + + /* *\ brief run operations to make color conversion*/ + cv::Mat run(cv::Mat abc) { + Operation hd; + for (auto& op : ops) + { + if (op.linear) + { + hd.add(op); + } + else + { + abc = hd(abc); + hd.clear(); + abc = op(abc); + } + } abc = hd(abc); - hd.clear(); - abc = op(abc); - } - } - abc = hd(abc); - return abc; - }; -}; - -const Operations IDENTITY_OPS{ IDENTITY_OP }; - -} // namespace ccm + return abc; + }; + }; + + const Operations IDENTITY_OPS{ IDENTITY_OP }; + + } // namespace ccm } // namespace cv diff --git a/modules/mcc/include/opencv2/mcc/utils.hpp b/modules/mcc/include/opencv2/mcc/utils.hpp index 6528e4284ab..4ef01d50896 100644 --- a/modules/mcc/include/opencv2/mcc/utils.hpp +++ b/modules/mcc/include/opencv2/mcc/utils.hpp @@ -37,201 +37,200 @@ namespace cv { -namespace ccm -{ - -double gammaCorrection_(const double& element, const double& gamma); -cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma); -cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask); -cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm); -cv::Mat saturate(cv::Mat& src, const double& low, const double& up); -cv::Mat rgb2gray(cv::Mat rgb); - -/* *\ brief function for elementWise operation - *\ param src the input array, type of cv::Mat - *\ lambda a for operation -*/ -template -cv::Mat elementWise(const cv::Mat& src, F&& lambda) -{ - cv::Mat dst = src.clone(); - const int channel = src.channels(); - switch (channel) - { - case 1: + namespace ccm { - cv::MatIterator_ it, end; - for (it = dst.begin(), end = dst.end(); it != end; ++it) + + double gammaCorrection_(const double& element, const double& gamma); + cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma); + cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask); + cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm); + cv::Mat saturate(cv::Mat& src, const double& low, const double& up); + cv::Mat rgb2gray(cv::Mat rgb); + + /* *\ brief function for elementWise operation + *\ param src the input array, type of cv::Mat + *\ lambda a for operation + */ + template + cv::Mat elementWise(const cv::Mat& src, F&& lambda) { - (*it) = lambda((*it)); + cv::Mat dst = src.clone(); + const int channel = src.channels(); + switch (channel) + { + case 1: + { + cv::MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) + { + (*it) = lambda((*it)); + } + break; + } + case 3: + { + cv::MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) + { + for (int j = 0; j < 3; j++) + { + (*it)[j] = lambda((*it)[j]); + } + } + break; + } + default: + throw std::invalid_argument{ "Wrong channel!" }; + break; + } + return dst; } - break; - } - case 3: - { - cv::MatIterator_ it, end; - for (it = dst.begin(), end = dst.end(); it != end; ++it) + + /* *\ brief function for channel operation + *\ param src the input array, type of cv::Mat + *\ lambda the function for operation + */ + template + cv::Mat channelWise(const cv::Mat& src, F&& lambda) { - for (int j = 0; j < 3; j++) + cv::Mat dst = src.clone(); + cv::MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) { - (*it)[j] = lambda((*it)[j]); + *it = lambda(*it); } + return dst; } - break; - } - default: - throw std::invalid_argument { "Wrong channel!" }; - break; - } - return dst; -} - -/* *\ brief function for channel operation - *\ param src the input array, type of cv::Mat - *\ lambda the function for operation -*/ -template -cv::Mat channelWise(const cv::Mat& src, F&& lambda) -{ - cv::Mat dst = src.clone(); - cv::MatIterator_ it, end; - for (it = dst.begin(), end = dst.end(); it != end; ++it) - { - *it = lambda(*it); - } - return dst; -} - -/* *\ brief function for distance operation. - *\ param src the input array, type of cv::Mat. - *\ param ref another input array, type of cv::Mat. - *\ param lambda the computing method for distance . -*/ -template -cv::Mat distanceWise(cv::Mat& src, cv::Mat& ref, F&& lambda) -{ - cv::Mat dst = cv::Mat(src.size(), CV_64FC1); - cv::MatIterator_ it_src = src.begin(), end_src = src.end(), - it_ref = ref.begin(); - cv::MatIterator_ it_dst = dst.begin(); - for (; it_src != end_src; ++it_src, ++it_ref, ++it_dst) - { - *it_dst = lambda(*it_src, *it_ref); - } - return dst; -} - - -double gammaCorrection_(const double& element, const double& gamma) -{ - return (element >= 0 ? pow(element, gamma) : -pow((-element), gamma)); -} - -/* *\ brief gamma correction ,see ColorSpace.pdf for details. - *\ param src the input array,type of cv::Mat. - *\ param gamma a constant for gamma correction. -*/ -cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma) -{ - return elementWise(src, [gamma](double element)->double {return gammaCorrection_(element, gamma); }); -} -/* *\ brief maskCopyTo a function to delete unsatisfied elementwise. - *\ param src the input array, type of cv::Mat. - *\ param mask operation mask that used to choose satisfided elementwise. - */ -cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) -{ - cv::Mat dst(countNonZero(mask), 1, src.type()); - const int channel = src.channels(); - auto it_mask = mask.begin(); - switch (channel) - { - case 1: - { - auto it_src = src.begin(), end_src = src.end(); - auto it_dst = dst.begin(); - for (; it_src != end_src; ++it_src, ++it_mask) + /* *\ brief function for distance operation. + *\ param src the input array, type of cv::Mat. + *\ param ref another input array, type of cv::Mat. + *\ param lambda the computing method for distance . + */ + template + cv::Mat distanceWise(cv::Mat& src, cv::Mat& ref, F&& lambda) { - if (*it_mask) + cv::Mat dst = cv::Mat(src.size(), CV_64FC1); + cv::MatIterator_ it_src = src.begin(), end_src = src.end(), + it_ref = ref.begin(); + cv::MatIterator_ it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_ref, ++it_dst) { - (*it_dst) = (*it_src); - ++it_dst; + *it_dst = lambda(*it_src, *it_ref); } + return dst; } - break; - } - case 3: - { - auto it_src = src.begin(), end_src = src.end(); - auto it_dst = dst.begin(); - for (; it_src != end_src; ++it_src, ++it_mask) + + + double gammaCorrection_(const double& element, const double& gamma) + { + return (element >= 0 ? pow(element, gamma) : -pow((-element), gamma)); + } + + /* *\ brief gamma correction ,see ColorSpace.pdf for details. + *\ param src the input array,type of cv::Mat. + *\ param gamma a constant for gamma correction. + */ + cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma) + { + return elementWise(src, [gamma](double element)->double {return gammaCorrection_(element, gamma); }); + } + + /* *\ brief maskCopyTo a function to delete unsatisfied elementwise. + *\ param src the input array, type of cv::Mat. + *\ param mask operation mask that used to choose satisfided elementwise. + */ + cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) { - if (*it_mask) + cv::Mat dst(countNonZero(mask), 1, src.type()); + const int channel = src.channels(); + auto it_mask = mask.begin(); + switch (channel) + { + case 1: { - (*it_dst) = (*it_src); - ++it_dst; + auto it_src = src.begin(), end_src = src.end(); + auto it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_mask) + { + if (*it_mask) + { + (*it_dst) = (*it_src); + ++it_dst; + } + } + break; + } + case 3: + { + auto it_src = src.begin(), end_src = src.end(); + auto it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_mask) + { + if (*it_mask) + { + (*it_dst) = (*it_src); + ++it_dst; + } + } + break; + } + default: + throw std::invalid_argument{ "Wrong channel!" }; + break; } + return dst; } - break; - } - default: - throw std::invalid_argument { "Wrong channel!" }; - break; - } - return dst; -} - -/* *\ brief multiple the function used to compute an array with n channels mulipied by ccm. - *\ param src the input array, type of cv::Mat. - *\ param ccm the ccm matrix to make color correction. -*/ -cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm) -{ - cv::Mat tmp = xyz.reshape(1, xyz.rows * xyz.cols); - cv::Mat res = tmp * ccm; - res = res.reshape(res.cols, xyz.rows); - return res; -} - -/* *\ brief multiple the function used to get the mask of saturated colors, - colors between low and up will be choosed. - *\ param src the input array, type of cv::Mat. - *\ param low the threshold to choose saturated colors - *\ param up the threshold to choose saturated colors -*/ -cv::Mat saturate(cv::Mat& src, const double& low, const double& up) -{ - cv::Mat dst = cv::Mat::ones(src.size(), CV_8UC1); - cv::MatIterator_ it_src = src.begin(), end_src = src.end(); - cv::MatIterator_ it_dst = dst.begin(); - for (; it_src != end_src; ++it_src, ++it_dst) - { - for (int i = 0; i < 3; ++i) + + /* *\ brief multiple the function used to compute an array with n channels mulipied by ccm. + *\ param src the input array, type of cv::Mat. + *\ param ccm the ccm matrix to make color correction. + */ + cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm) + { + cv::Mat tmp = xyz.reshape(1, xyz.rows * xyz.cols); + cv::Mat res = tmp * ccm; + res = res.reshape(res.cols, xyz.rows); + return res; + } + + /* *\ brief multiple the function used to get the mask of saturated colors, + colors between low and up will be choosed. + *\ param src the input array, type of cv::Mat. + *\ param low the threshold to choose saturated colors + *\ param up the threshold to choose saturated colors + */ + cv::Mat saturate(cv::Mat& src, const double& low, const double& up) { - if ((*it_src)[i] > up || (*it_src)[i] < low) + cv::Mat dst = cv::Mat::ones(src.size(), CV_8UC1); + cv::MatIterator_ it_src = src.begin(), end_src = src.end(); + cv::MatIterator_ it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_dst) { - *it_dst = 0; - break; + for (int i = 0; i < 3; ++i) + { + if ((*it_src)[i] > up || (*it_src)[i] < low) + { + *it_dst = 0; + break; + } + } } + return dst; } - } - return dst; -} -const static cv::Mat m_gray = (cv::Mat_(3, 1) << 0.2126, 0.7152, 0.0722); + const static cv::Mat m_gray = (cv::Mat_(3, 1) << 0.2126, 0.7152, 0.0722); -/* *\ brief rgb2gray it is an approximation grayscale function for relative RGB color space, - * see Miscellaneous.pdf for details; - *\ param rgb the input array, type of cv::Mat. - */ -cv::Mat rgb2gray(cv::Mat rgb) -{ - return multiple(rgb, m_gray); -} + /* *\ brief rgb2gray it is an approximation grayscale function for relative RGB color space, + * see Miscellaneous.pdf for details; + *\ param rgb the input array, type of cv::Mat. + */ + cv::Mat rgb2gray(cv::Mat rgb) + { + return multiple(rgb, m_gray); + } -} // namespace ccm + } // namespace ccm } // namespace cv - -#endif \ No newline at end of file +#endif From 483400c313f8ed68cb806f75444e9aa5dd086e43 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Tue, 8 Sep 2020 12:22:41 +0800 Subject: [PATCH 13/71] fix shadow variables warning & code style --- modules/mcc/include/opencv2/mcc/ccm.hpp | 68 +- modules/mcc/include/opencv2/mcc/color.hpp | 491 ++++--- .../mcc/include/opencv2/mcc/colorspace.hpp | 1159 ++++++++--------- modules/mcc/include/opencv2/mcc/distance.hpp | 454 ++++--- modules/mcc/include/opencv2/mcc/io.hpp | 134 +- modules/mcc/include/opencv2/mcc/linearize.hpp | 476 +++---- .../mcc/include/opencv2/mcc/operations.hpp | 176 +-- modules/mcc/include/opencv2/mcc/utils.hpp | 346 ++--- 8 files changed, 1645 insertions(+), 1659 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 36594b46704..4faed2c19f5 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -240,7 +240,6 @@ class ColorCorrectionModel cv::Mat ccm; cv::Mat ccm0; double loss; - //double loss0; int max_count; double epsilon; @@ -400,53 +399,28 @@ class ColorCorrectionModel } ccm_ = ccm_.reshape(0, ccm_loss->shape / 3); return ccm_loss->calc_loss(ccm_); - //Mat reshapecolor = ccm_loss->src_rgbl.reshape(1, 0) * ccm; - //cv::Mat dist = Color(reshapecolor.reshape(3, 0), ccm_loss->cs).diff(ccm_loss->dst, ccm_loss->distance); - //cv::Mat dist_; - //pow(dist, 2, dist_); - //if (!ccm_loss->weights.empty()) - //{ - // dist_ = ccm_loss->weights.mul(dist_); - //} - //Scalar ss = sum(dist_); - //return ss[0]; } }; - double calc_loss_(Color color, bool DEBUG = false) { - cv::Mat dist = color.diff(dst, distance, DEBUG); - // std::cout << "dist" << dist<< std::endl; + double calc_loss_(Color color) + { + cv::Mat distlist = color.diff(dst, distance); Color lab = color.to(Lab_D50_2); - if (DEBUG) { - std::cout << "dist: " << dist << std::endl; - std::cout << "colors: " << color.colors << std::endl; - std::cout << "TYPE: " << color.cs.type << std::endl; - std::cout << "linear: " << color.cs.linear << std::endl; - std::cout << "colors_lab: " << lab.colors << std::endl; - //std::cout << "ccm_: " << ccm_ << std::endl; - //std::cout << "converted: " << converted.reshape(3, 0) << std::endl; - } cv::Mat dist_; - //std::cout<<"dist_"<< dist_ < solver = cv::DownhillSolver::create(); cv::Ptr ptr_F(new LossFunction(this)); solver->setFunction(ptr_F); cv::Mat reshapeccm = ccm0.clone().reshape(0, 1); - cv::Mat step = cv::Mat::ones(reshapeccm.size(), CV_64F) * 0.1; - solver->setInitStep(step ); - /* TermCriteria termcrit = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, max_count, epsilon); - solver->setTermCriteria(termcrit);*/ + cv::Mat step = cv::Mat::ones(reshapeccm.size(), CV_64F); + solver->setInitStep(step); + TermCriteria termcrit = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, max_count, epsilon); + solver->setTermCriteria(termcrit); double res = solver->minimize(reshapeccm); ccm = reshapeccm.reshape(0, shape/3); loss = pow((res / masked_len), 0.5); @@ -518,13 +490,11 @@ class ColorCorrectionModel return out_img; }; - void report() { - std::cout << "CCM0: " << ccm0 << std::endl; - //std::cout << "Loss0: " << loss0 << std::endl; - std::cout << "CCM: " << ccm << std::endl; - std::cout << "Loss: " << loss << std::endl; - // std::cout << "mask: " << mask << std::endl; - } + // void report() { + // std::cout << "CCM0: " << ccm0 << std::endl; + // std::cout << "CCM: " << ccm << std::endl; + // std::cout << "Loss: " << loss << std::endl; + // } private: cv::Mat dist; @@ -562,12 +532,8 @@ class ColorCorrectionModel // weights' mask if (!weights.empty()) { - - cv::Mat weights_masked = maskCopyTo(this->weights, this->mask); - std::cout << weights_masked << std::endl; weights = weights_masked / mean(weights_masked)[0]; - } masked_len = (int)sum(mask)[0]; }; @@ -577,4 +543,4 @@ class ColorCorrectionModel } // namespace cv -#endif +#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/color.hpp b/modules/mcc/include/opencv2/mcc/color.hpp index 0937e3ad2f2..4d8a9350f4d 100644 --- a/modules/mcc/include/opencv2/mcc/color.hpp +++ b/modules/mcc/include/opencv2/mcc/color.hpp @@ -35,259 +35,252 @@ namespace cv { - namespace ccm +namespace ccm +{ + +/* *\ brief Color defined by color_values and color space +*/ + +class Color +{ +public: + + /* *\ param grays mask of grayscale color + *\ param colored mask of colored color + *\ param history storage of historical conversion + */ + cv::Mat colors; + const ColorSpace& cs; + cv::Mat grays; + cv::Mat colored; + std::map> history; + + Color(cv::Mat colors_, const ColorSpace& cs_, cv::Mat colored_) : colors(colors_), cs(cs_), colored(colored_) { + grays= ~colored; + } + Color(cv::Mat colors_, const ColorSpace& cs_) :colors(colors_), cs(cs_) {}; + + virtual ~Color() {}; + + /* *\ brief Change to other color space. + * The conversion process incorporates linear transformations to speed up. + * method is chromatic adapation method. + * when save if True, get data from history first. + *\ param other type of ColorSpace. + *\ return Color. + */ + Color to(const ColorSpace& other, CAM method = BRADFORD, bool save = true) + { + if (history.count(other) == 1) + { - /* *\ brief Color defined by color_values and color space - */ + return *history[other]; + } + if (cs.relate(other)) + { + return Color(cs.relation(other).run(colors), other); + } + Operations ops; + ops.add(cs.to).add(XYZ(cs.io).cam(other.io, method)).add(other.from); + std::shared_ptr color(new Color(ops.run(colors), other)); + if (save) + { + history[other] = color; + } + return *color; + } + + /* *\ brief Channels split. + *\ return each channel. + */ + cv::Mat channel(cv::Mat m, int i) + { + cv::Mat dchannels[3]; + split(m, dchannels); + return dchannels[i]; + } + + /* *\ brief To Gray. + */ + cv::Mat toGray(IO io, CAM method = BRADFORD, bool save = true) + { + XYZ xyz(io); + return channel(this->to(xyz, method, save).colors, 1); + } - class Color + /* *\ brief To Luminant. + */ + cv::Mat toLuminant(IO io, CAM method = BRADFORD, bool save = true) + { + Lab lab(io); + return channel(this->to(lab, method, save).colors, 0); + } + + /* *\ brief Diff without IO. + *\ param other type of Color. + *\ param method type of distance. + *\ return distance between self and other + */ + cv::Mat diff(Color& other, DISTANCE_TYPE method = CIE2000) + { + return diff(other, cs.io, method); + } + + /* *\ brief Diff with IO. + *\ param other type of Color. + *\ param io type of IO. + *\ param method type of distance. + *\ return distance between self and other + */ + cv::Mat diff(Color& other, IO io, DISTANCE_TYPE method = CIE2000) + { + Lab lab(io); + switch (method) { - public: - - /* *\ param grays mask of grayscale color - *\ param colored mask of colored color - *\ param history storage of historical conversion - */ - cv::Mat colors; - const ColorSpace& cs; - cv::Mat grays; - cv::Mat colored; - std::map> history; - - Color(cv::Mat colors_, const ColorSpace& cs_, cv::Mat grays) : colors(colors_), cs(cs_), grays(grays) { - colored = ~grays; - } - Color(cv::Mat colors_, const ColorSpace& cs_) :colors(colors_), cs(cs_) {}; - - virtual ~Color() {}; - - /* *\ brief Change to other color space. - * The conversion process incorporates linear transformations to speed up. - * method is chromatic adapation method. - * when save if True, get data from history first. - *\ param other type of ColorSpace. - *\ return Color. - */ - Color to(const ColorSpace& other, CAM method = BRADFORD, bool save = true) - { - if (history.count(other) == 1) - { - - return *history[other]; - } - if (cs.relate(other)) - { - return Color(cs.relation(other).run(colors), other); - } - Operations ops; - ops.add(cs.to).add(XYZ(cs.io).cam(other.io, method)).add(other.from); - std::shared_ptr color(new Color(ops.run(colors), other)); - if (save) - { - history[other] = color; - } - return *color; - } - - /* *\ brief Channels split. - *\ return each channel. - */ - cv::Mat channel(cv::Mat m, int i) - { - cv::Mat dchannels[3]; - split(m, dchannels); - return dchannels[i]; - } - - /* *\ brief To Gray. - */ - cv::Mat toGray(IO io, CAM method = BRADFORD, bool save = true) - { - XYZ xyz(io); - return channel(this->to(xyz, method, save).colors, 1); - } - - /* *\ brief To Luminant. - */ - cv::Mat toLuminant(IO io, CAM method = BRADFORD, bool save = true) - { - Lab lab(io); - return channel(this->to(lab, method, save).colors, 0); - } - - /* *\ brief Diff without IO. - *\ param other type of Color. - *\ param method type of distance. - *\ return distance between self and other - */ - cv::Mat diff(Color& other, DISTANCE_TYPE method = CIE2000, bool DEBUG = false) - { - return diff(other, cs.io, method, DEBUG); - } - - /* *\ brief Diff with IO. - *\ param other type of Color. - *\ param io type of IO. - *\ param method type of distance. - *\ return distance between self and other - */ - cv::Mat diff(Color& other, IO io, DISTANCE_TYPE method = CIE2000, bool DEBUG = false) - { - Lab lab(io); - switch (method) - { - case cv::ccm::CIE76: - case cv::ccm::CIE94_GRAPHIC_ARTS: - case cv::ccm::CIE94_TEXTILES: - case cv::ccm::CIE2000: - case cv::ccm::CMC_1TO1: - case cv::ccm::CMC_2TO1: - if (DEBUG) { - std::cout <<"to_lab: " <grays = d < JDN; - this->colored = ~grays; - } - - /* *\ brief Operator for mask copy. - */ - Color operator[](cv::Mat mask) - { - std::cout << "[]colors: " << colors << std::endl; - std::cout <<"[]mask: " << mask << std::endl; - std::cout << "[]maskcopyto: " << maskCopyTo(colors, mask) << std::endl; - return Color(maskCopyTo(colors, mask), cs); - } - - - }; - - - /* *\ brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls - * see Miscellaneous.md for details. - */ - const cv::Mat ColorChecker2005_LAB_D50_2 = (cv::Mat_(24, 1) << - cv::Vec3d(37.986, 13.555, 14.059), - cv::Vec3d(65.711, 18.13, 17.81), - cv::Vec3d(49.927, -4.88, -21.925), - cv::Vec3d(43.139, -13.095, 21.905), - cv::Vec3d(55.112, 8.844, -25.399), - cv::Vec3d(70.719, -33.397, -0.199), - cv::Vec3d(62.661, 36.067, 57.096), - cv::Vec3d(40.02, 10.41, -45.964), - cv::Vec3d(51.124, 48.239, 16.248), - cv::Vec3d(30.325, 22.976, -21.587), - cv::Vec3d(72.532, -23.709, 57.255), - cv::Vec3d(71.941, 19.363, 67.857), - cv::Vec3d(28.778, 14.179, -50.297), - cv::Vec3d(55.261, -38.342, 31.37), - cv::Vec3d(42.101, 53.378, 28.19), - cv::Vec3d(81.733, 4.039, 79.819), - cv::Vec3d(51.935, 49.986, -14.574), - cv::Vec3d(51.038, -28.631, -28.638), - cv::Vec3d(96.539, -0.425, 1.186), - cv::Vec3d(81.257, -0.638, -0.335), - cv::Vec3d(66.766, -0.734, -0.504), - cv::Vec3d(50.867, -0.153, -0.27), - cv::Vec3d(35.656, -0.421, -1.231), - cv::Vec3d(20.461, -0.079, -0.973)); - - const cv::Mat ColorChecker2005_LAB_D65_2 = (cv::Mat_(24, 1) << - cv::Vec3d(37.542, 12.018, 13.33), - cv::Vec3d(65.2, 14.821, 17.545), - cv::Vec3d(50.366, -1.573, -21.431), - cv::Vec3d(43.125, -14.63, 22.12), - cv::Vec3d(55.343, 11.449, -25.289), - cv::Vec3d(71.36, -32.718, 1.636), - cv::Vec3d(61.365, 32.885, 55.155), - cv::Vec3d(40.712, 16.908, -45.085), - cv::Vec3d(49.86, 45.934, 13.876), - cv::Vec3d(30.15, 24.915, -22.606), - cv::Vec3d(72.438, -27.464, 58.469), - cv::Vec3d(70.916, 15.583, 66.543), - cv::Vec3d(29.624, 21.425, -49.031), - cv::Vec3d(55.643, -40.76, 33.274), - cv::Vec3d(40.554, 49.972, 25.46), - cv::Vec3d(80.982, -1.037, 80.03), - cv::Vec3d(51.006, 49.876, -16.93), - cv::Vec3d(52.121, -24.61, -26.176), - cv::Vec3d(96.536, -0.694, 1.354), - cv::Vec3d(81.274, -0.61, -0.24), - cv::Vec3d(66.787, -0.647, -0.429), - cv::Vec3d(50.872, -0.059, -0.247), - cv::Vec3d(35.68, -0.22, -1.205), - cv::Vec3d(20.475, 0.049, -0.972)); - - const cv::Mat ColorChecker2005_GRAY_MASK = (cv::Mat_(24, 1) << - 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0); - - const cv::Mat Vinyl_LAB_D50_2 = (Mat_(18, 1) << - Vec3d(1.00000000e+02, 5.20000001e-03, -1.04000000e-02), - Vec3d(7.30833969e+01, -8.19999993e-01, -2.02099991e+00), - Vec3d(6.24930000e+01, 4.25999999e-01, -2.23099995e+00), - Vec3d(5.04640007e+01, 4.46999997e-01, -2.32399988e+00), - Vec3d(3.77970009e+01, 3.59999985e-02, -1.29700005e+00), - Vec3d(0.00000000e+00, 0.00000000e+00, 0.00000000e+00), - Vec3d(5.15880013e+01, 7.35179977e+01, 5.15690002e+01), - Vec3d(9.36989975e+01, -1.57340002e+01, 9.19420013e+01), - Vec3d(6.94079971e+01, -4.65940018e+01, 5.04869995e+01), - Vec3d(6.66100006e+01, -1.36789999e+01, -4.31720009e+01), - Vec3d(1.17110004e+01, 1.69799995e+01, -3.71759987e+01), - Vec3d(5.19739990e+01, 8.19440002e+01, -8.40699959e+00), - Vec3d(4.05489998e+01, 5.04399986e+01, 2.48490009e+01), - Vec3d(6.08160019e+01, 2.60690002e+01, 4.94420013e+01), - Vec3d(5.22529984e+01, -1.99500008e+01, -2.39960003e+01), - Vec3d(5.12859993e+01, 4.84700012e+01, -1.50579996e+01), - Vec3d(6.87070007e+01, 1.22959995e+01, 1.62129993e+01), - Vec3d(6.36839981e+01, 1.02930002e+01, 1.67639999e+01)); - - const cv::Mat Vinyl_GRAY_MASK = (cv::Mat_(18, 1) << - 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1); - - /* *\ brief Macbeth ColorChecker with 2deg D50. - */ - Color Macbeth_D50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2, ColorChecker2005_GRAY_MASK); - - /* *\ brief Macbeth ColorChecker with 2deg D65. - */ - Color Macbeth_D65_2(ColorChecker2005_LAB_D65_2, Lab_D65_2, ColorChecker2005_GRAY_MASK); - - Color Vinyl_D50_2(Vinyl_LAB_D50_2, Lab_D50_2, Vinyl_GRAY_MASK); - - - } // namespace ccm + case cv::ccm::CIE76: + case cv::ccm::CIE94_GRAPHIC_ARTS: + case cv::ccm::CIE94_TEXTILES: + case cv::ccm::CIE2000: + case cv::ccm::CMC_1TO1: + case cv::ccm::CMC_2TO1: + return distance(to(lab).colors, other.to(lab).colors, method); + case cv::ccm::RGB: + return distance(to(*cs.nl).colors, other.to(*cs.nl).colors, method); + case cv::ccm::RGBL: + return distance(to(*cs.l).colors, other.to(*cs.l).colors, method); + default: + throw std::invalid_argument{ "Wrong method!" }; + break; + } + } + + /* *\ brief Calculate gray mask. + */ + void getGray(double JDN = 2.0) + { + if (!grays.empty()) { + return; + } + cv::Mat lab = to(Lab_D65_2).colors; + cv::Mat gray(colors.size(), colors.type()); + int fromto[] = { 0,0, -1,1, -1,2 }; + mixChannels(&lab, 1, &gray, 1, fromto, 3); + cv::Mat d = distance(lab, gray, CIE2000); + this->grays = d < JDN; + this->colored = ~grays; + } + + /* *\ brief Operator for mask copy. + */ + Color operator[](cv::Mat mask) + { + return Color(maskCopyTo(colors, mask), cs); + } + + +}; + + +/* *\ brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls + * see Miscellaneous.md for details. +*/ +const cv::Mat ColorChecker2005_LAB_D50_2 = (cv::Mat_(24, 1) << + cv::Vec3d(37.986, 13.555, 14.059), + cv::Vec3d(65.711, 18.13, 17.81), + cv::Vec3d(49.927, -4.88, -21.925), + cv::Vec3d(43.139, -13.095, 21.905), + cv::Vec3d(55.112, 8.844, -25.399), + cv::Vec3d(70.719, -33.397, -0.199), + cv::Vec3d(62.661, 36.067, 57.096), + cv::Vec3d(40.02, 10.41, -45.964), + cv::Vec3d(51.124, 48.239, 16.248), + cv::Vec3d(30.325, 22.976, -21.587), + cv::Vec3d(72.532, -23.709, 57.255), + cv::Vec3d(71.941, 19.363, 67.857), + cv::Vec3d(28.778, 14.179, -50.297), + cv::Vec3d(55.261, -38.342, 31.37), + cv::Vec3d(42.101, 53.378, 28.19), + cv::Vec3d(81.733, 4.039, 79.819), + cv::Vec3d(51.935, 49.986, -14.574), + cv::Vec3d(51.038, -28.631, -28.638), + cv::Vec3d(96.539, -0.425, 1.186), + cv::Vec3d(81.257, -0.638, -0.335), + cv::Vec3d(66.766, -0.734, -0.504), + cv::Vec3d(50.867, -0.153, -0.27), + cv::Vec3d(35.656, -0.421, -1.231), + cv::Vec3d(20.461, -0.079, -0.973)); + +const cv::Mat ColorChecker2005_LAB_D65_2 = (cv::Mat_(24, 1) << + cv::Vec3d(37.542, 12.018, 13.33), + cv::Vec3d(65.2, 14.821, 17.545), + cv::Vec3d(50.366, -1.573, -21.431), + cv::Vec3d(43.125, -14.63, 22.12), + cv::Vec3d(55.343, 11.449, -25.289), + cv::Vec3d(71.36, -32.718, 1.636), + cv::Vec3d(61.365, 32.885, 55.155), + cv::Vec3d(40.712, 16.908, -45.085), + cv::Vec3d(49.86, 45.934, 13.876), + cv::Vec3d(30.15, 24.915, -22.606), + cv::Vec3d(72.438, -27.464, 58.469), + cv::Vec3d(70.916, 15.583, 66.543), + cv::Vec3d(29.624, 21.425, -49.031), + cv::Vec3d(55.643, -40.76, 33.274), + cv::Vec3d(40.554, 49.972, 25.46), + cv::Vec3d(80.982, -1.037, 80.03), + cv::Vec3d(51.006, 49.876, -16.93), + cv::Vec3d(52.121, -24.61, -26.176), + cv::Vec3d(96.536, -0.694, 1.354), + cv::Vec3d(81.274, -0.61, -0.24), + cv::Vec3d(66.787, -0.647, -0.429), + cv::Vec3d(50.872, -0.059, -0.247), + cv::Vec3d(35.68, -0.22, -1.205), + cv::Vec3d(20.475, 0.049, -0.972)); + +const cv::Mat ColorChecker2005_COLORED_MASK = (cv::Mat_(24, 1) << + 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0); + +const cv::Mat Vinyl_LAB_D50_2 = (Mat_(18, 1) << + Vec3d(1.00000000e+02, 5.20000001e-03, -1.04000000e-02), + Vec3d(7.30833969e+01, -8.19999993e-01, -2.02099991e+00), + Vec3d(6.24930000e+01, 4.25999999e-01, -2.23099995e+00), + Vec3d(5.04640007e+01, 4.46999997e-01, -2.32399988e+00), + Vec3d(3.77970009e+01, 3.59999985e-02, -1.29700005e+00), + Vec3d(0.00000000e+00, 0.00000000e+00, 0.00000000e+00), + Vec3d(5.15880013e+01, 7.35179977e+01, 5.15690002e+01), + Vec3d(9.36989975e+01, -1.57340002e+01, 9.19420013e+01), + Vec3d(6.94079971e+01, -4.65940018e+01, 5.04869995e+01), + Vec3d(6.66100006e+01, -1.36789999e+01, -4.31720009e+01), + Vec3d(1.17110004e+01, 1.69799995e+01, -3.71759987e+01), + Vec3d(5.19739990e+01, 8.19440002e+01, -8.40699959e+00), + Vec3d(4.05489998e+01, 5.04399986e+01, 2.48490009e+01), + Vec3d(6.08160019e+01, 2.60690002e+01, 4.94420013e+01), + Vec3d(5.22529984e+01, -1.99500008e+01, -2.39960003e+01), + Vec3d(5.12859993e+01, 4.84700012e+01, -1.50579996e+01), + Vec3d(6.87070007e+01, 1.22959995e+01, 1.62129993e+01), + Vec3d(6.36839981e+01, 1.02930002e+01, 1.67639999e+01)); + +const cv::Mat Vinyl_COLORED_MASK = (cv::Mat_(18, 1) << + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1); + +/* *\ brief Macbeth ColorChecker with 2deg D50. +*/ +Color Macbeth_D50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2, ColorChecker2005_COLORED_MASK); + +/* *\ brief Macbeth ColorChecker with 2deg D65. +*/ +Color Macbeth_D65_2(ColorChecker2005_LAB_D65_2, Lab_D65_2, ColorChecker2005_COLORED_MASK); + +Color Vinyl_D50_2(Vinyl_LAB_D50_2, Lab_D50_2, Vinyl_COLORED_MASK); + + +} // namespace ccm } // namespace cv -#endif +#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp index cebeb3db60b..d4f6fe9d601 100644 --- a/modules/mcc/include/opencv2/mcc/colorspace.hpp +++ b/modules/mcc/include/opencv2/mcc/colorspace.hpp @@ -38,600 +38,599 @@ namespace cv { - namespace ccm +namespace ccm +{ +/* *\ brief Basic class for ColorSpace. +*/ +class ColorSpace +{ +public: + IO io; + std::string type; + bool linear; + Operations to; + Operations from; + ColorSpace* l; + ColorSpace* nl; + + ColorSpace() {}; + + ColorSpace(IO io_, std::string type_, bool linear_) :io(io_), type(type_), linear(linear_) {}; + + virtual ~ColorSpace() { + l = 0; + nl = 0; + }; - /* *\ brief Basic class for ColorSpace. - */ - class ColorSpace - { - public: - IO io; - std::string type; - bool linear; - Operations to; - Operations from; - ColorSpace* l; - ColorSpace* nl; - - ColorSpace() {}; - - ColorSpace(IO io_, std::string type_, bool linear_) :io(io_), type(type_), linear(linear_) {}; - - virtual ~ColorSpace() - { - l = 0; - nl = 0; - }; - - virtual bool relate(const ColorSpace& other) const - { - return (type == other.type) && (io == other.io); - }; - - virtual Operations relation(const ColorSpace& /*other*/) const - { - return IDENTITY_OPS; - }; - - bool operator<(const ColorSpace& other)const - { - return (io < other.io || (io == other.io && type < other.type) || (io == other.io && type == other.type && linear < other.linear)); - } - }; - - /* *\ brief Base of RGB color space; - * the argument values are from AdobeRGB; - * Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space - */ - class RGBBase_ : public ColorSpace - { - public: - // primaries - double xr; - double yr; - double xg; - double yg; - double xb; - double yb; - MatFunc toL; - MatFunc fromL; - cv::Mat M_to; - cv::Mat M_from; - - using ColorSpace::ColorSpace; - - /* *\ brief There are 3 kinds of relationships for RGB: - * 1. Different types; - no operation - * 1. Same type, same linear; - copy - * 2. Same type, different linear, self is nonlinear; - 2 toL - * 3. Same type, different linear, self is linear - 3 fromL - *\ param other type of ColorSpace. - *\ return Operations. - */ - Operations relation(const ColorSpace& other) const CV_OVERRIDE - { - if (linear == other.linear) - { - return IDENTITY_OPS; - } - if (linear) - { - return Operations({ Operation(fromL) }); - } - return Operations({ Operation(toL) }); - }; - - /* *\ brief Initial operations. - */ - void init() - { - setParameter(); - calLinear(); - calM(); - calOperations(); - } - - /* *\ brief Produce color space instance with linear and non-linear versions. - *\ param rgbl type of RGBBase_. - */ - void bind(RGBBase_& rgbl) - { - init(); - rgbl.init(); - l = &rgbl; - rgbl.l = &rgbl; - nl = this; - rgbl.nl = this; - } - - private: - virtual void setParameter() {}; - - /* *\ brief Calculation of M_RGBL2XYZ_base. - * see ColorSpace.pdf for details. - */ - virtual void calM() - { - cv::Mat XYZr, XYZg, XYZb, XYZ_rgbl, Srgb; - XYZr = cv::Mat(xyY2XYZ({ xr, yr }), true); - XYZg = cv::Mat(xyY2XYZ({ xg, yg }), true); - XYZb = cv::Mat(xyY2XYZ({ xb, yb }), true); - merge(std::vector{ XYZr, XYZg, XYZb }, XYZ_rgbl); - XYZ_rgbl = XYZ_rgbl.reshape(1, XYZ_rgbl.rows); - cv::Mat XYZw = cv::Mat(illuminants.find(io)->second, true); - solve(XYZ_rgbl, XYZw, Srgb); - merge(std::vector{ Srgb.at(0)* XYZr, - Srgb.at(1)* XYZg, - Srgb.at(2)* XYZb }, M_to); - M_to = M_to.reshape(1, M_to.rows); - M_from = M_to.inv(); - }; - - /* *\ brief operations to or from XYZ. - */ - virtual void calOperations() - { - // rgb -> rgbl - toL = [this](cv::Mat rgb)->cv::Mat {return toLFunc(rgb); }; - - // rgbl -> rgb - fromL = [this](cv::Mat rgbl)->cv::Mat {return fromLFunc(rgbl); }; - - if (linear) - { - to = Operations({ Operation(M_to.t()) }); - from = Operations({ Operation(M_from.t()) }); - } - else - { - to = Operations({ Operation(toL), Operation(M_to.t()) }); - from = Operations({ Operation(M_from.t()), Operation(fromL) }); - } - } - - virtual void calLinear() {} - - virtual cv::Mat toLFunc(cv::Mat& /*rgb*/) - { - return cv::Mat(); - }; - - virtual cv::Mat fromLFunc(cv::Mat& /*rgbl*/) - { - return cv::Mat(); - }; - - }; - - /* *\ brief Base of Adobe RGB color space; - */ - class AdobeRGBBase_ : public RGBBase_ - { - public: - using RGBBase_::RGBBase_; - double gamma; - - private: - cv::Mat toLFunc(cv::Mat& rgb) CV_OVERRIDE - { - return gammaCorrection(rgb, gamma); - } - - cv::Mat fromLFunc(cv::Mat& rgbl) CV_OVERRIDE - { - return gammaCorrection(rgbl, 1. / gamma); - } - }; - - /* *\ brief Base of sRGB color space; - */ - class sRGBBase_ : public RGBBase_ - { - public: - using RGBBase_::RGBBase_; - double a; - double gamma; - double alpha; - double beta; - double phi; - double K0; - - private: - /* *\ brief linearization parameters - * see ColorSpace.pdf for details; - */ - virtual void calLinear() CV_OVERRIDE - { - alpha = a + 1; - K0 = a / (gamma - 1); - phi = (pow(alpha, gamma) * pow(gamma - 1, gamma - 1)) / (pow(a, gamma - 1) * pow(gamma, gamma)); - beta = K0 / phi; - } - - /* *\ brief Used by toLFunc. - */ - double toLFuncEW(double& x) - { - if (x > K0) - { - return pow(((x + alpha - 1) / alpha), gamma); - } - else if (x >= -K0) - { - return x / phi; - } - else - { - return -(pow(((-x + alpha - 1) / alpha), gamma)); - } - } - - /* *\ brief Linearization. - * see ColorSpace.pdf for details. - *\ param rgb the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat. - */ - cv::Mat toLFunc(cv::Mat& rgb) CV_OVERRIDE - { - return elementWise(rgb, [this](double a_)->double {return toLFuncEW(a_); }); - } - - /* *\ brief Used by fromLFunc. - */ - double fromLFuncEW(double& x) - { - if (x > beta) - { - return alpha * pow(x, 1 / gamma) - (alpha - 1); - } - else if (x >= -beta) - { - return x * phi; - } - else - { - return -(alpha * pow(-x, 1 / gamma) - (alpha - 1)); - } - } - - /* *\ brief Delinearization. - * see ColorSpace.pdf for details. - *\ param rgbl the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat. - */ - cv::Mat fromLFunc(cv::Mat& rgbl) CV_OVERRIDE - { - return elementWise(rgbl, [this](double a_)->double {return fromLFuncEW(a_); }); - } - }; - - /* *\ brief sRGB color space. - * data from https://en.wikipedia.org/wiki/SRGB. - */ - class sRGB_ :public sRGBBase_ + virtual bool relate(const ColorSpace& other) const + { + return (type == other.type) && (io == other.io); + }; + + virtual Operations relation(const ColorSpace& /*other*/) const + { + return IDENTITY_OPS; + }; + + bool operator<(const ColorSpace& other)const + { + return (io < other.io || (io == other.io && type < other.type) || (io == other.io && type == other.type && linear < other.linear)); + } +}; + +/* *\ brief Base of RGB color space; + * the argument values are from AdobeRGB; + * Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space +*/ +class RGBBase_ : public ColorSpace +{ +public: + // primaries + double xr; + double yr; + double xg; + double yg; + double xb; + double yb; + MatFunc toL; + MatFunc fromL; + cv::Mat M_to; + cv::Mat M_from; + + using ColorSpace::ColorSpace; + + /* *\ brief There are 3 kinds of relationships for RGB: + * 1. Different types; - no operation + * 1. Same type, same linear; - copy + * 2. Same type, different linear, self is nonlinear; - 2 toL + * 3. Same type, different linear, self is linear - 3 fromL + *\ param other type of ColorSpace. + *\ return Operations. + */ + Operations relation(const ColorSpace& other) const CV_OVERRIDE + { + if (linear == other.linear) { - public: - sRGB_(bool linear_) :sRGBBase_(D65_2, "sRGB", linear_) {}; - - private: - void setParameter() CV_OVERRIDE - { - xr = 0.64; - yr = 0.33; - xg = 0.3; - yg = 0.6; - xb = 0.15; - yb = 0.06; - a = 0.055; - gamma = 2.4; - } - }; - - /* *\ brief Adobe RGB color space. - */ - class AdobeRGB_ : public AdobeRGBBase_ + return IDENTITY_OPS; + } + if (linear) { - public: - AdobeRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AdobeRGB", linear_) {}; - - private: - void setParameter() CV_OVERRIDE - { - xr = 0.64; - yr = 0.33; - xg = 0.21; - yg = 0.71; - xb = 0.15; - yb = 0.06; - gamma = 2.2; - } - }; - - /* *\ brief Wide-gamut RGB color space. - * data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. - */ - class WideGamutRGB_ : public AdobeRGBBase_ + return Operations({ Operation(fromL) }); + } + return Operations({ Operation(toL) }); + }; + + /* *\ brief Initial operations. + */ + void init() + { + setParameter(); + calLinear(); + calM(); + calOperations(); + } + + /* *\ brief Produce color space instance with linear and non-linear versions. + *\ param rgbl type of RGBBase_. + */ + void bind(RGBBase_& rgbl) + { + init(); + rgbl.init(); + l = &rgbl; + rgbl.l = &rgbl; + nl = this; + rgbl.nl = this; + } + +private: + virtual void setParameter() {}; + + /* *\ brief Calculation of M_RGBL2XYZ_base. + * see ColorSpace.pdf for details. + */ + virtual void calM() + { + cv::Mat XYZr, XYZg, XYZb, XYZ_rgbl, Srgb; + XYZr = cv::Mat(xyY2XYZ({ xr, yr }), true); + XYZg = cv::Mat(xyY2XYZ({ xg, yg }), true); + XYZb = cv::Mat(xyY2XYZ({ xb, yb }), true); + merge(std::vector{ XYZr, XYZg, XYZb }, XYZ_rgbl); + XYZ_rgbl = XYZ_rgbl.reshape(1, XYZ_rgbl.rows); + cv::Mat XYZw = cv::Mat(illuminants.find(io)->second, true); + solve(XYZ_rgbl, XYZw, Srgb); + merge(std::vector{ Srgb.at(0)* XYZr, + Srgb.at(1)* XYZg, + Srgb.at(2)* XYZb }, M_to); + M_to = M_to.reshape(1, M_to.rows); + M_from = M_to.inv(); + }; + + /* *\ brief operations to or from XYZ. + */ + virtual void calOperations() + { + // rgb -> rgbl + toL = [this](cv::Mat rgb)->cv::Mat {return toLFunc(rgb); }; + + // rgbl -> rgb + fromL = [this](cv::Mat rgbl)->cv::Mat {return fromLFunc(rgbl); }; + + if (linear) { - public: - WideGamutRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "WideGamutRGB", linear_) {}; - - private: - void setParameter() CV_OVERRIDE - { - xr = 0.7347; - yr = 0.2653; - xg = 0.1152; - yg = 0.8264; - xb = 0.1566; - yb = 0.0177; - gamma = 2.2; - } - }; - - /* *\ brief ProPhoto RGB color space. - * data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. - */ - class ProPhotoRGB_ : public AdobeRGBBase_ + to = Operations({ Operation(M_to.t()) }); + from = Operations({ Operation(M_from.t()) }); + } + else { - public: - ProPhotoRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "ProPhotoRGB", linear_) {}; - - private: - void setParameter() CV_OVERRIDE - { - xr = 0.734699; - yr = 0.265301; - xg = 0.159597; - yg = 0.840403; - xb = 0.036598; - yb = 0.000105; - gamma = 1.8; - } - }; - - /* *\ brief DCI-P3 RGB color space. - * data from https://en.wikipedia.org/wiki/DCI-P3. - */ - class DCI_P3_RGB_ : public AdobeRGBBase_ + to = Operations({ Operation(toL), Operation(M_to.t()) }); + from = Operations({ Operation(M_from.t()), Operation(fromL) }); + } + } + + virtual void calLinear() {} + + virtual cv::Mat toLFunc(cv::Mat& /*rgb*/) + { + return cv::Mat(); + }; + + virtual cv::Mat fromLFunc(cv::Mat& /*rgbl*/) + { + return cv::Mat(); + }; + +}; + +/* *\ brief Base of Adobe RGB color space; +*/ +class AdobeRGBBase_ : public RGBBase_ +{ +public: + using RGBBase_::RGBBase_; + double gamma; + +private: + cv::Mat toLFunc(cv::Mat& rgb) CV_OVERRIDE + { + return gammaCorrection(rgb, gamma); + } + + cv::Mat fromLFunc(cv::Mat& rgbl) CV_OVERRIDE + { + return gammaCorrection(rgbl, 1. / gamma); + } +}; + +/* *\ brief Base of sRGB color space; +*/ +class sRGBBase_ : public RGBBase_ +{ +public: + using RGBBase_::RGBBase_; + double a; + double gamma; + double alpha; + double beta; + double phi; + double K0; + +private: + /* *\ brief linearization parameters + * see ColorSpace.pdf for details; + */ + virtual void calLinear() CV_OVERRIDE + { + alpha = a + 1; + K0 = a / (gamma - 1); + phi = (pow(alpha, gamma) * pow(gamma - 1, gamma - 1)) / (pow(a, gamma - 1) * pow(gamma, gamma)); + beta = K0 / phi; + } + + /* *\ brief Used by toLFunc. + */ + double toLFuncEW(double& x) + { + if (x > K0) { - public: - DCI_P3_RGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "DCI_P3_RGB", linear_) {}; - - private: - void setParameter() CV_OVERRIDE - { - xr = 0.68; - yr = 0.32; - xg = 0.265; - yg = 0.69; - xb = 0.15; - yb = 0.06; - gamma = 2.2; - } - }; - - /* *\ brief Apple RGB color space. - * data from http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. - */ - class AppleRGB_ : public AdobeRGBBase_ + return pow(((x + alpha - 1) / alpha), gamma); + } + else if (x >= -K0) { - public: - AppleRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AppleRGB", linear_) {}; - - private: - void setParameter() CV_OVERRIDE - { - xr = 0.625; - yr = 0.34; - xg = 0.28; - yg = 0.595; - xb = 0.155; - yb = 0.07; - gamma = 1.8; - } - }; - - /* *\ brief REC_709 RGB color space. - * data from https://en.wikipedia.org/wiki/Rec._709. - */ - class REC_709_RGB_ : public sRGBBase_ + return x / phi; + } + else { - public: - REC_709_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_709_RGB", linear_) {}; - - private: - void setParameter() CV_OVERRIDE - { - xr = 0.64; - yr = 0.33; - xg = 0.3; - yg = 0.6; - xb = 0.15; - yb = 0.06; - a = 0.099; - gamma = 1 / 0.45; - } - }; - - /* *\ brief REC_2020 RGB color space. - * data from https://en.wikipedia.org/wiki/Rec._2020. - */ - class REC_2020_RGB_ : public sRGBBase_ + return -(pow(((-x + alpha - 1) / alpha), gamma)); + } + } + + /* *\ brief Linearization. + * see ColorSpace.pdf for details. + *\ param rgb the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat. + */ + cv::Mat toLFunc(cv::Mat& rgb) CV_OVERRIDE + { + return elementWise(rgb, [this](double a_)->double {return toLFuncEW(a_); }); + } + + /* *\ brief Used by fromLFunc. + */ + double fromLFuncEW(double& x) + { + if (x > beta) { - public: - REC_2020_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_2020_RGB", linear_) {}; - - private: - void setParameter() CV_OVERRIDE - { - xr = 0.708; - yr = 0.292; - xg = 0.17; - yg = 0.797; - xb = 0.131; - yb = 0.046; - a = 0.09929682680944; - gamma = 1 / 0.45; - } - }; - - - sRGB_ sRGB(false), sRGBL(true); - AdobeRGB_ AdobeRGB(false), AdobeRGBL(true); - WideGamutRGB_ WideGamutRGB(false), WideGamutRGBL(true); - ProPhotoRGB_ ProPhotoRGB(false), ProPhotoRGBL(true); - DCI_P3_RGB_ DCI_P3_RGB(false), DCI_P3_RGBL(true); - AppleRGB_ AppleRGB(false), AppleRGBL(true); - REC_709_RGB_ REC_709_RGB(false), REC_709_RGBL(true); - REC_2020_RGB_ REC_2020_RGB(false), REC_2020_RGBL(true); - - /* *\ brief Bind RGB with RGBL. - */ - class ColorSpaceInitial + return alpha * pow(x, 1 / gamma) - (alpha - 1); + } + else if (x >= -beta) { - public: - ColorSpaceInitial() - { - sRGB.bind(sRGBL); - AdobeRGB.bind(AdobeRGBL); - WideGamutRGB.bind(WideGamutRGBL); - ProPhotoRGB.bind(ProPhotoRGBL); - DCI_P3_RGB.bind(DCI_P3_RGBL); - AppleRGB.bind(AppleRGBL); - REC_709_RGB.bind(REC_709_RGBL); - REC_2020_RGB.bind(REC_2020_RGBL); - - } - }; - - ColorSpaceInitial color_space_initial; - - - /* *\ brief Enum of the possible types of CAMs. - */ - enum CAM + return x * phi; + } + else { - IDENTITY, - VON_KRIES, - BRADFORD - }; - - static std::map , cv::Mat > cams; - const static cv::Mat Von_Kries = (cv::Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); - const static cv::Mat Bradford = (cv::Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); - const static std::map > MAs = { - {IDENTITY , { cv::Mat::eye(cv::Size(3,3),CV_64FC1) , cv::Mat::eye(cv::Size(3,3),CV_64FC1)} }, - {VON_KRIES, { Von_Kries ,Von_Kries.inv() }}, - {BRADFORD, { Bradford ,Bradford.inv() }} - }; - - /* *\ brief XYZ color space. - * Chromatic adaption matrices. - */ - class XYZ :public ColorSpace + return -(alpha * pow(-x, 1 / gamma) - (alpha - 1)); + } + } + + /* *\ brief Delinearization. + * see ColorSpace.pdf for details. + *\ param rgbl the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat. + */ + cv::Mat fromLFunc(cv::Mat& rgbl) CV_OVERRIDE + { + return elementWise(rgbl, [this](double a_)->double {return fromLFuncEW(a_); }); + } +}; + +/* *\ brief sRGB color space. + * data from https://en.wikipedia.org/wiki/SRGB. +*/ +class sRGB_ :public sRGBBase_ +{ +public: + sRGB_(bool linear_) :sRGBBase_(D65_2, "sRGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE + { + xr = 0.64; + yr = 0.33; + xg = 0.3; + yg = 0.6; + xb = 0.15; + yb = 0.06; + a = 0.055; + gamma = 2.4; + } +}; + +/* *\ brief Adobe RGB color space. +*/ +class AdobeRGB_ : public AdobeRGBBase_ +{ +public: + AdobeRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AdobeRGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE + { + xr = 0.64; + yr = 0.33; + xg = 0.21; + yg = 0.71; + xb = 0.15; + yb = 0.06; + gamma = 2.2; + } +}; + +/* *\ brief Wide-gamut RGB color space. + * data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. +*/ +class WideGamutRGB_ : public AdobeRGBBase_ +{ +public: + WideGamutRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "WideGamutRGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE + { + xr = 0.7347; + yr = 0.2653; + xg = 0.1152; + yg = 0.8264; + xb = 0.1566; + yb = 0.0177; + gamma = 2.2; + } +}; + +/* *\ brief ProPhoto RGB color space. + * data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. +*/ +class ProPhotoRGB_ : public AdobeRGBBase_ +{ +public: + ProPhotoRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "ProPhotoRGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE + { + xr = 0.734699; + yr = 0.265301; + xg = 0.159597; + yg = 0.840403; + xb = 0.036598; + yb = 0.000105; + gamma = 1.8; + } +}; + +/* *\ brief DCI-P3 RGB color space. + * data from https://en.wikipedia.org/wiki/DCI-P3. +*/ +class DCI_P3_RGB_ : public AdobeRGBBase_ +{ +public: + DCI_P3_RGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "DCI_P3_RGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE + { + xr = 0.68; + yr = 0.32; + xg = 0.265; + yg = 0.69; + xb = 0.15; + yb = 0.06; + gamma = 2.2; + } +}; + +/* *\ brief Apple RGB color space. + * data from http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. +*/ +class AppleRGB_ : public AdobeRGBBase_ +{ +public: + AppleRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AppleRGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE + { + xr = 0.625; + yr = 0.34; + xg = 0.28; + yg = 0.595; + xb = 0.155; + yb = 0.07; + gamma = 1.8; + } +}; + +/* *\ brief REC_709 RGB color space. + * data from https://en.wikipedia.org/wiki/Rec._709. +*/ +class REC_709_RGB_ : public sRGBBase_ +{ +public: + REC_709_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_709_RGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE + { + xr = 0.64; + yr = 0.33; + xg = 0.3; + yg = 0.6; + xb = 0.15; + yb = 0.06; + a = 0.099; + gamma = 1 / 0.45; + } +}; + +/* *\ brief REC_2020 RGB color space. + * data from https://en.wikipedia.org/wiki/Rec._2020. +*/ +class REC_2020_RGB_ : public sRGBBase_ +{ +public: + REC_2020_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_2020_RGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE + { + xr = 0.708; + yr = 0.292; + xg = 0.17; + yg = 0.797; + xb = 0.131; + yb = 0.046; + a = 0.09929682680944; + gamma = 1 / 0.45; + } +}; + + +sRGB_ sRGB(false), sRGBL(true); +AdobeRGB_ AdobeRGB(false), AdobeRGBL(true); +WideGamutRGB_ WideGamutRGB(false), WideGamutRGBL(true); +ProPhotoRGB_ ProPhotoRGB(false), ProPhotoRGBL(true); +DCI_P3_RGB_ DCI_P3_RGB(false), DCI_P3_RGBL(true); +AppleRGB_ AppleRGB(false), AppleRGBL(true); +REC_709_RGB_ REC_709_RGB(false), REC_709_RGBL(true); +REC_2020_RGB_ REC_2020_RGB(false), REC_2020_RGBL(true); + +/* *\ brief Bind RGB with RGBL. +*/ +class ColorSpaceInitial +{ +public: + ColorSpaceInitial() + { + sRGB.bind(sRGBL); + AdobeRGB.bind(AdobeRGBL); + WideGamutRGB.bind(WideGamutRGBL); + ProPhotoRGB.bind(ProPhotoRGBL); + DCI_P3_RGB.bind(DCI_P3_RGBL); + AppleRGB.bind(AppleRGBL); + REC_709_RGB.bind(REC_709_RGBL); + REC_2020_RGB.bind(REC_2020_RGBL); + + } +}; + +ColorSpaceInitial color_space_initial; + + +/* *\ brief Enum of the possible types of CAMs. +*/ +enum CAM +{ + IDENTITY, + VON_KRIES, + BRADFORD +}; + +static std::map , cv::Mat > cams; +const static cv::Mat Von_Kries = (cv::Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); +const static cv::Mat Bradford = (cv::Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); +const static std::map > MAs = { + {IDENTITY , { cv::Mat::eye(cv::Size(3,3),CV_64FC1) , cv::Mat::eye(cv::Size(3,3),CV_64FC1)} }, + {VON_KRIES, { Von_Kries ,Von_Kries.inv() }}, + {BRADFORD, { Bradford ,Bradford.inv() }} +}; + +/* *\ brief XYZ color space. + * Chromatic adaption matrices. +*/ +class XYZ :public ColorSpace +{ +public: + XYZ(IO io_) : ColorSpace(io_, "XYZ", true) {}; + Operations cam(IO dio, CAM method = BRADFORD) + { + return (io == dio) ? Operations() : Operations({ Operation(cam_(io, dio, method).t()) }); + } + +private: + /* *\ brief Get cam. + *\ param sio the input IO of src. + *\ param dio the input IO of dst. + *\ param method type of CAM. + *\ return the output array, type of cv::Mat. + */ + cv::Mat cam_(IO sio, IO dio, CAM method = BRADFORD) const + { + if (sio == dio) { - public: - XYZ(IO io_) : ColorSpace(io_, "XYZ", true) {}; - Operations cam(IO dio, CAM method = BRADFORD) - { - return (io == dio) ? Operations() : Operations({ Operation(cam_(io, dio, method).t()) }); - } - - private: - /* *\ brief Get cam. - *\ param sio the input IO of src. - *\ param dio the input IO of dst. - *\ param method type of CAM. - *\ return the output array, type of cv::Mat. - */ - cv::Mat cam_(IO sio, IO dio, CAM method = BRADFORD) const - { - if (sio == dio) - { - return cv::Mat::eye(cv::Size(3, 3), CV_64FC1); - } - if (cams.count(std::make_tuple(dio, sio, method)) == 1) - { - return cams[std::make_tuple(dio, sio, method)]; - } - - // Function from http ://www.brucelindbloom.com/index.html?ColorCheckerRGB.html. - cv::Mat XYZws = cv::Mat(illuminants.find(dio)->second); - cv::Mat XYZWd = cv::Mat(illuminants.find(sio)->second); - cv::Mat MA = MAs.at(method)[0]; - cv::Mat MA_inv = MAs.at(method)[1]; - cv::Mat M = MA_inv * cv::Mat::diag((MA * XYZws) / (MA * XYZWd)) * MA; - cams[std::make_tuple(dio, sio, method)] = M; - cams[std::make_tuple(sio, dio, method)] = M.inv(); - return M; - } - }; - - /* *\ brief Define XYZ_D65_2 and XYZ_D50_2. - */ - const XYZ XYZ_D65_2(D65_2); - const XYZ XYZ_D50_2(D50_2); - - - /* *\ brief Lab color space. - */ - class Lab :public ColorSpace + return cv::Mat::eye(cv::Size(3, 3), CV_64FC1); + } + if (cams.count(std::make_tuple(dio, sio, method)) == 1) { - public: - Lab(IO io_) : ColorSpace(io_, "Lab", true) - { - to = { Operation([this](cv::Mat src)->cv::Mat {return tosrc(src); }) }; - from = { Operation([this](cv::Mat src)->cv::Mat {return fromsrc(src); }) }; - } - - private: - static constexpr double delta = (6. / 29.); - static constexpr double m = 1. / (3. * delta * delta); - static constexpr double t0 = delta * delta * delta; - static constexpr double c = 4. / 29.; - - cv::Vec3d fromxyz(cv::Vec3d& xyz) - { - double x = xyz[0] / illuminants.find(io)->second[0], y = xyz[1] / illuminants.find(io)->second[1], z = xyz[2] / illuminants.find(io)->second[2]; - auto f = [](double t)->double { return t > t0 ? std::cbrt(t) : (m * t + c); }; - double fx = f(x), fy = f(y), fz = f(z); - return { 116. * fy - 16. ,500 * (fx - fy),200 * (fy - fz) }; - } - - /* *\ brief Calculate From. - *\ param src the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat - */ - cv::Mat fromsrc(cv::Mat& src) - { - return channelWise(src, [this](cv::Vec3d a)->cv::Vec3d {return fromxyz(a); }); - } - - cv::Vec3d tolab(cv::Vec3d& lab) - { - auto f_inv = [](double t)->double {return t > delta ? pow(t, 3.0) : (t - c) / m; }; - double L = (lab[0] + 16.) / 116., a = lab[1] / 500., b = lab[2] / 200.; - return { illuminants.find(io)->second[0] * f_inv(L + a),illuminants.find(io)->second[1] * f_inv(L),illuminants.find(io)->second[2] * f_inv(L - b) }; - } - - /* *\ brief Calculate To. - *\ param src the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat - */ - cv::Mat tosrc(cv::Mat& src) - { - return channelWise(src, [this](cv::Vec3d a)->cv::Vec3d {return tolab(a); }); - } - }; - - /* *\ brief Define Lab_D65_2 and Lab_D50_2. - */ - const Lab Lab_D65_2(D65_2); - const Lab Lab_D50_2(D50_2); - - } // namespace ccm + return cams[std::make_tuple(dio, sio, method)]; + } + + // Function from http ://www.brucelindbloom.com/index.html?ColorCheckerRGB.html. + cv::Mat XYZws = cv::Mat(illuminants.find(dio)->second); + cv::Mat XYZWd = cv::Mat(illuminants.find(sio)->second); + cv::Mat MA = MAs.at(method)[0]; + cv::Mat MA_inv = MAs.at(method)[1]; + cv::Mat M = MA_inv * cv::Mat::diag((MA * XYZws) / (MA * XYZWd)) * MA; + cams[std::make_tuple(dio, sio, method)] = M; + cams[std::make_tuple(sio, dio, method)] = M.inv(); + return M; + } +}; + +/* *\ brief Define XYZ_D65_2 and XYZ_D50_2. +*/ +const XYZ XYZ_D65_2(D65_2); +const XYZ XYZ_D50_2(D50_2); + + +/* *\ brief Lab color space. +*/ +class Lab :public ColorSpace +{ +public: + Lab(IO io_) : ColorSpace(io_, "Lab", true) + { + to = { Operation([this](cv::Mat src)->cv::Mat {return tosrc(src); }) }; + from = { Operation([this](cv::Mat src)->cv::Mat {return fromsrc(src); }) }; + } + +private: + static constexpr double delta = (6. / 29.); + static constexpr double m = 1. / (3. * delta * delta); + static constexpr double t0 = delta * delta * delta; + static constexpr double c = 4. / 29.; + + cv::Vec3d fromxyz(cv::Vec3d& xyz) + { + double x = xyz[0] / illuminants.find(io)->second[0], y = xyz[1] / illuminants.find(io)->second[1], z = xyz[2] / illuminants.find(io)->second[2]; + auto f = [](double t)->double { return t > t0 ? std::cbrt(t) : (m * t + c); }; + double fx = f(x), fy = f(y), fz = f(z); + return { 116. * fy - 16. ,500 * (fx - fy),200 * (fy - fz) }; + } + + /* *\ brief Calculate From. + *\ param src the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat + */ + cv::Mat fromsrc(cv::Mat& src) + { + return channelWise(src, [this](cv::Vec3d a)->cv::Vec3d {return fromxyz(a); }); + } + + cv::Vec3d tolab(cv::Vec3d& lab) + { + auto f_inv = [](double t)->double {return t > delta ? pow(t, 3.0) : (t - c) / m; }; + double L = (lab[0] + 16.) / 116., a = lab[1] / 500., b = lab[2] / 200.; + return { illuminants.find(io)->second[0] * f_inv(L + a),illuminants.find(io)->second[1] * f_inv(L),illuminants.find(io)->second[2] * f_inv(L - b) }; + } + + /* *\ brief Calculate To. + *\ param src the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat + */ + cv::Mat tosrc(cv::Mat& src) + { + return channelWise(src, [this](cv::Vec3d a)->cv::Vec3d {return tolab(a); }); + } +}; + +/* *\ brief Define Lab_D65_2 and Lab_D50_2. +*/ +const Lab Lab_D65_2(D65_2); +const Lab Lab_D50_2(D50_2); + +} // namespace ccm } // namespace cv -#endif +#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/distance.hpp b/modules/mcc/include/opencv2/mcc/distance.hpp index ea2257c0eac..d4ac7f83cfe 100644 --- a/modules/mcc/include/opencv2/mcc/distance.hpp +++ b/modules/mcc/include/opencv2/mcc/distance.hpp @@ -31,245 +31,269 @@ #include "opencv2/mcc/utils.hpp" -namespace cv { - namespace ccm { +namespace cv +{ +namespace ccm +{ - /* *\brief Enum of possibale functions to calculate the distance between - * colors.see https://en.wikipedia.org/wiki/Color_difference for details;*/ - enum DISTANCE_TYPE { - CIE76, - CIE94_GRAPHIC_ARTS, - CIE94_TEXTILES, - CIE2000, - CMC_1TO1, - CMC_2TO1, - RGB, - RGBL - }; +/* *\brief Enum of possibale functions to calculate the distance between + * colors.see https://en.wikipedia.org/wiki/Color_difference for details;*/ +enum DISTANCE_TYPE +{ + CIE76, + CIE94_GRAPHIC_ARTS, + CIE94_TEXTILES, + CIE2000, + CMC_1TO1, + CMC_2TO1, + RGB, + RGBL +}; - double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2); - double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH = 1.0, - double kC = 1.0, double kL = 1.0, double k1 = 0.045, - double k2 = 0.015); - double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2); - double toRad(double degree); - double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2); - double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1.0, - double kC = 1.0, double kH = 1.0); - double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2); - double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1, double kC = 1); - double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2); - double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2); - cv::Mat distance(cv::Mat src, cv::Mat ref, DISTANCE_TYPE distance_type); +double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH = 1.0, + double kC = 1.0, double kL = 1.0, double k1 = 0.045, + double k2 = 0.015); +double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2); +double toRad(double degree); +double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1.0, + double kC = 1.0, double kH = 1.0); +double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1, double kC = 1); +double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2); +cv::Mat distance(cv::Mat src, cv::Mat ref, DISTANCE_TYPE distance_type); - /* *\ brief distance between two points in formula CIE76 - *\ param lab1 a 3D vector - *\ param lab2 a 3D vector - *\ return distance between lab1 and lab2 - */ - double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2) { return norm(lab1 - lab2); }; +/* *\ brief distance between two points in formula CIE76 + *\ param lab1 a 3D vector + *\ param lab2 a 3D vector + *\ return distance between lab1 and lab2 +*/ +double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2) { return norm(lab1 - lab2); }; - /* *\ brief distance between two points in formula CIE94 - *\ param lab1 a 3D vector - *\ param lab2 a 3D vector - *\ param kH Hue scale - *\ param kC Chroma scale - *\ param kL Lightness scale - *\ param k1 first scale parameter - *\ param k2 second scale parameter - *\ return distance between lab1 and lab2 - */ - double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH, - double kC, double kL, double k1, double k2) { - double dl = lab1[0] - lab2[0]; - double c1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); - double c2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); - double dc = c1 - c2; - double da = lab1[1] - lab2[1]; - double db = lab1[2] - lab2[2]; - double dh = pow(da, 2) + pow(db, 2) - pow(dc, 2); - double sc = 1.0 + k1 * c1; - double sh = 1.0 + k2 * c1; - double sl = 1.0; - double res = - pow(dl / (kL * sl), 2) + pow(dc / (kC * sc), 2) + dh / pow(kH * sh, 2); +/* *\ brief distance between two points in formula CIE94 + *\ param lab1 a 3D vector + *\ param lab2 a 3D vector + *\ param kH Hue scale + *\ param kC Chroma scale + *\ param kL Lightness scale + *\ param k1 first scale parameter + *\ param k2 second scale parameter + *\ return distance between lab1 and lab2 +*/ +double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH, + double kC, double kL, double k1, double k2) +{ + double dl = lab1[0] - lab2[0]; + double c1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); + double c2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); + double dc = c1 - c2; + double da = lab1[1] - lab2[1]; + double db = lab1[2] - lab2[2]; + double dh = pow(da, 2) + pow(db, 2) - pow(dc, 2); + double sc = 1.0 + k1 * c1; + double sh = 1.0 + k2 * c1; + double sl = 1.0; + double res = + pow(dl / (kL * sl), 2) + pow(dc / (kC * sc), 2) + dh / pow(kH * sh, 2); - return res > 0 ? sqrt(res) : 0; - } + return res > 0 ? sqrt(res) : 0; +} - double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2) { - return deltaCIE94(lab1, lab2); - } +double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2) +{ + return deltaCIE94(lab1, lab2); +} - double toRad(double degree) { return degree / 180 * CV_PI; }; +double toRad(double degree) { return degree / 180 * CV_PI; }; - double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2) { - return deltaCIE94(lab1, lab2, 1.0, 1.0, 2.0, 0.048, 0.014); - } +double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2) +{ + return deltaCIE94(lab1, lab2, 1.0, 1.0, 2.0, 0.048, 0.014); +} - /* *\ brief distance between two points in formula CIE2000 - *\ param lab1 a 3D vector - *\ param lab2 a 3D vector - *\ param kL Lightness scale - *\ param kC Chroma scale - *\ param kH Hue scale - *\ return distance between lab1 and lab2 - */ - double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL, - double kC, double kH) { - double delta_L_apo = lab2[0] - lab1[0]; - double l_bar_apo = (lab1[0] + lab2[0]) / 2.0; - double C1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); - double C2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); - double C_bar = (C1 + C2) / 2.0; - double G = sqrt(pow(C_bar, 7) / (pow(C_bar, 7) + pow(25, 7))); - double a1_apo = lab1[1] + lab1[1] / 2.0 * (1.0 - G); - double a2_apo = lab2[1] + lab2[1] / 2.0 * (1.0 - G); - double C1_apo = sqrt(pow(a1_apo, 2) + pow(lab1[2], 2)); - double C2_apo = sqrt(pow(a2_apo, 2) + pow(lab2[2], 2)); - double C_bar_apo = (C1_apo + C2_apo) / 2.0; - double delta_C_apo = C2_apo - C1_apo; +/* *\ brief distance between two points in formula CIE2000 + *\ param lab1 a 3D vector + *\ param lab2 a 3D vector + *\ param kL Lightness scale + *\ param kC Chroma scale + *\ param kH Hue scale + *\ return distance between lab1 and lab2 +*/ +double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL, + double kC, double kH) +{ + double delta_L_apo = lab2[0] - lab1[0]; + double l_bar_apo = (lab1[0] + lab2[0]) / 2.0; + double C1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); + double C2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); + double C_bar = (C1 + C2) / 2.0; + double G = sqrt(pow(C_bar, 7) / (pow(C_bar, 7) + pow(25, 7))); + double a1_apo = lab1[1] + lab1[1] / 2.0 * (1.0 - G); + double a2_apo = lab2[1] + lab2[1] / 2.0 * (1.0 - G); + double C1_apo = sqrt(pow(a1_apo, 2) + pow(lab1[2], 2)); + double C2_apo = sqrt(pow(a2_apo, 2) + pow(lab2[2], 2)); + double C_bar_apo = (C1_apo + C2_apo) / 2.0; + double delta_C_apo = C2_apo - C1_apo; - double h1_apo; - if (C1_apo == 0) { - h1_apo = 0.0; - } - else { - h1_apo = atan2(lab1[2], a1_apo); - if (h1_apo < 0.0) h1_apo += 2. * CV_PI; - } + double h1_apo; + if (C1_apo == 0) + { + h1_apo = 0.0; + } + else + { + h1_apo = atan2(lab1[2], a1_apo); + if (h1_apo < 0.0) h1_apo += 2. * CV_PI; + } - double h2_apo; - if (C2_apo == 0) { - h2_apo = 0.0; - } - else { - h2_apo = atan2(lab2[2], a2_apo); - if (h2_apo < 0.0) h2_apo += 2. * CV_PI; - } + double h2_apo; + if (C2_apo == 0) + { + h2_apo = 0.0; + } + else + { + h2_apo = atan2(lab2[2], a2_apo); + if (h2_apo < 0.0) h2_apo += 2. * CV_PI; + } - double delta_h_apo; - if (abs(h2_apo - h1_apo) <= CV_PI) { - delta_h_apo = h2_apo - h1_apo; - } - else if (h2_apo <= h1_apo) { - delta_h_apo = h2_apo - h1_apo + 2. * CV_PI; - } - else { - delta_h_apo = h2_apo - h1_apo - 2. * CV_PI; - } + double delta_h_apo; + if (abs(h2_apo - h1_apo) <= CV_PI) + { + delta_h_apo = h2_apo - h1_apo; + } + else if (h2_apo <= h1_apo) + { + delta_h_apo = h2_apo - h1_apo + 2. * CV_PI; + } + else + { + delta_h_apo = h2_apo - h1_apo - 2. * CV_PI; + } - double H_bar_apo; - if (C1_apo == 0 || C2_apo == 0) { - H_bar_apo = h1_apo + h2_apo; - } - else if (abs(h1_apo - h2_apo) <= CV_PI) { - H_bar_apo = (h1_apo + h2_apo) / 2.0; - } - else if (h1_apo + h2_apo < 2. * CV_PI) { - H_bar_apo = (h1_apo + h2_apo + 2. * CV_PI) / 2.0; - } - else { - H_bar_apo = (h1_apo + h2_apo - 2. * CV_PI) / 2.0; - } + double H_bar_apo; + if (C1_apo == 0 || C2_apo == 0) + { + H_bar_apo = h1_apo + h2_apo; + } + else if (abs(h1_apo - h2_apo) <= CV_PI) + { + H_bar_apo = (h1_apo + h2_apo) / 2.0; + } + else if (h1_apo + h2_apo < 2. * CV_PI) + { + H_bar_apo = (h1_apo + h2_apo + 2. * CV_PI) / 2.0; + } + else + { + H_bar_apo = (h1_apo + h2_apo - 2. * CV_PI) / 2.0; + } - double delta_H_apo = 2.0 * sqrt(C1_apo * C2_apo) * sin(delta_h_apo / 2.0); - double T = 1.0 - 0.17 * cos(H_bar_apo - toRad(30.)) + - 0.24 * cos(2.0 * H_bar_apo) + - 0.32 * cos(3.0 * H_bar_apo + toRad(6.0)) - - 0.2 * cos(4.0 * H_bar_apo - toRad(63.0)); - double sC = 1.0 + 0.045 * C_bar_apo; - double sH = 1.0 + 0.015 * C_bar_apo * T; - double sL = 1.0 + ((0.015 * pow(l_bar_apo - 50.0, 2.0)) / - sqrt(20.0 + pow(l_bar_apo - 50.0, 2.0))); - double RT = -2.0 * G * - sin(toRad(60.0) * - exp(-pow((H_bar_apo - toRad(275.0)) / toRad(25.0), 2.0))); - double res = - (pow(delta_L_apo / (kL * sL), 2.0) + pow(delta_C_apo / (kC * sC), 2.0) + - pow(delta_H_apo / (kH * sH), 2.0) + - RT * (delta_C_apo / (kC * sC)) * (delta_H_apo / (kH * sH))); - return res > 0 ? sqrt(res) : 0; - } + double delta_H_apo = 2.0 * sqrt(C1_apo * C2_apo) * sin(delta_h_apo / 2.0); + double T = 1.0 - 0.17 * cos(H_bar_apo - toRad(30.)) + + 0.24 * cos(2.0 * H_bar_apo) + + 0.32 * cos(3.0 * H_bar_apo + toRad(6.0)) - + 0.2 * cos(4.0 * H_bar_apo - toRad(63.0)); + double sC = 1.0 + 0.045 * C_bar_apo; + double sH = 1.0 + 0.015 * C_bar_apo * T; + double sL = 1.0 + ((0.015 * pow(l_bar_apo - 50.0, 2.0)) / + sqrt(20.0 + pow(l_bar_apo - 50.0, 2.0))); + double RT = -2.0 * G * + sin(toRad(60.0) * + exp(-pow((H_bar_apo - toRad(275.0)) / toRad(25.0), 2.0))); + double res = + (pow(delta_L_apo / (kL * sL), 2.0) + pow(delta_C_apo / (kC * sC), 2.0) + + pow(delta_H_apo / (kH * sH), 2.0) + + RT * (delta_C_apo / (kC * sC)) * (delta_H_apo / (kH * sH))); + return res > 0 ? sqrt(res) : 0; +} - double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2) { - return deltaCIEDE2000_(lab1, lab2); - } +double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2) +{ + return deltaCIEDE2000_(lab1, lab2); +} - /* *\ brief distance between two points in formula CMC - *\ param lab1 a 3D vector - *\ param lab2 a 3D vector - *\ param kL Lightness scale - *\ param kC Chroma scale - *\ return distance between lab1 and lab2 - */ - double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL, double kC) { - double dL = lab2[0] - lab1[0]; - double da = lab2[1] - lab1[1]; - double db = lab2[2] - lab1[2]; - double C1 = sqrt(pow(lab1[1], 2.0) + pow(lab1[2], 2.0)); - double C2 = sqrt(pow(lab2[1], 2.0) + pow(lab2[2], 2.0)); - double dC = C2 - C1; - double dH = sqrt(pow(da, 2) + pow(db, 2) - pow(dC, 2)); +/* *\ brief distance between two points in formula CMC + *\ param lab1 a 3D vector + *\ param lab2 a 3D vector + *\ param kL Lightness scale + *\ param kC Chroma scale + *\ return distance between lab1 and lab2 +*/ +double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL, double kC) +{ + double dL = lab2[0] - lab1[0]; + double da = lab2[1] - lab1[1]; + double db = lab2[2] - lab1[2]; + double C1 = sqrt(pow(lab1[1], 2.0) + pow(lab1[2], 2.0)); + double C2 = sqrt(pow(lab2[1], 2.0) + pow(lab2[2], 2.0)); + double dC = C2 - C1; + double dH = sqrt(pow(da, 2) + pow(db, 2) - pow(dC, 2)); - double H1; - if (C1 == 0.) { - H1 = 0.0; - } - else { - H1 = atan2(lab1[2], lab1[1]); - if (H1 < 0.0) H1 += 2. * CV_PI; - } + double H1; + if (C1 == 0.) + { + H1 = 0.0; + } + else + { + H1 = atan2(lab1[2], lab1[1]); + if (H1 < 0.0) H1 += 2. * CV_PI; + } - double F = pow(C1, 2) / sqrt(pow(C1, 4) + 1900); - double T = (H1 > toRad(164) && H1 <= toRad(345)) - ? 0.56 + abs(0.2 * cos(H1 + toRad(168))) - : 0.36 + abs(0.4 * cos(H1 + toRad(35))); - ; - double sL = - lab1[0] < 16. ? 0.511 : (0.040975 * lab1[0]) / (1.0 + 0.01765 * lab1[0]); - ; - double sC = (0.0638 * C1) / (1.0 + 0.0131 * C1) + 0.638; - double sH = sC * (F * T + 1.0 - F); + double F = pow(C1, 2) / sqrt(pow(C1, 4) + 1900); + double T = (H1 > toRad(164) && H1 <= toRad(345)) + ? 0.56 + abs(0.2 * cos(H1 + toRad(168))) + : 0.36 + abs(0.4 * cos(H1 + toRad(35))); + double sL = + lab1[0] < 16. ? 0.511 : (0.040975 * lab1[0]) / (1.0 + 0.01765 * lab1[0]); + double sC = (0.0638 * C1) / (1.0 + 0.0131 * C1) + 0.638; + double sH = sC * (F * T + 1.0 - F); - return sqrt(pow(dL / (kL * sL), 2.0) + pow(dC / (kC * sC), 2.0) + - pow(dH / sH, 2.0)); - } + return sqrt(pow(dL / (kL * sL), 2.0) + pow(dC / (kC * sC), 2.0) + + pow(dH / sH, 2.0)); +} - double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2) { - return deltaCMC(lab1, lab2); - } +double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2) +{ + return deltaCMC(lab1, lab2); +} - double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2) { - return deltaCMC(lab1, lab2, 2, 1); - } +double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2) +{ + return deltaCMC(lab1, lab2, 2, 1); +} - cv::Mat distance(cv::Mat src, cv::Mat ref, DISTANCE_TYPE distance_type) { - switch (distance_type) { - case cv::ccm::CIE76: - return distanceWise(src, ref, deltaCIE76); - case cv::ccm::CIE94_GRAPHIC_ARTS: - return distanceWise(src, ref, deltaCIE94GraphicArts); - case cv::ccm::CIE94_TEXTILES: - return distanceWise(src, ref, deltaCIE94Textiles); - case cv::ccm::CIE2000: - return distanceWise(src, ref, deltaCIEDE2000); - case cv::ccm::CMC_1TO1: - return distanceWise(src, ref, deltaCMC1To1); - case cv::ccm::CMC_2TO1: - return distanceWise(src, ref, deltaCMC2To1); - case cv::ccm::RGB: - return distanceWise(src, ref, deltaCIE76); - case cv::ccm::RGBL: - return distanceWise(src, ref, deltaCIE76); - default: - throw std::invalid_argument{ "Wrong distance_type!" }; - break; - } - }; +cv::Mat distance(cv::Mat src, cv::Mat ref, DISTANCE_TYPE distance_type) +{ + switch (distance_type) + { + case cv::ccm::CIE76: + return distanceWise(src, ref, deltaCIE76); + case cv::ccm::CIE94_GRAPHIC_ARTS: + return distanceWise(src, ref, deltaCIE94GraphicArts); + case cv::ccm::CIE94_TEXTILES: + return distanceWise(src, ref, deltaCIE94Textiles); + case cv::ccm::CIE2000: + return distanceWise(src, ref, deltaCIEDE2000); + case cv::ccm::CMC_1TO1: + return distanceWise(src, ref, deltaCMC1To1); + case cv::ccm::CMC_2TO1: + return distanceWise(src, ref, deltaCMC2To1); + case cv::ccm::RGB: + return distanceWise(src, ref, deltaCIE76); + case cv::ccm::RGBL: + return distanceWise(src, ref, deltaCIE76); + default: + throw std::invalid_argument{ "Wrong distance_type!" }; + break; + } +}; - } // namespace ccm +} // namespace ccm } // namespace cv #endif diff --git a/modules/mcc/include/opencv2/mcc/io.hpp b/modules/mcc/include/opencv2/mcc/io.hpp index fe7736bb01f..a1be185dfe9 100644 --- a/modules/mcc/include/opencv2/mcc/io.hpp +++ b/modules/mcc/include/opencv2/mcc/io.hpp @@ -36,75 +36,75 @@ namespace cv { - namespace ccm +namespace ccm +{ + +/* *\ brief Io is the meaning of illuminant and observer. See notes of ccm.hpp + * for supported list for illuminant and observer*/ +class IO +{ +public: + + std::string illuminant; + std::string observer; + + IO() {}; + + IO(std::string illuminant_, std::string observer_) :illuminant(illuminant_), observer(observer_) {}; + + virtual ~IO() {}; + + bool operator<(const IO& other) const + { + return (illuminant < other.illuminant || ((illuminant == other.illuminant) && (observer < other.observer))); + } + + bool operator==(const IO& other) const + { + return illuminant == other.illuminant && observer == other.observer; + }; +}; + +const IO A_2("A", "2"), A_10("A", "10"), + D50_2("D50", "2"), D50_10("D50", "10"), + D55_2("D55", "2"), D55_10("D55", "10"), + D65_2("D65", "2"), D65_10("D65", "10"), + D75_2("D75", "2"), D75_10("D75", "10"), + E_2("E", "2"), E_10("E", "10"); + +// data from https://en.wikipedia.org/wiki/Standard_illuminant. +const static std::map> illuminants_xy = +{ + {A_2, { 0.44757, 0.40745 }}, {A_10, { 0.45117, 0.40594 }}, + {D50_2, { 0.34567, 0.35850 }}, {D50_10, { 0.34773, 0.35952 }}, + {D55_2, { 0.33242, 0.34743 }}, {D55_10, { 0.33411, 0.34877 }}, + {D65_2, { 0.31271, 0.32902 }}, {D65_10, { 0.31382, 0.33100 }}, + {D75_2, { 0.29902, 0.31485 }}, {D75_10, { 0.45117, 0.40594 }}, + {E_2, { 1 / 3, 1 / 3 }}, {E_10, { 1 / 3, 1 / 3 }}, +}; + +std::vector xyY2XYZ(const std::vector& xyY); +std::vector xyY2XYZ(const std::vector& xyY) +{ + double Y = xyY.size() >= 3 ? xyY[2] : 1; + return { Y * xyY[0] / xyY[1], Y, Y / xyY[1] * (1 - xyY[0] - xyY[1]) }; +} + +/* *\ brief function to get illuminants*/ +static std::map > getIlluminant(); +static std::map > getIlluminant() +{ + std::map > illuminants; + for (auto it = illuminants_xy.begin(); it != illuminants_xy.end(); ++it) { + illuminants[it->first] = xyY2XYZ(it->second); + } + return illuminants; +} - /* *\ brief Io is the meaning of illuminant and observer. See notes of ccm.hpp - * for supported list for illuminant and observer*/ - class IO - { - public: - - std::string illuminant; - std::string observer; - - IO() {}; - - IO(std::string illuminant_, std::string observer_) :illuminant(illuminant_), observer(observer_) {}; - - virtual ~IO() {}; - - bool operator<(const IO& other) const - { - return (illuminant < other.illuminant || ((illuminant == other.illuminant) && (observer < other.observer))); - } - - bool operator==(const IO& other) const - { - return illuminant == other.illuminant && observer == other.observer; - }; - }; - - const IO A_2("A", "2"), A_10("A", "10"), - D50_2("D50", "2"), D50_10("D50", "10"), - D55_2("D55", "2"), D55_10("D55", "10"), - D65_2("D65", "2"), D65_10("D65", "10"), - D75_2("D75", "2"), D75_10("D75", "10"), - E_2("E", "2"), E_10("E", "10"); - - // data from https://en.wikipedia.org/wiki/Standard_illuminant. - const static std::map> illuminants_xy = - { - {A_2, { 0.44757, 0.40745 }}, {A_10, { 0.45117, 0.40594 }}, - {D50_2, { 0.34567, 0.35850 }}, {D50_10, { 0.34773, 0.35952 }}, - {D55_2, { 0.33242, 0.34743 }}, {D55_10, { 0.33411, 0.34877 }}, - {D65_2, { 0.31271, 0.32902 }}, {D65_10, { 0.31382, 0.33100 }}, - {D75_2, { 0.29902, 0.31485 }}, {D75_10, { 0.45117, 0.40594 }}, - {E_2, { 1 / 3, 1 / 3 }}, {E_10, { 1 / 3, 1 / 3 }}, - }; - - std::vector xyY2XYZ(const std::vector& xyY); - std::vector xyY2XYZ(const std::vector& xyY) - { - double Y = xyY.size() >= 3 ? xyY[2] : 1; - return { Y * xyY[0] / xyY[1], Y, Y / xyY[1] * (1 - xyY[0] - xyY[1]) }; - } - - /* *\ brief function to get illuminants*/ - static std::map > getIlluminant(); - static std::map > getIlluminant() - { - std::map > illuminants; - for (auto it = illuminants_xy.begin(); it != illuminants_xy.end(); ++it) - { - illuminants[it->first] = xyY2XYZ(it->second); - } - return illuminants; - } - - const std::map > illuminants = getIlluminant(); - } // namespace ccm +const std::map > illuminants = getIlluminant(); +} // namespace ccm } // namespace cv -#endif +#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/linearize.hpp b/modules/mcc/include/opencv2/mcc/linearize.hpp index ecc6227a87b..ad337ac76dc 100644 --- a/modules/mcc/include/opencv2/mcc/linearize.hpp +++ b/modules/mcc/include/opencv2/mcc/linearize.hpp @@ -33,267 +33,267 @@ namespace cv { - namespace ccm - { - - /* *\ brief Enum of the possible types of linearization. - */ - enum LINEAR_TYPE - { - IDENTITY_, - GAMMA, - COLORPOLYFIT, - COLORLOGPOLYFIT, - GRAYPOLYFIT, - GRAYLOGPOLYFIT - }; - - /* *\ brief Polyfit model. - */ - class Polyfit - { - public: - int deg; - cv::Mat p; - - Polyfit() {}; +namespace ccm +{ - /* *\ brief Polyfit method. - */ - Polyfit(cv::Mat s, cv::Mat d, int deg_) :deg(deg_) - { - int npoints = s.checkVector(1); - cv::Mat_ srcX(s), srcY(d); - cv::Mat_ m = cv::Mat_::ones(npoints, deg + 1); - for (int y = 0; y < npoints; ++y) - { - for (int x = 1; x < m.cols; ++x) - { - m.at(y, x) = srcX.at(y) * m.at(y, x - 1); - } - } - cv::solve(m, srcY, p, DECOMP_SVD); - } +/* *\ brief Enum of the possible types of linearization. +*/ +enum LINEAR_TYPE +{ + IDENTITY_, + GAMMA, + COLORPOLYFIT, + COLORLOGPOLYFIT, + GRAYPOLYFIT, + GRAYLOGPOLYFIT +}; + +/* *\ brief Polyfit model. +*/ +class Polyfit +{ +public: + int deg; + cv::Mat p; - virtual ~Polyfit() {}; - cv::Mat operator()(const cv::Mat& inp) - { - return elementWise(inp, [this](double a)->double {return fromEW(a); }); - }; + Polyfit() {}; - private: - double fromEW(double x) - { - double res = 0; - for (int d = 0; d <= deg; ++d) - { - res += pow(x, d) * p.at(d, 0); - } - return res; - }; - }; - - /* *\ brief Logpolyfit model. - */ - class LogPolyfit + /* *\ brief Polyfit method. + */ + Polyfit(cv::Mat s, cv::Mat d, int deg_) :deg(deg_) + { + int npoints = s.checkVector(1); + cv::Mat_ srcX(s), srcY(d); + cv::Mat_ m = cv::Mat_::ones(npoints, deg + 1); + for (int y = 0; y < npoints; ++y) { - public: - int deg; - Polyfit p; - - LogPolyfit() {}; - - /* *\ brief Logpolyfit method. - */ - LogPolyfit(cv::Mat s, cv::Mat d, int deg_) :deg(deg_) + for (int x = 1; x < m.cols; ++x) { - cv::Mat mask_ = (s > 0) & (d > 0); - cv::Mat src_, dst_, s_, d_; - src_ = maskCopyTo(s, mask_); - dst_ = maskCopyTo(d, mask_); - log(src_, s_); - log(dst_, d_); - p = Polyfit(s_, d_, deg); + m.at(y, x) = srcX.at(y) * m.at(y, x - 1); } + } + cv::solve(m, srcY, p, DECOMP_SVD); + } - virtual ~LogPolyfit() {}; + virtual ~Polyfit() {}; + cv::Mat operator()(const cv::Mat& inp) + { + return elementWise(inp, [this](double a)->double {return fromEW(a); }); + }; - cv::Mat operator()(const cv::Mat& inp) - { - cv::Mat mask_ = inp >= 0; - cv::Mat y, y_, res; - log(inp, y); - y = p(y); - exp(y, y_); - y_.copyTo(res, mask_); - return res; - }; - }; - - /* *\ brief Linearization base. - */ - class Linear +private: + double fromEW(double x) + { + double res = 0; + for (int d = 0; d <= deg; ++d) { - public: - Linear() {}; + res += pow(x, d) * p.at(d, 0); + } + return res; + }; +}; + +/* *\ brief Logpolyfit model. +*/ +class LogPolyfit +{ +public: + int deg; + Polyfit p; - virtual ~Linear() {}; + LogPolyfit() {}; - /* *\ brief Inference. - *\ param inp the input array, type of cv::Mat. - */ - virtual cv::Mat linearize(cv::Mat inp) - { - return inp; - }; - - /* *\brief Evaluate linearization model. - */ - virtual void value(void) {}; - }; + /* *\ brief Logpolyfit method. + */ + LogPolyfit(cv::Mat s, cv::Mat d, int deg_) :deg(deg_) + { + cv::Mat mask_ = (s > 0) & (d > 0); + cv::Mat src_, dst_, s_, d_; + src_ = maskCopyTo(s, mask_); + dst_ = maskCopyTo(d, mask_); + log(src_, s_); + log(dst_, d_); + p = Polyfit(s_, d_, deg); + } + + virtual ~LogPolyfit() {}; + + cv::Mat operator()(const cv::Mat& inp) + { + cv::Mat mask_ = inp >= 0; + cv::Mat y, y_, res; + log(inp, y); + y = p(y); + exp(y, y_); + y_.copyTo(res, mask_); + return res; + }; +}; + +/* *\ brief Linearization base. +*/ +class Linear +{ +public: + Linear() {}; + virtual ~Linear() {}; - /* *\ brief Linearization identity. - * make no change. - */ - class LinearIdentity : public Linear {}; + /* *\ brief Inference. + *\ param inp the input array, type of cv::Mat. + */ + virtual cv::Mat linearize(cv::Mat inp) + { + return inp; + }; - /* *\ brief Linearization gamma correction. - */ - class LinearGamma : public Linear - { - public: - double gamma; + /* *\brief Evaluate linearization model. + */ + virtual void value(void) {}; +}; - LinearGamma(double gamma_) :gamma(gamma_) {}; - cv::Mat linearize(cv::Mat inp) CV_OVERRIDE - { - return gammaCorrection(inp, gamma); - }; - }; - - /* *\ brief Linearization. - * Grayscale polynomial fitting. - */ - template - class LinearGray :public Linear - { - public: - int deg; - T p; +/* *\ brief Linearization identity. + * make no change. +*/ +class LinearIdentity : public Linear {}; - LinearGray(int deg_, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg_) - { - dst.getGray(); - Mat lear_gray_mask = mask & dst.grays; +/* *\ brief Linearization gamma correction. +*/ +class LinearGamma : public Linear +{ +public: + double gamma; - // the grayscale function is approximate for src is in relative color space. - src = rgb2gray(maskCopyTo(src, lear_gray_mask)); - cv::Mat dst_ = maskCopyTo(dst.toGray(cs.io), lear_gray_mask); - calc(src, dst_); - } + LinearGamma(double gamma_) :gamma(gamma_) {}; - /* *\ brief monotonically increase is not guaranteed. - *\ param src the input array, type of cv::Mat. - *\ param dst the input array, type of cv::Mat. - */ - void calc(const cv::Mat& src, const cv::Mat& dst) - { - p = T(src, dst, deg); - }; + cv::Mat linearize(cv::Mat inp) CV_OVERRIDE + { + return gammaCorrection(inp, gamma); + }; +}; + +/* *\ brief Linearization. + * Grayscale polynomial fitting. +*/ +template +class LinearGray :public Linear +{ +public: + int deg; + T p; - cv::Mat linearize(cv::Mat inp) CV_OVERRIDE - { - return p(inp); - }; - }; - - /* *\ brief Linearization. - * Fitting channels respectively. - */ - template - class LinearColor :public Linear - { - public: - int deg; - T pr; - T pg; - T pb; + LinearGray(int deg_, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg_) + { + dst.getGray(); + Mat lear_gray_mask = mask & dst.grays; + + // the grayscale function is approximate for src is in relative color space. + src = rgb2gray(maskCopyTo(src, lear_gray_mask)); + cv::Mat dst_ = maskCopyTo(dst.toGray(cs.io), lear_gray_mask); + calc(src, dst_); + } + + /* *\ brief monotonically increase is not guaranteed. + *\ param src the input array, type of cv::Mat. + *\ param dst the input array, type of cv::Mat. + */ + void calc(const cv::Mat& src, const cv::Mat& dst) + { + p = T(src, dst, deg); + }; - LinearColor(int deg_, cv::Mat src_, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg_) - { - Mat src = maskCopyTo(src_, mask); - cv::Mat dst_ = maskCopyTo(dst.to(*cs.l).colors, mask); - calc(src, dst_); - } + cv::Mat linearize(cv::Mat inp) CV_OVERRIDE + { + return p(inp); + }; +}; + +/* *\ brief Linearization. + * Fitting channels respectively. +*/ +template +class LinearColor :public Linear +{ +public: + int deg; + T pr; + T pg; + T pb; - void calc(const cv::Mat& src, const cv::Mat& dst) - { - cv::Mat schannels[3]; - cv::Mat dchannels[3]; - split(src, schannels); - split(dst, dchannels); - pr = T(schannels[0], dchannels[0], deg); - pg = T(schannels[1], dchannels[1], deg); - pb = T(schannels[2], dchannels[2], deg); - }; - - cv::Mat linearize(cv::Mat inp) CV_OVERRIDE - { - cv::Mat channels[3]; - split(inp, channels); - std::vector channel; - cv::Mat res; - merge(std::vector{ pr(channels[0]), pg(channels[1]), pb(channels[2]) }, res); - return res; - }; - }; - - - /* *\ brief Get linearization method. - * used in ccm model. - *\ param gamma used in LinearGamma. - *\ param deg degrees. - *\ param src the input array, type of cv::Mat. - *\ param dst the input array, type of cv::Mat. - *\ param mask the input array, type of cv::Mat. - *\ param cs type of RGBBase_. - *\ param linear_type type of linear. - */ - std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type); - std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type) - { - std::shared_ptr p = std::make_shared(); - switch (linear_type) - { - case cv::ccm::IDENTITY_: - p.reset(new LinearIdentity()); - break; - case cv::ccm::GAMMA: - p.reset(new LinearGamma(gamma)); - break; - case cv::ccm::COLORPOLYFIT: - p.reset(new LinearColor(deg, src, dst, mask, cs)); - break; - case cv::ccm::COLORLOGPOLYFIT: - p.reset(new LinearColor(deg, src, dst, mask, cs)); - break; - case cv::ccm::GRAYPOLYFIT: - p.reset(new LinearGray(deg, src, dst, mask, cs)); - break; - case cv::ccm::GRAYLOGPOLYFIT: - p.reset(new LinearGray(deg, src, dst, mask, cs)); - break; - default: - throw std::invalid_argument{ "Wrong linear_type!" }; - break; - } - return p; - }; + LinearColor(int deg_, cv::Mat src_, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg_) + { + Mat src = maskCopyTo(src_, mask); + cv::Mat dst_ = maskCopyTo(dst.to(*cs.l).colors, mask); + calc(src, dst_); + } - } // namespace ccm + void calc(const cv::Mat& src, const cv::Mat& dst) + { + cv::Mat schannels[3]; + cv::Mat dchannels[3]; + split(src, schannels); + split(dst, dchannels); + pr = T(schannels[0], dchannels[0], deg); + pg = T(schannels[1], dchannels[1], deg); + pb = T(schannels[2], dchannels[2], deg); + }; + + cv::Mat linearize(cv::Mat inp) CV_OVERRIDE + { + cv::Mat channels[3]; + split(inp, channels); + std::vector channel; + cv::Mat res; + merge(std::vector{ pr(channels[0]), pg(channels[1]), pb(channels[2]) }, res); + return res; + }; +}; + + +/* *\ brief Get linearization method. + * used in ccm model. + *\ param gamma used in LinearGamma. + *\ param deg degrees. + *\ param src the input array, type of cv::Mat. + *\ param dst the input array, type of cv::Mat. + *\ param mask the input array, type of cv::Mat. + *\ param cs type of RGBBase_. + *\ param linear_type type of linear. +*/ +std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type); +std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type) +{ + std::shared_ptr p = std::make_shared(); + switch (linear_type) + { + case cv::ccm::IDENTITY_: + p.reset(new LinearIdentity()); + break; + case cv::ccm::GAMMA: + p.reset(new LinearGamma(gamma)); + break; + case cv::ccm::COLORPOLYFIT: + p.reset(new LinearColor(deg, src, dst, mask, cs)); + break; + case cv::ccm::COLORLOGPOLYFIT: + p.reset(new LinearColor(deg, src, dst, mask, cs)); + break; + case cv::ccm::GRAYPOLYFIT: + p.reset(new LinearGray(deg, src, dst, mask, cs)); + break; + case cv::ccm::GRAYLOGPOLYFIT: + p.reset(new LinearGray(deg, src, dst, mask, cs)); + break; + default: + throw std::invalid_argument{ "Wrong linear_type!" }; + break; + } + return p; +}; + +} // namespace ccm } // namespace cv -#endif#pragma once +#endif diff --git a/modules/mcc/include/opencv2/mcc/operations.hpp b/modules/mcc/include/opencv2/mcc/operations.hpp index 783eb64eb1b..2369f11b29d 100644 --- a/modules/mcc/include/opencv2/mcc/operations.hpp +++ b/modules/mcc/include/opencv2/mcc/operations.hpp @@ -35,107 +35,111 @@ namespace cv { - namespace ccm - { +namespace ccm +{ - typedef std::function MatFunc; +typedef std::function MatFunc; - /* *\ brief Operation class contains some operarions used for color space - * conversion containing linear transformation and non-linear transformation - */ - class Operation - { - public: - bool linear; - cv::Mat M; - MatFunc f; +/* *\ brief Operation class contains some operarions used for color space + * conversion containing linear transformation and non-linear transformation + */ +class Operation +{ +public: + bool linear; + cv::Mat M; + MatFunc f; - Operation() : linear(true), M(cv::Mat()) {}; + Operation() : linear(true), M(cv::Mat()) {}; - Operation(cv::Mat M_) :linear(true), M(M_) {}; + Operation(cv::Mat M_) :linear(true), M(M_) {}; - Operation(MatFunc f_) : linear(false), f(f_) {}; + Operation(MatFunc f_) : linear(false), f(f_) {}; - virtual ~Operation() {}; - /* *\ brief operator function will run operation*/ - cv::Mat operator()(cv::Mat& abc) - { - if (!linear) - { - return f(abc); - } - if (M.empty()) - { - return abc; - } - return multiple(abc, M); - }; - - /* *\ brief add function will conbine this operation - * with other linear transformation operation*/ - void add(const Operation& other) - { - if (M.empty()) - { - M = other.M.clone(); - } - else - { - M = M * other.M; - } - }; - - void clear() - { - M = cv::Mat(); - }; - }; + virtual ~Operation() {}; + /* *\ brief operator function will run operation + */ + cv::Mat operator()(cv::Mat& abc) + { + if (!linear) + { + return f(abc); + } + if (M.empty()) + { + return abc; + } + return multiple(abc, M); + }; + + /* *\ brief add function will conbine this operation + * with other linear transformation operation + */ + void add(const Operation& other) + { + if (M.empty()) + { + M = other.M.clone(); + } + else + { + M = M * other.M; + } + }; - const Operation IDENTITY_OP([](cv::Mat x) {return x; }); + void clear() + { + M = cv::Mat(); + }; +}; - class Operations - { - public: - std::vector ops; +const Operation IDENTITY_OP([](cv::Mat x) {return x; }); - Operations() :ops{ } {}; +class Operations +{ +public: + std::vector ops; - Operations(std::initializer_list op) :ops{ op } {}; + Operations() :ops{ } {}; - virtual ~Operations() {}; + Operations(std::initializer_list op) :ops{ op } {}; - /* *\ brief add function will conbine this operation with other transformation operations*/ - Operations& add(const Operations& other) - { - ops.insert(ops.end(), other.ops.begin(), other.ops.end()); - return *this; - }; + virtual ~Operations() {}; + + /* *\ brief add function will conbine this operation with other transformation operations + */ + Operations& add(const Operations& other) + { + ops.insert(ops.end(), other.ops.begin(), other.ops.end()); + return *this; + }; - /* *\ brief run operations to make color conversion*/ - cv::Mat run(cv::Mat abc) + /* *\ brief run operations to make color conversion + */ + cv::Mat run(cv::Mat abc) + { + Operation hd; + for (auto& op : ops) + { + if (op.linear) + { + hd.add(op); + } + else { - Operation hd; - for (auto& op : ops) - { - if (op.linear) - { - hd.add(op); - } - else - { - abc = hd(abc); - hd.clear(); - abc = op(abc); - } - } abc = hd(abc); - return abc; - }; - }; - - const Operations IDENTITY_OPS{ IDENTITY_OP }; - - } // namespace ccm + hd.clear(); + abc = op(abc); + } + } + abc = hd(abc); + return abc; + }; +}; + +const Operations IDENTITY_OPS{ IDENTITY_OP }; + +} // namespace ccm } // namespace cv diff --git a/modules/mcc/include/opencv2/mcc/utils.hpp b/modules/mcc/include/opencv2/mcc/utils.hpp index 4ef01d50896..7c63dae9030 100644 --- a/modules/mcc/include/opencv2/mcc/utils.hpp +++ b/modules/mcc/include/opencv2/mcc/utils.hpp @@ -37,200 +37,200 @@ namespace cv { - namespace ccm - { +namespace ccm +{ - double gammaCorrection_(const double& element, const double& gamma); - cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma); - cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask); - cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm); - cv::Mat saturate(cv::Mat& src, const double& low, const double& up); - cv::Mat rgb2gray(cv::Mat rgb); - - /* *\ brief function for elementWise operation - *\ param src the input array, type of cv::Mat - *\ lambda a for operation - */ - template - cv::Mat elementWise(const cv::Mat& src, F&& lambda) +double gammaCorrection_(const double& element, const double& gamma); +cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma); +cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask); +cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm); +cv::Mat saturate(cv::Mat& src, const double& low, const double& up); +cv::Mat rgb2gray(cv::Mat rgb); + +/* *\ brief function for elementWise operation + *\ param src the input array, type of cv::Mat + *\ lambda a for operation +*/ +template +cv::Mat elementWise(const cv::Mat& src, F&& lambda) +{ + cv::Mat dst = src.clone(); + const int channel = src.channels(); + switch (channel) + { + case 1: + { + cv::MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) { - cv::Mat dst = src.clone(); - const int channel = src.channels(); - switch (channel) - { - case 1: - { - cv::MatIterator_ it, end; - for (it = dst.begin(), end = dst.end(); it != end; ++it) - { - (*it) = lambda((*it)); - } - break; - } - case 3: - { - cv::MatIterator_ it, end; - for (it = dst.begin(), end = dst.end(); it != end; ++it) - { - for (int j = 0; j < 3; j++) - { - (*it)[j] = lambda((*it)[j]); - } - } - break; - } - default: - throw std::invalid_argument{ "Wrong channel!" }; - break; - } - return dst; + (*it) = lambda((*it)); } - - /* *\ brief function for channel operation - *\ param src the input array, type of cv::Mat - *\ lambda the function for operation - */ - template - cv::Mat channelWise(const cv::Mat& src, F&& lambda) + break; + } + case 3: + { + cv::MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) { - cv::Mat dst = src.clone(); - cv::MatIterator_ it, end; - for (it = dst.begin(), end = dst.end(); it != end; ++it) + for (int j = 0; j < 3; j++) { - *it = lambda(*it); + (*it)[j] = lambda((*it)[j]); } - return dst; } + break; + } + default: + throw std::invalid_argument{ "Wrong channel!" }; + break; + } + return dst; +} + +/* *\ brief function for channel operation + *\ param src the input array, type of cv::Mat + *\ lambda the function for operation +*/ +template +cv::Mat channelWise(const cv::Mat& src, F&& lambda) +{ + cv::Mat dst = src.clone(); + cv::MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) + { + *it = lambda(*it); + } + return dst; +} + +/* *\ brief function for distance operation. + *\ param src the input array, type of cv::Mat. + *\ param ref another input array, type of cv::Mat. + *\ param lambda the computing method for distance . +*/ +template +cv::Mat distanceWise(cv::Mat& src, cv::Mat& ref, F&& lambda) +{ + cv::Mat dst = cv::Mat(src.size(), CV_64FC1); + cv::MatIterator_ it_src = src.begin(), end_src = src.end(), + it_ref = ref.begin(); + cv::MatIterator_ it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_ref, ++it_dst) + { + *it_dst = lambda(*it_src, *it_ref); + } + return dst; +} + - /* *\ brief function for distance operation. - *\ param src the input array, type of cv::Mat. - *\ param ref another input array, type of cv::Mat. - *\ param lambda the computing method for distance . - */ - template - cv::Mat distanceWise(cv::Mat& src, cv::Mat& ref, F&& lambda) +double gammaCorrection_(const double& element, const double& gamma) +{ + return (element >= 0 ? pow(element, gamma) : -pow((-element), gamma)); +} + +/* *\ brief gamma correction, see ColorSpace.pdf for details. + *\ param src the input array, type of cv::Mat. + *\ param gamma a constant for gamma correction. +*/ +cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma) +{ + return elementWise(src, [gamma](double element)->double {return gammaCorrection_(element, gamma); }); +} + +/* *\ brief maskCopyTo a function to delete unsatisfied elementwise. + *\ param src the input array, type of cv::Mat. + *\ param mask operation mask that used to choose satisfided elementwise. +*/ +cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) +{ + cv::Mat dst(countNonZero(mask), 1, src.type()); + const int channel = src.channels(); + auto it_mask = mask.begin(); + switch (channel) + { + case 1: + { + auto it_src = src.begin(), end_src = src.end(); + auto it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_mask) { - cv::Mat dst = cv::Mat(src.size(), CV_64FC1); - cv::MatIterator_ it_src = src.begin(), end_src = src.end(), - it_ref = ref.begin(); - cv::MatIterator_ it_dst = dst.begin(); - for (; it_src != end_src; ++it_src, ++it_ref, ++it_dst) + if (*it_mask) { - *it_dst = lambda(*it_src, *it_ref); + (*it_dst) = (*it_src); + ++it_dst; } - return dst; } - - - double gammaCorrection_(const double& element, const double& gamma) - { - return (element >= 0 ? pow(element, gamma) : -pow((-element), gamma)); - } - - /* *\ brief gamma correction ,see ColorSpace.pdf for details. - *\ param src the input array,type of cv::Mat. - *\ param gamma a constant for gamma correction. - */ - cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma) - { - return elementWise(src, [gamma](double element)->double {return gammaCorrection_(element, gamma); }); - } - - /* *\ brief maskCopyTo a function to delete unsatisfied elementwise. - *\ param src the input array, type of cv::Mat. - *\ param mask operation mask that used to choose satisfided elementwise. - */ - cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) + break; + } + case 3: + { + auto it_src = src.begin(), end_src = src.end(); + auto it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_mask) { - cv::Mat dst(countNonZero(mask), 1, src.type()); - const int channel = src.channels(); - auto it_mask = mask.begin(); - switch (channel) + if (*it_mask) { - case 1: - { - auto it_src = src.begin(), end_src = src.end(); - auto it_dst = dst.begin(); - for (; it_src != end_src; ++it_src, ++it_mask) - { - if (*it_mask) - { - (*it_dst) = (*it_src); - ++it_dst; - } - } - break; - } - case 3: - { - auto it_src = src.begin(), end_src = src.end(); - auto it_dst = dst.begin(); - for (; it_src != end_src; ++it_src, ++it_mask) - { - if (*it_mask) - { - (*it_dst) = (*it_src); - ++it_dst; - } - } - break; - } - default: - throw std::invalid_argument{ "Wrong channel!" }; - break; + (*it_dst) = (*it_src); + ++it_dst; } - return dst; } - - /* *\ brief multiple the function used to compute an array with n channels mulipied by ccm. - *\ param src the input array, type of cv::Mat. - *\ param ccm the ccm matrix to make color correction. - */ - cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm) - { - cv::Mat tmp = xyz.reshape(1, xyz.rows * xyz.cols); - cv::Mat res = tmp * ccm; - res = res.reshape(res.cols, xyz.rows); - return res; - } - - /* *\ brief multiple the function used to get the mask of saturated colors, - colors between low and up will be choosed. - *\ param src the input array, type of cv::Mat. - *\ param low the threshold to choose saturated colors - *\ param up the threshold to choose saturated colors - */ - cv::Mat saturate(cv::Mat& src, const double& low, const double& up) + break; + } + default: + throw std::invalid_argument{ "Wrong channel!" }; + break; + } + return dst; +} + +/* *\ brief multiple the function used to compute an array with n channels mulipied by ccm. + *\ param src the input array, type of cv::Mat. + *\ param ccm the ccm matrix to make color correction. +*/ +cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm) +{ + cv::Mat tmp = xyz.reshape(1, xyz.rows * xyz.cols); + cv::Mat res = tmp * ccm; + res = res.reshape(res.cols, xyz.rows); + return res; +} + +/* *\ brief multiple the function used to get the mask of saturated colors, + colors between low and up will be choosed. + *\ param src the input array, type of cv::Mat. + *\ param low the threshold to choose saturated colors + *\ param up the threshold to choose saturated colors +*/ +cv::Mat saturate(cv::Mat& src, const double& low, const double& up) +{ + cv::Mat dst = cv::Mat::ones(src.size(), CV_8UC1); + cv::MatIterator_ it_src = src.begin(), end_src = src.end(); + cv::MatIterator_ it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_dst) + { + for (int i = 0; i < 3; ++i) { - cv::Mat dst = cv::Mat::ones(src.size(), CV_8UC1); - cv::MatIterator_ it_src = src.begin(), end_src = src.end(); - cv::MatIterator_ it_dst = dst.begin(); - for (; it_src != end_src; ++it_src, ++it_dst) + if ((*it_src)[i] > up || (*it_src)[i] < low) { - for (int i = 0; i < 3; ++i) - { - if ((*it_src)[i] > up || (*it_src)[i] < low) - { - *it_dst = 0; - break; - } - } + *it_dst = 0; + break; } - return dst; } + } + return dst; +} - const static cv::Mat m_gray = (cv::Mat_(3, 1) << 0.2126, 0.7152, 0.0722); - - /* *\ brief rgb2gray it is an approximation grayscale function for relative RGB color space, - * see Miscellaneous.pdf for details; - *\ param rgb the input array, type of cv::Mat. - */ - cv::Mat rgb2gray(cv::Mat rgb) - { - return multiple(rgb, m_gray); - } +const static cv::Mat m_gray = (cv::Mat_(3, 1) << 0.2126, 0.7152, 0.0722); - } // namespace ccm +/* *\ brief rgb2gray it is an approximation grayscale function for relative RGB color space, + * see Miscellaneous.pdf for details; + *\ param rgb the input array, type of cv::Mat. +*/ +cv::Mat rgb2gray(cv::Mat rgb) +{ + return multiple(rgb, m_gray); +} +} // namespace ccm } // namespace cv -#endif + +#endif \ No newline at end of file From d6079756a1b7ecb836f27df6f3e9e1e23848f91d Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Thu, 10 Sep 2020 11:00:18 +0800 Subject: [PATCH 14/71] update document for sample --- .../mcc/samples/color_correction_model.cpp | 191 +++++++++++------- .../basic_ccm/color_correction_model.markdown | 69 +++---- 2 files changed, 142 insertions(+), 118 deletions(-) diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp index 5be8c631d23..fd5ffef8f2b 100644 --- a/modules/mcc/samples/color_correction_model.cpp +++ b/modules/mcc/samples/color_correction_model.cpp @@ -1,81 +1,124 @@ -#include -#include #include -#include "opencv2/mcc/ccm.hpp" -using namespace cv; +#include +#include +#include +#include +#include + using namespace std; +using namespace cv; +using namespace mcc; using namespace ccm; +using namespace std; -// inp the input array, type of cv::Mat. - - -int main() { - -const Mat s = (Mat_(24, 1) << - Vec3d(214.11, 98.67, 37.97), - Vec3d(231.94, 153.1, 85.27), - Vec3d(204.08, 143.71, 78.46), - Vec3d(190.58, 122.99, 30.84), - Vec3d(230.93, 148.46, 100.84), - Vec3d(228.64, 206.97, 97.5), - Vec3d(229.09, 137.07, 55.29), - Vec3d(189.21, 111.22, 92.66), - Vec3d(223.5, 96.42, 75.45), - Vec3d(201.82, 69.71, 50.9), - Vec3d(240.52, 196.47, 59.3), - Vec3d(235.73, 172.13, 54.), - Vec3d(131.6, 75.04, 68.86), - Vec3d(189.04, 170.43, 42.05), - Vec3d(222.23, 74., 71.95), - Vec3d(241.01, 199.1, 61.15), - Vec3d(224.99, 101.4, 100.24), - Vec3d(174.58, 152.63, 91.52), - Vec3d(248.06, 227.69, 140.5), - Vec3d(241.15, 201.38, 115.58), - Vec3d(236.49, 175.87, 88.86), - Vec3d(212.19, 133.49, 54.79), - Vec3d(181.17, 102.94, 36.18), - Vec3d(115.1, 53.77, 15.23)); - Color color = Macbeth_D65_2; - std::vector saturated_threshold = { 0, 0.98 }; - cv::Mat weight_list; - //std::string filename = "input1.png"; - - - ColorCorrectionModel p1(s / 255, color, sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, - saturated_threshold, weight_list, 0, LEAST_SQUARE, 5000, 1e-4); - //ColorCorrectionModel p2(s / 255, color, AdobeRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, - // saturated_threshold, weight_list, 0, LEAST_SQUARE, 5000, 1e-4); - //ColorCorrectionModel p3(s / 255, color, WideGamutRGB, CCM_4x3, CIE2000, GRAYPOLYFIT, 2.2, 3, - // saturated_threshold, weight_list, 0, LEAST_SQUARE, 5000, 1e-4); - //ColorCorrectionModel p4(s / 255, color, ProPhotoRGB, CCM_4x3, RGBL, GRAYLOGPOLYFIT, 2.2, 3, - // saturated_threshold, weight_list, 0, LEAST_SQUARE, 5000, 1e-4); - //ColorCorrectionModel p5(s / 255, color, DCI_P3_RGB, CCM_3x3, RGB, IDENTITY_, 2.2, 3, - // saturated_threshold, weight_list, 0, LEAST_SQUARE, 5000, 1e-4); - //ColorCorrectionModel p6(s / 255, color, AppleRGB, CCM_3x3, CIE2000, COLORPOLYFIT, 2.2, 2, - // saturated_threshold, weight_list, 2, LEAST_SQUARE, 5000, 1e-4); - //ColorCorrectionModel p7(s / 255, color, REC_2020_RGB, CCM_3x3, CIE94_GRAPHIC_ARTS, COLORLOGPOLYFIT, 2.2, 3, - // saturated_threshold, weight_list, 0, LEAST_SQUARE, 5000, 1e-4); - - - std::cout <<"ccm1"<< p1.ccm << std::endl; - //std::cout << "ccm2" << p2.ccm << std::endl; - //std::cout << "ccm3" << p3.ccm << std::endl; - //std::cout << "ccm4" << p4.ccm << std::endl; - //std::cout << "ccm5" << p5.ccm << std::endl; - //std::cout << "ccm6" << p6.ccm << std::endl; - //std::cout << "ccm7" << p7.ccm << std::endl; - - - //Mat img1 = p1.inferImage(filename); - //Mat img2 = p2.inferImage(filename); - //Mat img3 = p3.inferImage(filename); - //Mat img4 = p4.inferImage(filename); - //Mat img5 = p5.inferImage(filename, true); - //Mat img6 = p6.inferImage(filename); - //Mat img7 = p7.inferImage(filename); +const char *about = "Basic chart detection"; +const char *keys = { + "{ help h usage ? | | show this message }" + "{t | | chartType: 0-Standard, 1-DigitalSG, 2-Vinyl }" + "{v | | Input from video file, if ommited, input comes from camera }" + "{ci | 0 | Camera id if input doesnt come from video (-v) }" + "{f | 1 | Path of the file to process (-v) }" + "{nc | 1 | Maximum number of charts in the image }"}; - return 0; +int main(int argc, char *argv[]) +{ + + // ---------------------------------------------------------- + // Scroll down a bit (~40 lines) to find actual relevant code + // ---------------------------------------------------------- + + CommandLineParser parser(argc, argv, keys); + parser.about(about); + + int t = parser.get("t"); + int nc = parser.get("nc"); + string filepath = parser.get("f"); + + CV_Assert(0 <= t && t <= 2); + TYPECHART chartType = TYPECHART(t); + + cout << "t: " << t << " , nc: " << nc << ", \nf: " << filepath << endl; -} \ No newline at end of file + if (!parser.check()) + { + parser.printErrors(); + return 0; + } + + Mat image = cv::imread(filepath, IMREAD_COLOR); + if (!image.data) + { + cout << "Invalid Image!" << endl; + return 1; + } + + Mat imageCopy = image.clone(); + Ptr detector = CCheckerDetector::create(); + // Marker type to detect + if (!detector->process(image, chartType, nc)) + { + printf("ChartColor not detected \n"); + return 2; + } + // get checker + vector> checkers = detector->getListColorChecker(); + + for (Ptr checker : checkers) + { + Ptr cdraw = CCheckerDraw::create(checker); + cdraw->draw(image); + Mat chartsRGB = checker->getChartsRGB(); + Mat src = chartsRGB.col(1).clone().reshape(3, 18); + src /= 255.0; + + //compte color correction matrix + ColorCorrectionModel model1(src, Vinyl_D50_2); + + /* brief More models with different parameters, try it & check the document for details. + */ + // ColorCorrectionModel model2(src, Vinyl_D50_2, AdobeRGB, CCM_4x3, CIE2000, GAMMA, 2.2, 3); + // ColorCorrectionModel model3(src, Vinyl_D50_2, WideGamutRGB, CCM_4x3, CIE2000, GRAYPOLYFIT, 2.2, 3); + // ColorCorrectionModel model4(src, Vinyl_D50_2, ProPhotoRGB, CCM_4x3, RGBL, GRAYLOGPOLYFIT, 2.2, 3); + // ColorCorrectionModel model5(src, Vinyl_D50_2, DCI_P3_RGB, CCM_3x3, RGB, IDENTITY_, 2.2, 3); + // ColorCorrectionModel model6(src, Vinyl_D50_2, AppleRGB, CCM_3x3, CIE2000, COLORPOLYFIT, 2.2, 2,{ 0, 0.98 },Mat(),2); + // ColorCorrectionModel model7(src, Vinyl_D50_2, REC_2020_RGB, CCM_3x3, CIE94_GRAPHIC_ARTS, COLORLOGPOLYFIT, 2.2, 3); + + /* If you use a customized ColorChecker, you can use your own reference color values and corresponding color space in a way like: + */ + // cv::Mat ref = = (Mat_(18, 1) << + // Vec3d(1.00000000e+02, 5.20000001e-03, -1.04000000e-02), + // Vec3d(7.30833969e+01, -8.19999993e-01, -2.02099991e+00), + // Vec3d(6.24930000e+01, 4.25999999e-01, -2.23099995e+00), + // Vec3d(5.04640007e+01, 4.46999997e-01, -2.32399988e+00), + // Vec3d(3.77970009e+01, 3.59999985e-02, -1.29700005e+00), + // Vec3d(0.00000000e+00, 0.00000000e+00, 0.00000000e+00), + // Vec3d(5.15880013e+01, 7.35179977e+01, 5.15690002e+01), + // Vec3d(9.36989975e+01, -1.57340002e+01, 9.19420013e+01), + // Vec3d(6.94079971e+01, -4.65940018e+01, 5.04869995e+01), + // Vec3d(6.66100006e+01, -1.36789999e+01, -4.31720009e+01), + // Vec3d(1.17110004e+01, 1.69799995e+01, -3.71759987e+01), + // Vec3d(5.19739990e+01, 8.19440002e+01, -8.40699959e+00), + // Vec3d(4.05489998e+01, 5.04399986e+01, 2.48490009e+01), + // Vec3d(6.08160019e+01, 2.60690002e+01, 4.94420013e+01), + // Vec3d(5.22529984e+01, -1.99500008e+01, -2.39960003e+01), + // Vec3d(5.12859993e+01, 4.84700012e+01, -1.50579996e+01), + // Vec3d(6.87070007e+01, 1.22959995e+01, 1.62129993e+01), + // Vec3d(6.36839981e+01, 1.02930002e+01, 1.67639999e+01)); + + // ColorCorrectionModel model8(src,ref,Lab_D50_2); + + //make color correction + Mat calibratedImage = model1.inferImage(filepath); + + // Save the calibrated image to {FILE_NAME}.calibrated.{FILE_EXT} + string filename = filepath.substr(filepath.find_last_of('/')+1); + int dotIndex = filename.find_last_of('.'); + string baseName = filename.substr(0, dotIndex); + string ext = filename.substr(dotIndex+1, filename.length()-dotIndex); + string calibratedFilePath = baseName + ".calibrated." + ext; + cv::imwrite(calibratedFilePath, calibratedImage); + } + + return 0; +} diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index 59ca15d72ef..5734621db3a 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -28,9 +28,10 @@ Or make sure you check the mcc module in the GUI version of CMake: cmake-gui. Source Code of the sample ----------- -Parameters +The sample has two parts of code, the first is the color checker detector model, see details at[basic_chart_detection](https://github.com/opencv/opencv_contrib/tree/master/modules/mcc/tutorials/basic_chart_detection), the second part is to make collor calibration. ``` +Here are the parameters for ColorCorrectionModel src : detected colors of ColorChecker patches; NOTICE: the color type is RGB not BGR, and the color values are in [0, 1]; @@ -178,19 +179,9 @@ Supported Color Space: ## Explanation - @code{.cpp} + The first part is to detect the ColorChecker position. -\#include - -\#include "opencv2/mcc/ccm.hpp" - -using namespace cv; - -using namespace std; - -using namespace ccm; - - @endcode +@code{.cpp}#include #include #include #include #include #include using namespace std;using namespace cv;using namespace mcc;using namespace ccm;using namespace std;@endcode ``` Here is sets of header and namespaces. You can set other namespace like the code above. @@ -198,60 +189,50 @@ Here is sets of header and namespaces. You can set other namespace like the code @code{.cpp} -const Mat s = (Mat_(24, 1) << Vec3d(214.11, 98.67, 37.97), Vec3d(231.94, 153.1, 85.27), Vec3d(204.08, 143.71, 78.46), Vec3d(190.58, 122.99, 30.84), Vec3d(230.93, 148.46, 100.84), Vec3d(228.64, 206.97, 97.5), Vec3d(229.09, 137.07, 55.29), Vec3d(189.21, 111.22, 92.66), Vec3d(223.5, 96.42, 75.45), Vec3d(201.82, 69.71, 50.9), Vec3d(240.52, 196.47, 59.3), Vec3d(235.73, 172.13, 54.), Vec3d(131.6, 75.04, 68.86), Vec3d(189.04, 170.43, 42.05), Vec3d(222.23, 74., 71.95), Vec3d(241.01, 199.1, 61.15), Vec3d(224.99, 101.4, 100.24), Vec3d(174.58, 152.63, 91.52), Vec3d(248.06, 227.69, 140.5), Vec3d(241.15, 201.38, 115.58), Vec3d(236.49, 175.87, 88.86), Vec3d(212.19, 133.49, 54.79), Vec3d(181.17, 102.94, 36.18), Vec3d(115.1, 53.77, 15.23)); +const char *about = "Basic chart detection";const char *keys = { "{ help h usage ? | | show this message }" "{t | | chartType: 0-Standard, 1-DigitalSG, 2-Vinyl }" "{v | | Input from video file, if ommited, input comes from camera }" "{ci | 0 | Camera id if input doesnt come from video (-v) }" - @endcode + "{f | 1 | Path of the file to process (-v) }" "{nc | 1 | Maximum number of charts in the image }"};@ endcode ``` -The ColorChecker Matrix with the size of Nx1, type of cv::Mat. +Some arguments for ColorChecker detection. ``` -@code{.cpp} - - Color color = Macbeth_D65_2; - - // If you use a customized ColorChecker, make sure to define the Color instance with your own reference color values and corresponding color space: - - // Color color(ref_color_values, color_space); - - std::vector saturated_threshold = { 0, 0.98 }; +@code{.cpp} CommandLineParser parser(argc, argv, keys); parser.about(about); int t = parser.get("t"); int nc = parser.get("nc"); string filepath = parser.get("f"); CV_Assert(0 <= t && t <= 2); TYPECHART chartType = TYPECHART(t); cout << "t: " << t << " , nc: " << nc << ", \nf: " << filepath << endl;if (!parser.check()){ parser.printErrors();return 0;} Mat image = cv::imread(filepath, IMREAD_COLOR);if (!image.data) { cout << "Invalid Image!" << endl; return 1; } @endcode - cv::Mat weight_list; +``` +Preparation for ColorChecker detection to get messages for the image. +``` - std::string filename = "input1.png"; +@code{.cpp}Mat imageCopy = image.clone(); - @endcode + Ptr detector = CCheckerDetector::create(); if (!detector->process(image, chartType, nc)) { printf("ChartColor not detected \n"); return 2; } vector> checkers = detector->getListColorChecker();@endcode ``` -Some variables for computing ccm Matrix. The variable filename is the path of a picture to be corrected.See other parameters' detail at the Parameters. +The CCheckerDetectorobject is created and uses getListColorChecker function to get ColorChecker message. ``` -@code{.cpp} - -ColorCorrectionModel p1(s / 255., color, sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, saturated_threshold, weight_list, 0, LEAST_SQUARE, 5000, 1.e-4); - - @endcode +@code{.cpp} for (Ptr checker : checkers) { Ptr cdraw = CCheckerDraw::create(checker); cdraw->draw(image); Mat chartsRGB = checker->getChartsRGB();Mat src = chartsRGB.col(1).clone().reshape(3, 18); src /= 255.0; //compte color correction matrix ColorCorrectionModel model1(src, Vinyl_D50_2);}@endcode ``` -the object p1 is an object of ColorCorrectionModel class. The parameters should be changed to get the best effect of color correction. +For every ColorChecker,we can compute a ccm matrix for color correction.model1 is an object of ColorCorrectionModel class. The parameters should be changed to get the best effect of color correction.See other parameters' detail at the Parameters. ``` -@code{.cpp} - - std::cout <<"ccm1"<< p1.ccm << std::endl; +@code{.cpp}cv::Mat ref = = (Mat_(18, 1) < Date: Thu, 10 Sep 2020 17:40:16 +0800 Subject: [PATCH 15/71] update license --- modules/mcc/include/opencv2/mcc/ccm.hpp | 47 +++++++++-------- modules/mcc/include/opencv2/mcc/color.hpp | 47 +++++++++-------- .../mcc/include/opencv2/mcc/colorspace.hpp | 47 +++++++++-------- modules/mcc/include/opencv2/mcc/distance.hpp | 51 +++++++++---------- modules/mcc/include/opencv2/mcc/io.hpp | 47 +++++++++-------- modules/mcc/include/opencv2/mcc/linearize.hpp | 47 +++++++++-------- .../mcc/include/opencv2/mcc/operations.hpp | 46 ++++++++--------- modules/mcc/include/opencv2/mcc/utils.hpp | 47 +++++++++-------- .../basic_ccm/color_correction_model.markdown | 2 +- 9 files changed, 187 insertions(+), 194 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 4faed2c19f5..ebd8c860f4d 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -1,30 +1,29 @@ // This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. - -/* - * MIT License - * - * Copyright (c) 2018 Pedro Diamel Marrero Fernández - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan #ifndef __OPENCV_MCC_CCM_HPP__ #define __OPENCV_MCC_CCM_HPP__ diff --git a/modules/mcc/include/opencv2/mcc/color.hpp b/modules/mcc/include/opencv2/mcc/color.hpp index 4d8a9350f4d..aee5c6d7e75 100644 --- a/modules/mcc/include/opencv2/mcc/color.hpp +++ b/modules/mcc/include/opencv2/mcc/color.hpp @@ -1,30 +1,29 @@ // This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. - -/* - * MIT License - * - * Copyright (c) 2018 Pedro Diamel Marrero Fernández - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan #ifndef __OPENCV_MCC_COLOR_HPP__ #define __OPENCV_MCC_COLOR_HPP__ diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp index d4f6fe9d601..5a03b60c5db 100644 --- a/modules/mcc/include/opencv2/mcc/colorspace.hpp +++ b/modules/mcc/include/opencv2/mcc/colorspace.hpp @@ -1,30 +1,29 @@ // This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. - -/* - * MIT License - * - * Copyright (c) 2018 Pedro Diamel Marrero Fernández - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan #ifndef __OPENCV_MCC_COLORSPACE_HPP__ #define __OPENCV_MCC_COLORSPACE_HPP__ diff --git a/modules/mcc/include/opencv2/mcc/distance.hpp b/modules/mcc/include/opencv2/mcc/distance.hpp index d4ac7f83cfe..0fb599faf9a 100644 --- a/modules/mcc/include/opencv2/mcc/distance.hpp +++ b/modules/mcc/include/opencv2/mcc/distance.hpp @@ -1,30 +1,29 @@ // This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level -// directory of this distribution and at http://opencv.org/license.html. - -/* - * MIT License - * - * Copyright (c) 2018 Pedro Diamel Marrero Fernández - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan #ifndef __OPENCV_MCC_DISTANCE_HPP__ #define __OPENCV_MCC_DISTANCE_HPP__ diff --git a/modules/mcc/include/opencv2/mcc/io.hpp b/modules/mcc/include/opencv2/mcc/io.hpp index a1be185dfe9..e2b66053690 100644 --- a/modules/mcc/include/opencv2/mcc/io.hpp +++ b/modules/mcc/include/opencv2/mcc/io.hpp @@ -1,30 +1,29 @@ // This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. - -/* - * MIT License - * - * Copyright (c) 2018 Pedro Diamel Marrero Fernández - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan #ifndef __OPENCV_MCC_IO_HPP__ #define __OPENCV_MCC_IO_HPP__ diff --git a/modules/mcc/include/opencv2/mcc/linearize.hpp b/modules/mcc/include/opencv2/mcc/linearize.hpp index ad337ac76dc..5adc12f2072 100644 --- a/modules/mcc/include/opencv2/mcc/linearize.hpp +++ b/modules/mcc/include/opencv2/mcc/linearize.hpp @@ -1,30 +1,29 @@ // This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. - -/* - * MIT License - * - * Copyright (c) 2018 Pedro Diamel Marrero Fernández - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan #ifndef __OPENCV_MCC_LINEARIZE_HPP__ #define __OPENCV_MCC_LINEARIZE_HPP__ diff --git a/modules/mcc/include/opencv2/mcc/operations.hpp b/modules/mcc/include/opencv2/mcc/operations.hpp index 2369f11b29d..af5c5554b68 100644 --- a/modules/mcc/include/opencv2/mcc/operations.hpp +++ b/modules/mcc/include/opencv2/mcc/operations.hpp @@ -1,30 +1,30 @@ // This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan -/* - * MIT License - * - * Copyright (c) 2018 Pedro Diamel Marrero Fernández - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #ifndef __OPENCV_MCC_OPERATIONS_HPP__ #define __OPENCV_MCC_OPERATIONS_HPP__ diff --git a/modules/mcc/include/opencv2/mcc/utils.hpp b/modules/mcc/include/opencv2/mcc/utils.hpp index 7c63dae9030..56c071bb883 100644 --- a/modules/mcc/include/opencv2/mcc/utils.hpp +++ b/modules/mcc/include/opencv2/mcc/utils.hpp @@ -1,30 +1,29 @@ // This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. - -/* - * MIT License - * - * Copyright (c) 2018 Pedro Diamel Marrero Fernández - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan #ifndef __OPENCV_MCC_UTILS_HPP__ #define __OPENCV_MCC_UTILS_HPP__ diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index 5734621db3a..0999c92cd72 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -214,7 +214,7 @@ The CCheckerDetectorobject is created and uses getListColorChecker function to g @code{.cpp} for (Ptr checker : checkers) { Ptr cdraw = CCheckerDraw::create(checker); cdraw->draw(image); Mat chartsRGB = checker->getChartsRGB();Mat src = chartsRGB.col(1).clone().reshape(3, 18); src /= 255.0; //compte color correction matrix ColorCorrectionModel model1(src, Vinyl_D50_2);}@endcode ``` -For every ColorChecker,we can compute a ccm matrix for color correction.model1 is an object of ColorCorrectionModel class. The parameters should be changed to get the best effect of color correction.See other parameters' detail at the Parameters. +For every ColorChecker, we can compute a ccm matrix for color correction. Model1 is an object of ColorCorrectionModel class. The parameters should be changed to get the best effect of color correction. See other parameters' detail at the Parameters. ``` @code{.cpp}cv::Mat ref = = (Mat_(18, 1) < Date: Thu, 10 Sep 2020 20:45:21 +0800 Subject: [PATCH 16/71] fix linearize.hpp --- modules/mcc/include/opencv2/mcc/linearize.hpp | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/linearize.hpp b/modules/mcc/include/opencv2/mcc/linearize.hpp index 5adc12f2072..7d4de718bed 100644 --- a/modules/mcc/include/opencv2/mcc/linearize.hpp +++ b/modules/mcc/include/opencv2/mcc/linearize.hpp @@ -58,26 +58,32 @@ class Polyfit Polyfit() {}; /* *\ brief Polyfit method. + https://en.wikipedia.org/wiki/Polynomial_regression + polynomial: yi = a0 + a1*xi + a2*xi^2 + ... + an*xi^deg (i = 1,2,...,n) + and deduct: Ax = y + See linear.pdf for details */ - Polyfit(cv::Mat s, cv::Mat d, int deg_) :deg(deg_) + Polyfit(cv::Mat x, cv::Mat y, int deg_) :deg(deg_) { - int npoints = s.checkVector(1); - cv::Mat_ srcX(s), srcY(d); - cv::Mat_ m = cv::Mat_::ones(npoints, deg + 1); - for (int y = 0; y < npoints; ++y) + int n = x.cols * x.rows * x.channels(); + x = x.reshape(1, n); + y = y.reshape(1, n); + cv::Mat_ A = cv::Mat_::ones(n, deg + 1); + for (int i = 0; i < n; ++i) { - for (int x = 1; x < m.cols; ++x) + for (int j = 1; j < A.cols; ++j) { - m.at(y, x) = srcX.at(y) * m.at(y, x - 1); + A.at(i, j) = x.at(i) * A.at(i, j - 1); } } - cv::solve(m, srcY, p, DECOMP_SVD); + cv::Mat y_(y); + cv::solve(A, y_, p, DECOMP_SVD); } virtual ~Polyfit() {}; cv::Mat operator()(const cv::Mat& inp) { - return elementWise(inp, [this](double a)->double {return fromEW(a); }); + return elementWise(inp, [this](double x)->double {return fromEW(x); }); }; private: @@ -104,12 +110,12 @@ class LogPolyfit /* *\ brief Logpolyfit method. */ - LogPolyfit(cv::Mat s, cv::Mat d, int deg_) :deg(deg_) + LogPolyfit(cv::Mat x, cv::Mat y, int deg_) :deg(deg_) { - cv::Mat mask_ = (s > 0) & (d > 0); + cv::Mat mask_ = (x > 0) & (y > 0); cv::Mat src_, dst_, s_, d_; - src_ = maskCopyTo(s, mask_); - dst_ = maskCopyTo(d, mask_); + src_ = maskCopyTo(x, mask_); + dst_ = maskCopyTo(y, mask_); log(src_, s_); log(dst_, d_); p = Polyfit(s_, d_, deg); From 9b821670075a3d4a2d90459bc4b67b282cf50cc4 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Thu, 10 Sep 2020 21:18:23 +0800 Subject: [PATCH 17/71] Add basic io, utils, operations helpers. Implement color distance. --- modules/mcc/include/opencv2/mcc/distance.hpp | 298 ++++++++++++++++++ modules/mcc/include/opencv2/mcc/io.hpp | 109 +++++++ .../mcc/include/opencv2/mcc/operations.hpp | 146 +++++++++ modules/mcc/include/opencv2/mcc/utils.hpp | 235 ++++++++++++++ 4 files changed, 788 insertions(+) create mode 100644 modules/mcc/include/opencv2/mcc/distance.hpp create mode 100644 modules/mcc/include/opencv2/mcc/io.hpp create mode 100644 modules/mcc/include/opencv2/mcc/operations.hpp create mode 100644 modules/mcc/include/opencv2/mcc/utils.hpp diff --git a/modules/mcc/include/opencv2/mcc/distance.hpp b/modules/mcc/include/opencv2/mcc/distance.hpp new file mode 100644 index 00000000000..d0c9ac16307 --- /dev/null +++ b/modules/mcc/include/opencv2/mcc/distance.hpp @@ -0,0 +1,298 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#ifndef __OPENCV_MCC_DISTANCE_HPP__ +#define __OPENCV_MCC_DISTANCE_HPP__ + +#include "opencv2/mcc/utils.hpp" + +namespace cv +{ +namespace ccm +{ + +/* *\brief Enum of possibale functions to calculate the distance between + * colors.see https://en.wikipedia.org/wiki/Color_difference for details;*/ +enum DISTANCE_TYPE +{ + CIE76, + CIE94_GRAPHIC_ARTS, + CIE94_TEXTILES, + CIE2000, + CMC_1TO1, + CMC_2TO1, + RGB, + RGBL +}; + +double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH = 1.0, + double kC = 1.0, double kL = 1.0, double k1 = 0.045, + double k2 = 0.015); +double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2); +double toRad(double degree); +double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1.0, + double kC = 1.0, double kH = 1.0); +double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1, double kC = 1); +double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2); +cv::Mat distance(cv::Mat src, cv::Mat ref, DISTANCE_TYPE distance_type); + + +/* *\ brief distance between two points in formula CIE76 + *\ param lab1 a 3D vector + *\ param lab2 a 3D vector + *\ return distance between lab1 and lab2 +*/ +double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2) { return norm(lab1 - lab2); }; + +/* *\ brief distance between two points in formula CIE94 + *\ param lab1 a 3D vector + *\ param lab2 a 3D vector + *\ param kH Hue scale + *\ param kC Chroma scale + *\ param kL Lightness scale + *\ param k1 first scale parameter + *\ param k2 second scale parameter + *\ return distance between lab1 and lab2 +*/ +double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH, + double kC, double kL, double k1, double k2) +{ + double dl = lab1[0] - lab2[0]; + double c1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); + double c2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); + double dc = c1 - c2; + double da = lab1[1] - lab2[1]; + double db = lab1[2] - lab2[2]; + double dh = pow(da, 2) + pow(db, 2) - pow(dc, 2); + double sc = 1.0 + k1 * c1; + double sh = 1.0 + k2 * c1; + double sl = 1.0; + double res = + pow(dl / (kL * sl), 2) + pow(dc / (kC * sc), 2) + dh / pow(kH * sh, 2); + + return res > 0 ? sqrt(res) : 0; +} + +double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2) +{ + return deltaCIE94(lab1, lab2); +} + +double toRad(double degree) { return degree / 180 * CV_PI; }; + +double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2) +{ + return deltaCIE94(lab1, lab2, 1.0, 1.0, 2.0, 0.048, 0.014); +} + +/* *\ brief distance between two points in formula CIE2000 + *\ param lab1 a 3D vector + *\ param lab2 a 3D vector + *\ param kL Lightness scale + *\ param kC Chroma scale + *\ param kH Hue scale + *\ return distance between lab1 and lab2 +*/ +double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL, + double kC, double kH) +{ + double delta_L_apo = lab2[0] - lab1[0]; + double l_bar_apo = (lab1[0] + lab2[0]) / 2.0; + double C1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); + double C2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); + double C_bar = (C1 + C2) / 2.0; + double G = sqrt(pow(C_bar, 7) / (pow(C_bar, 7) + pow(25, 7))); + double a1_apo = lab1[1] + lab1[1] / 2.0 * (1.0 - G); + double a2_apo = lab2[1] + lab2[1] / 2.0 * (1.0 - G); + double C1_apo = sqrt(pow(a1_apo, 2) + pow(lab1[2], 2)); + double C2_apo = sqrt(pow(a2_apo, 2) + pow(lab2[2], 2)); + double C_bar_apo = (C1_apo + C2_apo) / 2.0; + double delta_C_apo = C2_apo - C1_apo; + + double h1_apo; + if (C1_apo == 0) + { + h1_apo = 0.0; + } + else + { + h1_apo = atan2(lab1[2], a1_apo); + if (h1_apo < 0.0) h1_apo += 2. * CV_PI; + } + + double h2_apo; + if (C2_apo == 0) + { + h2_apo = 0.0; + } + else + { + h2_apo = atan2(lab2[2], a2_apo); + if (h2_apo < 0.0) h2_apo += 2. * CV_PI; + } + + double delta_h_apo; + if (abs(h2_apo - h1_apo) <= CV_PI) + { + delta_h_apo = h2_apo - h1_apo; + } + else if (h2_apo <= h1_apo) + { + delta_h_apo = h2_apo - h1_apo + 2. * CV_PI; + } + else + { + delta_h_apo = h2_apo - h1_apo - 2. * CV_PI; + } + + double H_bar_apo; + if (C1_apo == 0 || C2_apo == 0) + { + H_bar_apo = h1_apo + h2_apo; + } + else if (abs(h1_apo - h2_apo) <= CV_PI) + { + H_bar_apo = (h1_apo + h2_apo) / 2.0; + } + else if (h1_apo + h2_apo < 2. * CV_PI) + { + H_bar_apo = (h1_apo + h2_apo + 2. * CV_PI) / 2.0; + } + else + { + H_bar_apo = (h1_apo + h2_apo - 2. * CV_PI) / 2.0; + } + + double delta_H_apo = 2.0 * sqrt(C1_apo * C2_apo) * sin(delta_h_apo / 2.0); + double T = 1.0 - 0.17 * cos(H_bar_apo - toRad(30.)) + + 0.24 * cos(2.0 * H_bar_apo) + + 0.32 * cos(3.0 * H_bar_apo + toRad(6.0)) - + 0.2 * cos(4.0 * H_bar_apo - toRad(63.0)); + double sC = 1.0 + 0.045 * C_bar_apo; + double sH = 1.0 + 0.015 * C_bar_apo * T; + double sL = 1.0 + ((0.015 * pow(l_bar_apo - 50.0, 2.0)) / + sqrt(20.0 + pow(l_bar_apo - 50.0, 2.0))); + double RT = -2.0 * G * + sin(toRad(60.0) * + exp(-pow((H_bar_apo - toRad(275.0)) / toRad(25.0), 2.0))); + double res = + (pow(delta_L_apo / (kL * sL), 2.0) + pow(delta_C_apo / (kC * sC), 2.0) + + pow(delta_H_apo / (kH * sH), 2.0) + + RT * (delta_C_apo / (kC * sC)) * (delta_H_apo / (kH * sH))); + return res > 0 ? sqrt(res) : 0; +} + +double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2) +{ + return deltaCIEDE2000_(lab1, lab2); +} + +/* *\ brief distance between two points in formula CMC + *\ param lab1 a 3D vector + *\ param lab2 a 3D vector + *\ param kL Lightness scale + *\ param kC Chroma scale + *\ return distance between lab1 and lab2 +*/ +double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL, double kC) +{ + double dL = lab2[0] - lab1[0]; + double da = lab2[1] - lab1[1]; + double db = lab2[2] - lab1[2]; + double C1 = sqrt(pow(lab1[1], 2.0) + pow(lab1[2], 2.0)); + double C2 = sqrt(pow(lab2[1], 2.0) + pow(lab2[2], 2.0)); + double dC = C2 - C1; + double dH = sqrt(pow(da, 2) + pow(db, 2) - pow(dC, 2)); + + double H1; + if (C1 == 0.) + { + H1 = 0.0; + } + else + { + H1 = atan2(lab1[2], lab1[1]); + if (H1 < 0.0) H1 += 2. * CV_PI; + } + + double F = pow(C1, 2) / sqrt(pow(C1, 4) + 1900); + double T = (H1 > toRad(164) && H1 <= toRad(345)) + ? 0.56 + abs(0.2 * cos(H1 + toRad(168))) + : 0.36 + abs(0.4 * cos(H1 + toRad(35))); + double sL = + lab1[0] < 16. ? 0.511 : (0.040975 * lab1[0]) / (1.0 + 0.01765 * lab1[0]); + double sC = (0.0638 * C1) / (1.0 + 0.0131 * C1) + 0.638; + double sH = sC * (F * T + 1.0 - F); + + return sqrt(pow(dL / (kL * sL), 2.0) + pow(dC / (kC * sC), 2.0) + + pow(dH / sH, 2.0)); +} + +double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2) +{ + return deltaCMC(lab1, lab2); +} + +double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2) +{ + return deltaCMC(lab1, lab2, 2, 1); +} + +cv::Mat distance(cv::Mat src, cv::Mat ref, DISTANCE_TYPE distance_type) +{ + switch (distance_type) + { + case cv::ccm::CIE76: + return distanceWise(src, ref, deltaCIE76); + case cv::ccm::CIE94_GRAPHIC_ARTS: + return distanceWise(src, ref, deltaCIE94GraphicArts); + case cv::ccm::CIE94_TEXTILES: + return distanceWise(src, ref, deltaCIE94Textiles); + case cv::ccm::CIE2000: + return distanceWise(src, ref, deltaCIEDE2000); + case cv::ccm::CMC_1TO1: + return distanceWise(src, ref, deltaCMC1To1); + case cv::ccm::CMC_2TO1: + return distanceWise(src, ref, deltaCMC2To1); + case cv::ccm::RGB: + return distanceWise(src, ref, deltaCIE76); + case cv::ccm::RGBL: + return distanceWise(src, ref, deltaCIE76); + default: + throw std::invalid_argument{ "Wrong distance_type!" }; + break; + } +}; + +} // namespace ccm +} // namespace cv + +#endif diff --git a/modules/mcc/include/opencv2/mcc/io.hpp b/modules/mcc/include/opencv2/mcc/io.hpp new file mode 100644 index 00000000000..dd62d46e423 --- /dev/null +++ b/modules/mcc/include/opencv2/mcc/io.hpp @@ -0,0 +1,109 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#ifndef __OPENCV_MCC_IO_HPP__ +#define __OPENCV_MCC_IO_HPP__ + +#include +#include +#include +#include + +namespace cv +{ +namespace ccm +{ + +/* *\ brief Io is the meaning of illuminant and observer. See notes of ccm.hpp + * for supported list for illuminant and observer*/ +class IO +{ +public: + + std::string illuminant; + std::string observer; + + IO() {}; + + IO(std::string illuminant_, std::string observer_) :illuminant(illuminant_), observer(observer_) {}; + + virtual ~IO() {}; + + bool operator<(const IO& other) const + { + return (illuminant < other.illuminant || ((illuminant == other.illuminant) && (observer < other.observer))); + } + + bool operator==(const IO& other) const + { + return illuminant == other.illuminant && observer == other.observer; + }; +}; + +const IO A_2("A", "2"), A_10("A", "10"), + D50_2("D50", "2"), D50_10("D50", "10"), + D55_2("D55", "2"), D55_10("D55", "10"), + D65_2("D65", "2"), D65_10("D65", "10"), + D75_2("D75", "2"), D75_10("D75", "10"), + E_2("E", "2"), E_10("E", "10"); + +// data from https://en.wikipedia.org/wiki/Standard_illuminant. +const static std::map> illuminants_xy = +{ + {A_2, { 0.44757, 0.40745 }}, {A_10, { 0.45117, 0.40594 }}, + {D50_2, { 0.34567, 0.35850 }}, {D50_10, { 0.34773, 0.35952 }}, + {D55_2, { 0.33242, 0.34743 }}, {D55_10, { 0.33411, 0.34877 }}, + {D65_2, { 0.31271, 0.32902 }}, {D65_10, { 0.31382, 0.33100 }}, + {D75_2, { 0.29902, 0.31485 }}, {D75_10, { 0.45117, 0.40594 }}, + {E_2, { 1 / 3, 1 / 3 }}, {E_10, { 1 / 3, 1 / 3 }}, +}; + +std::vector xyY2XYZ(const std::vector& xyY); +std::vector xyY2XYZ(const std::vector& xyY) +{ + double Y = xyY.size() >= 3 ? xyY[2] : 1; + return { Y * xyY[0] / xyY[1], Y, Y / xyY[1] * (1 - xyY[0] - xyY[1]) }; +} + +/* *\ brief function to get illuminants*/ +static std::map > getIlluminant(); +static std::map > getIlluminant() +{ + std::map > illuminants; + for (auto it = illuminants_xy.begin(); it != illuminants_xy.end(); ++it) + { + illuminants[it->first] = xyY2XYZ(it->second); + } + return illuminants; +} + +const std::map > illuminants = getIlluminant(); +} // namespace ccm +} // namespace cv + + +#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/operations.hpp b/modules/mcc/include/opencv2/mcc/operations.hpp new file mode 100644 index 00000000000..71947306071 --- /dev/null +++ b/modules/mcc/include/opencv2/mcc/operations.hpp @@ -0,0 +1,146 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + + +#ifndef __OPENCV_MCC_OPERATIONS_HPP__ +#define __OPENCV_MCC_OPERATIONS_HPP__ + +#include +#include +#include "opencv2/mcc/utils.hpp" + +namespace cv +{ +namespace ccm +{ + +typedef std::function MatFunc; + +/* *\ brief Operation class contains some operarions used for color space + * conversion containing linear transformation and non-linear transformation + */ +class Operation +{ +public: + bool linear; + cv::Mat M; + MatFunc f; + + Operation() : linear(true), M(cv::Mat()) {}; + + Operation(cv::Mat M_) :linear(true), M(M_) {}; + + Operation(MatFunc f_) : linear(false), f(f_) {}; + + virtual ~Operation() {}; + /* *\ brief operator function will run operation + */ + cv::Mat operator()(cv::Mat& abc) + { + if (!linear) + { + return f(abc); + } + if (M.empty()) + { + return abc; + } + return multiple(abc, M); + }; + + /* *\ brief add function will conbine this operation + * with other linear transformation operation + */ + void add(const Operation& other) + { + if (M.empty()) + { + M = other.M.clone(); + } + else + { + M = M * other.M; + } + }; + + void clear() + { + M = cv::Mat(); + }; +}; + +const Operation IDENTITY_OP([](cv::Mat x) {return x; }); + +class Operations +{ +public: + std::vector ops; + + Operations() :ops{ } {}; + + Operations(std::initializer_list op) :ops{ op } {}; + + virtual ~Operations() {}; + + /* *\ brief add function will conbine this operation with other transformation operations + */ + Operations& add(const Operations& other) + { + ops.insert(ops.end(), other.ops.begin(), other.ops.end()); + return *this; + }; + + /* *\ brief run operations to make color conversion + */ + cv::Mat run(cv::Mat abc) + { + Operation hd; + for (auto& op : ops) + { + if (op.linear) + { + hd.add(op); + } + else + { + abc = hd(abc); + hd.clear(); + abc = op(abc); + } + } + abc = hd(abc); + return abc; + }; +}; + +const Operations IDENTITY_OPS{ IDENTITY_OP }; + +} // namespace ccm +} // namespace cv + + +#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/utils.hpp b/modules/mcc/include/opencv2/mcc/utils.hpp new file mode 100644 index 00000000000..d1f56854c85 --- /dev/null +++ b/modules/mcc/include/opencv2/mcc/utils.hpp @@ -0,0 +1,235 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#ifndef __OPENCV_MCC_UTILS_HPP__ +#define __OPENCV_MCC_UTILS_HPP__ + +#include +#include +#include +#include +#include + +namespace cv +{ +namespace ccm +{ + +double gammaCorrection_(const double& element, const double& gamma); +cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma); +cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask); +cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm); +cv::Mat saturate(cv::Mat& src, const double& low, const double& up); +cv::Mat rgb2gray(cv::Mat rgb); + +/* *\ brief function for elementWise operation + *\ param src the input array, type of cv::Mat + *\ lambda a for operation +*/ +template +cv::Mat elementWise(const cv::Mat& src, F&& lambda) +{ + cv::Mat dst = src.clone(); + const int channel = src.channels(); + switch (channel) + { + case 1: + { + cv::MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) + { + (*it) = lambda((*it)); + } + break; + } + case 3: + { + cv::MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) + { + for (int j = 0; j < 3; j++) + { + (*it)[j] = lambda((*it)[j]); + } + } + break; + } + default: + throw std::invalid_argument{ "Wrong channel!" }; + break; + } + return dst; +} + +/* *\ brief function for channel operation + *\ param src the input array, type of cv::Mat + *\ lambda the function for operation +*/ +template +cv::Mat channelWise(const cv::Mat& src, F&& lambda) +{ + cv::Mat dst = src.clone(); + cv::MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) + { + *it = lambda(*it); + } + return dst; +} + +/* *\ brief function for distance operation. + *\ param src the input array, type of cv::Mat. + *\ param ref another input array, type of cv::Mat. + *\ param lambda the computing method for distance . +*/ +template +cv::Mat distanceWise(cv::Mat& src, cv::Mat& ref, F&& lambda) +{ + cv::Mat dst = cv::Mat(src.size(), CV_64FC1); + cv::MatIterator_ it_src = src.begin(), end_src = src.end(), + it_ref = ref.begin(); + cv::MatIterator_ it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_ref, ++it_dst) + { + *it_dst = lambda(*it_src, *it_ref); + } + return dst; +} + + +double gammaCorrection_(const double& element, const double& gamma) +{ + return (element >= 0 ? pow(element, gamma) : -pow((-element), gamma)); +} + +/* *\ brief gamma correction, see ColorSpace.pdf for details. + *\ param src the input array, type of cv::Mat. + *\ param gamma a constant for gamma correction. +*/ +cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma) +{ + return elementWise(src, [gamma](double element)->double {return gammaCorrection_(element, gamma); }); +} + +/* *\ brief maskCopyTo a function to delete unsatisfied elementwise. + *\ param src the input array, type of cv::Mat. + *\ param mask operation mask that used to choose satisfided elementwise. +*/ +cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) +{ + cv::Mat dst(countNonZero(mask), 1, src.type()); + const int channel = src.channels(); + auto it_mask = mask.begin(); + switch (channel) + { + case 1: + { + auto it_src = src.begin(), end_src = src.end(); + auto it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_mask) + { + if (*it_mask) + { + (*it_dst) = (*it_src); + ++it_dst; + } + } + break; + } + case 3: + { + auto it_src = src.begin(), end_src = src.end(); + auto it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_mask) + { + if (*it_mask) + { + (*it_dst) = (*it_src); + ++it_dst; + } + } + break; + } + default: + throw std::invalid_argument{ "Wrong channel!" }; + break; + } + return dst; +} + +/* *\ brief multiple the function used to compute an array with n channels mulipied by ccm. + *\ param src the input array, type of cv::Mat. + *\ param ccm the ccm matrix to make color correction. +*/ +cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm) +{ + cv::Mat tmp = xyz.reshape(1, xyz.rows * xyz.cols); + cv::Mat res = tmp * ccm; + res = res.reshape(res.cols, xyz.rows); + return res; +} + +/* *\ brief multiple the function used to get the mask of saturated colors, + colors between low and up will be choosed. + *\ param src the input array, type of cv::Mat. + *\ param low the threshold to choose saturated colors + *\ param up the threshold to choose saturated colors +*/ +cv::Mat saturate(cv::Mat& src, const double& low, const double& up) +{ + cv::Mat dst = cv::Mat::ones(src.size(), CV_8UC1); + cv::MatIterator_ it_src = src.begin(), end_src = src.end(); + cv::MatIterator_ it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_dst) + { + for (int i = 0; i < 3; ++i) + { + if ((*it_src)[i] > up || (*it_src)[i] < low) + { + *it_dst = 0; + break; + } + } + } + return dst; +} + +const static cv::Mat m_gray = (cv::Mat_(3, 1) << 0.2126, 0.7152, 0.0722); + +/* *\ brief rgb2gray it is an approximation grayscale function for relative RGB color space, + * see Miscellaneous.pdf for details; + *\ param rgb the input array, type of cv::Mat. +*/ +cv::Mat rgb2gray(cv::Mat rgb) +{ + return multiple(rgb, m_gray); +} +} // namespace ccm +} // namespace cv + + +#endif \ No newline at end of file From 02c1d2a5ed1d74c0c08aef58cdb75f6b91f6455b Mon Sep 17 00:00:00 2001 From: Jinheng Zhang Date: Thu, 10 Sep 2020 21:18:56 +0800 Subject: [PATCH 18/71] Implement color, colorspace, linearization and ccm features. --- modules/mcc/include/opencv2/mcc/ccm.hpp | 545 +++++++++++++++ modules/mcc/include/opencv2/mcc/color.hpp | 285 ++++++++ .../mcc/include/opencv2/mcc/colorspace.hpp | 635 ++++++++++++++++++ modules/mcc/include/opencv2/mcc/linearize.hpp | 304 +++++++++ 4 files changed, 1769 insertions(+) create mode 100644 modules/mcc/include/opencv2/mcc/ccm.hpp create mode 100644 modules/mcc/include/opencv2/mcc/color.hpp create mode 100644 modules/mcc/include/opencv2/mcc/colorspace.hpp create mode 100644 modules/mcc/include/opencv2/mcc/linearize.hpp diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp new file mode 100644 index 00000000000..9a581cf9112 --- /dev/null +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -0,0 +1,545 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#ifndef __OPENCV_MCC_CCM_HPP__ +#define __OPENCV_MCC_CCM_HPP__ + +#include +#include +#include +#include +#include +#include +#include +#include "opencv2/mcc/linearize.hpp" + +namespace cv +{ +namespace ccm +{ + +/** + src : + detected colors of ColorChecker patches; + NOTICE: the color type is RGB not BGR, and the color values are in [0, 1]; + type: cv::Mat; + dst : + the reference colors; + NOTICE: Built-in color card or custom color card are supported; + Built-in: + Macbeth_D50_2: Macbeth ColorChecker with 2deg D50; + Macbeth_D65_2: Macbeth ColorChecker with 2deg D65; + Custom: + You should use Color + For the list of color spaces supported, see the notes below; + If the color type is some RGB, the format is RGB not BGR, and the color values are in [0, 1]; + type: Color; + colorspace : + the absolute color space that detected colors convert to; + NOTICE: it should be some RGB color space; + For the list of RGB color spaces supported, see the notes below; + type: ColorSpace; + ccm_type : + the shape of color correction matrix(CCM); + Supported list: + "CCM_3x3": 3x3 matrix; + "CCM_4x3": 4x3 matrix; + type: enum CCM_TYPE; + default: CCM_3x3; + distance : + the type of color distance; + Supported list: + "CIE2000"; + "CIE94_GRAPHIC_ARTS"; + "CIE94_TEXTILES"; + "CIE76"; + "CMC_1TO1"; + "CMC_2TO1"; + "RGB" : Euclidean distance of rgb color space; + "RGBL" : Euclidean distance of rgbl color space; + type: enum DISTANCE_TYPE; + default: CIE2000; + linear_type : + the method of linearization; + NOTICE: see Linearization.pdf for details; + Supported list: + "IDENTITY_" : no change is made; + "GAMMA": gamma correction; + Need assign a value to gamma simultaneously; + "COLORPOLYFIT": polynomial fitting channels respectively; + Need assign a value to deg simultaneously; + "GRAYPOLYFIT": grayscale polynomial fitting; + Need assign a value to deg and dst_whites simultaneously; + "COLORLOGPOLYFIT": logarithmic polynomial fitting channels respectively; + Need assign a value to deg simultaneously; + "GRAYLOGPOLYFIT": grayscale Logarithmic polynomial fitting; + Need assign a value to deg and dst_whites simultaneously; + type: enum LINEAR_TYPE; + default: IDENTITY_; + gamma : + the gamma value of gamma correction; + NOTICE: only valid when linear is set to "gamma"; + type: double; + default: 2.2; + deg : + the degree of linearization polynomial; + NOTICE: only valid when linear is set to "COLORPOLYFIT", "GRAYPOLYFIT", + "COLORLOGPOLYFIT" and "GRAYLOGPOLYFIT"; + type: int; + default: 3; + saturated_threshold : + the threshold to determine saturation; + NOTICE: it is a tuple of [low, up]; + The colors in the closed interval [low, up] are reserved to participate + in the calculation of the loss function and initialization parameters. + type: std::vector; + default: { 0, 0.98 }; + --------------------------------------------------- + There are some ways to set weights: + 1. set weights_list only; + 2. set weights_coeff only; + see CCM.pdf for details; + weights_list : + the list of weight of each color; + type: cv::Mat; + default: empty array; + weights_coeff : + the exponent number of L* component of the reference color in CIE Lab color space; + type: double; + default: 0; + --------------------------------------------------- + initial_method_type : + the method of calculating CCM initial value; + see CCM.pdf for details; + Supported list: + 'LEAST_SQUARE': least-squre method; + 'WHITE_BALANCE': white balance method; + type: enum INITIAL_METHOD_TYPE; + max_count, epsilon : + used in MinProblemSolver-DownhillSolver; + Terminal criteria to the algorithm; + type: int, double; + default: 5000, 1e-4; + --------------------------------------------------- + Supported Color Space: + Supported list of RGB color spaces: + sRGB; + AdobeRGB; + WideGamutRGB; + ProPhotoRGB; + DCI_P3_RGB; + AppleRGB; + REC_709_RGB; + REC_2020_RGB; + Supported list of linear RGB color spaces: + sRGBL; + AdobeRGBL; + WideGamutRGBL; + ProPhotoRGBL; + DCI_P3_RGBL; + AppleRGBL; + REC_709_RGBL; + REC_2020_RGBL; + Supported list of non-RGB color spaces: + Lab_D50_2; + Lab_D65_2; + XYZ_D50_2; + XYZ_D65_2; + Supported IO (You can use Lab(io) or XYZ(io) to create color space): + A_2; + A_10; + D50_2; + D50_10; + D55_2; + D55_10; + D65_2; + D65_10; + D75_2; + D75_10; + E_2; + E_10; + --------------------------------------------------- + Abbr. + src, s: source; + dst, d: destination; + io: illuminant & observer; + sio, dio: source of io; destination of io; + rgbl: linear RGB + cs: color space; + cc: Colorchecker; + M, m: matrix + ccm: color correction matrix; + cam: chromatic adaption matrix; +*/ + + +/* *\ brief Enum of the possible types of ccm. +*/ +enum CCM_TYPE +{ + CCM_3x3, + CCM_4x3 +}; + +/* *\ brief Enum of the possible types of initial method. +*/ +enum INITIAL_METHOD_TYPE +{ + WHITE_BALANCE, + LEAST_SQUARE +}; + + +/* *\ brief Core class of ccm model. + * produce a ColorCorrectionModel instance for inference. +*/ +class ColorCorrectionModel +{ +public: + // detected colors, the referenceand the RGB colorspace for conversion + cv::Mat src; + Color dst; + + RGBBase_& cs; + cv::Mat mask; + + // ccm type and shape + CCM_TYPE ccm_type; + int shape; + + // linear method and distance + std::shared_ptr linear; + DISTANCE_TYPE distance; + + cv::Mat weights; + cv::Mat ccm; + cv::Mat ccm0; + double loss; + + int max_count; + double epsilon; + + ColorCorrectionModel(cv::Mat src_, cv::Mat colors_, const ColorSpace& ref_cs_, RGBBase_& cs_=sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, cv::Mat weights_list = Mat(), double weights_coeff = 0, + INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4) : + ColorCorrectionModel(src_, Color(colors_, ref_cs_), cs_, ccm_type_, distance_, linear_type, + gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} + + ColorCorrectionModel(cv::Mat src_, Color dst_, RGBBase_& cs_= sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, cv::Mat weights_list = Mat(), double weights_coeff = 0, + INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4) : + src(src_), dst(dst_), cs(cs_), ccm_type(ccm_type_), distance(distance_), max_count(max_count_), epsilon(epsilon_) + { + cv::Mat saturate_mask = saturate(src, saturated_threshold[0], saturated_threshold[1]); + this->linear = getLinear(gamma, deg, this->src, this->dst, saturate_mask, this->cs, linear_type); + calWeightsMasks(weights_list, weights_coeff, saturate_mask); + + src_rgbl = this->linear->linearize(maskCopyTo(this->src, mask)); + dst.colors = maskCopyTo(dst.colors, mask); + dst_rgbl =this->dst.to(*(this->cs.l)).colors; + + // make no change for CCM_3x3, make change for CCM_4x3. + src_rgbl = prepare(src_rgbl); + + + // distance function may affect the loss function and the fitting function + switch (this->distance) + { + case cv::ccm::RGBL: + initialLeastSquare(true); + break; + default: + switch (initial_method_type) + { + case cv::ccm::WHITE_BALANCE: + initialWhiteBalance(); + break; + case cv::ccm::LEAST_SQUARE: + initialLeastSquare(); + break; + default: + throw std::invalid_argument{ "Wrong initial_methoddistance_type!" }; + break; + } + break; + } + + fitting(); + } + + /* *\ brief Make no change for CCM_3x3. + * convert cv::Mat A to [A, 1] in CCM_4x3. + *\ param inp the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat + */ + cv::Mat prepare(const cv::Mat& inp) + { + switch (ccm_type) + { + case cv::ccm::CCM_3x3: + shape = 9; + return inp; + case cv::ccm::CCM_4x3: + { + shape = 12; + cv::Mat arr1 = cv::Mat::ones(inp.size(), CV_64F); + cv::Mat arr_out(inp.size(), CV_64FC4); + cv::Mat arr_channels[3]; + split(inp, arr_channels); + merge(std::vector{arr_channels[0], arr_channels[1], arr_channels[2], arr1}, arr_out); + return arr_out; + } + default: + throw std::invalid_argument{ "Wrong ccm_type!" }; + break; + } + }; + + /* *\ brief Fitting nonlinear - optimization initial value by white balance. + * see CCM.pdf for details. + *\ return the output array, type of cv::Mat + */ + cv::Mat initialWhiteBalance(void) + { + cv::Mat schannels[3]; + split(src_rgbl, schannels); + cv::Mat dchannels[3]; + split(dst_rgbl, dchannels); + std::vector initial_vec = { sum(dchannels[0])[0] / sum(schannels[0])[0], 0, 0, 0, + sum(dchannels[1])[0] / sum(schannels[1])[0], 0, 0, 0, + sum(dchannels[2])[0] / sum(schannels[2])[0], 0, 0, 0 }; + std::vector initial_vec_(initial_vec.begin(), initial_vec.begin() + shape); + cv::Mat initial_white_balance = cv::Mat(initial_vec_, true).reshape(0, shape / 3); + + return initial_white_balance; + }; + + /* *\ brief Fitting nonlinear-optimization initial value by least square. + * see CCM.pdf for details + *\ param fit if fit is True, return optimalization for rgbl distance function. + */ + void initialLeastSquare(bool fit = false) + { + cv::Mat A, B, w; + if (weights.empty()) + { + A = src_rgbl; + B = dst_rgbl; + } + else + { + pow(weights, 0.5, w); + cv::Mat w_; + merge(std::vector{w, w, w}, w_); + A = w_.mul(src_rgbl); + B = w_.mul(dst_rgbl); + } + solve(A.reshape(1, A.rows), B.reshape(1, B.rows), ccm0, DECOMP_SVD); + + // if fit is True, return optimalization for rgbl distance function. + if (fit) + { + ccm = ccm0; + cv::Mat residual = A.reshape(1, A.rows) * ccm.reshape(0, shape / 3) - B.reshape(1, B.rows); + Scalar s = residual.dot(residual); + double sum = s[0]; + loss = sqrt(sum / masked_len); + } + }; + + /* *\ brief Loss function base on cv::MinProblemSolver::Function. + * see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp + */ + class LossFunction : public cv::MinProblemSolver::Function + { + public: + ColorCorrectionModel* ccm_loss; + LossFunction(ColorCorrectionModel* ccm) : ccm_loss(ccm) {}; + + /* *\ brief Reset dims to ccm->shape. + */ + int getDims() const CV_OVERRIDE + { + return ccm_loss->shape; + } + + /* *\ brief Reset calculation. + */ + double calc(const double* x) const CV_OVERRIDE + { + cv::Mat ccm_(ccm_loss->shape, 1, CV_64F); + for (int i = 0; i < ccm_loss->shape; i++) + { + ccm_.at(i, 0) = x[i]; + } + ccm_ = ccm_.reshape(0, ccm_loss->shape / 3); + return ccm_loss->calc_loss(ccm_); + } + }; + + double calc_loss_(Color color) + { + cv::Mat distlist = color.diff(dst, distance); + Color lab = color.to(Lab_D50_2); + cv::Mat dist_; + pow(distlist, 2, dist_); + if (!weights.empty()) + { + dist_ = weights.mul(dist_); + } + Scalar ss = sum(dist_); + return ss[0]; + } + + double calc_loss(const Mat ccm_) + { + Mat converted = src_rgbl.reshape(1, 0) * ccm_; + Color color(converted.reshape(3, 0), *(cs.l)); + return calc_loss_(color); + } + + /* *\ brief Fitting ccm if distance function is associated with CIE Lab color space. + * see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp + * Set terminal criteria for solver is possible. + */ + void fitting(void) + { + cv::Ptr solver = cv::DownhillSolver::create(); + cv::Ptr ptr_F(new LossFunction(this)); + solver->setFunction(ptr_F); + cv::Mat reshapeccm = ccm0.clone().reshape(0, 1); + cv::Mat step = cv::Mat::ones(reshapeccm.size(), CV_64F); + solver->setInitStep(step); + TermCriteria termcrit = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, max_count, epsilon); + solver->setTermCriteria(termcrit); + double res = solver->minimize(reshapeccm); + ccm = reshapeccm.reshape(0, shape/3); + loss = pow((res / masked_len), 0.5); + std::cout << " ccm " << ccm << std::endl; + std::cout << " loss " << loss << std::endl; + }; + + /* *\ brief Infer using fitting ccm. + *\ param img the input image, type of cv::Mat. + *\ return the output array, type of cv::Mat. + */ + cv::Mat infer(const cv::Mat& img, bool islinear = false) + { + if (!ccm.data) + { + throw "No CCM values!"; + } + cv::Mat img_lin = linear->linearize(img); + cv::Mat img_ccm(img_lin.size(), img_lin.type()); + cv::Mat ccm_ = ccm.reshape(0, shape / 3); + img_ccm = multiple(prepare(img_lin), ccm_); + if (islinear == true) + { + return img_ccm; + } + return cs.fromL(img_ccm); + }; + + /* *\ brief Infer image and output as an BGR image with uint8 type. + * mainly for test or debug. + * input size and output size should be 255. + *\ param imgfile path name of image to infer. + *\ param islinear if linearize or not. + *\ return the output array, type of cv::Mat. + */ + cv::Mat inferImage(std::string imgfile, bool islinear = false) + { + const int inp_size = 255; + const int out_size = 255; + cv::Mat img = imread(imgfile); + cv::Mat img_; + cvtColor(img, img_, COLOR_BGR2RGB); + img_.convertTo(img_, CV_64F); + img_ = img_ / inp_size; + cv::Mat out = this->infer(img_, islinear); + cv::Mat out_ = out * out_size; + out_.convertTo(out_, CV_8UC3); + cv::Mat img_out = min(max(out_, 0), out_size); + cv::Mat out_img; + cvtColor(img_out, out_img, COLOR_RGB2BGR); + return out_img; + }; + + // void report() { + // std::cout << "CCM0: " << ccm0 << std::endl; + // std::cout << "CCM: " << ccm << std::endl; + // std::cout << "Loss: " << loss << std::endl; + // } + +private: + cv::Mat dist; + int masked_len; + + // RGBl of detected data and the reference + cv::Mat src_rgbl; + cv::Mat dst_rgbl; + + /* *\ brief Calculate weights and mask. + *\ param weights_list the input array, type of cv::Mat. + *\ param weights_coeff type of double. + *\ param saturate_list the input array, type of cv::Mat. + */ + void calWeightsMasks(cv::Mat weights_list, double weights_coeff, cv::Mat saturate_mask) + { + // weights + if (!weights_list.empty()) + { + weights = weights_list; + } + else if (weights_coeff != 0) + { + pow(dst.toLuminant(dst.cs.io), weights_coeff, weights); + } + + // masks + cv::Mat weight_mask = cv::Mat::ones(src.rows, 1, CV_8U); + if (!weights.empty()) + { + weight_mask = weights > 0; + } + this->mask = (weight_mask) & (saturate_mask); + + // weights' mask + if (!weights.empty()) + { + cv::Mat weights_masked = maskCopyTo(this->weights, this->mask); + weights = weights_masked / mean(weights_masked)[0]; + } + masked_len = (int)sum(mask)[0]; + }; +}; + +} // namespace ccm +} // namespace cv + + +#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/color.hpp b/modules/mcc/include/opencv2/mcc/color.hpp new file mode 100644 index 00000000000..1b542e5d45f --- /dev/null +++ b/modules/mcc/include/opencv2/mcc/color.hpp @@ -0,0 +1,285 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#ifndef __OPENCV_MCC_COLOR_HPP__ +#define __OPENCV_MCC_COLOR_HPP__ + +#include +#include "opencv2/mcc/colorspace.hpp" +#include "opencv2/mcc/distance.hpp" + +namespace cv +{ +namespace ccm +{ + +/* *\ brief Color defined by color_values and color space +*/ + +class Color +{ +public: + + /* *\ param grays mask of grayscale color + *\ param colored mask of colored color + *\ param history storage of historical conversion + */ + cv::Mat colors; + const ColorSpace& cs; + cv::Mat grays; + cv::Mat colored; + std::map> history; + + Color(cv::Mat colors_, const ColorSpace& cs_, cv::Mat colored_) : colors(colors_), cs(cs_), colored(colored_) + { + grays= ~colored; + } + Color(cv::Mat colors_, const ColorSpace& cs_) :colors(colors_), cs(cs_) {}; + + virtual ~Color() {}; + + /* *\ brief Change to other color space. + * The conversion process incorporates linear transformations to speed up. + * method is chromatic adapation method. + * when save if True, get data from history first. + *\ param other type of ColorSpace. + *\ return Color. + */ + Color to(const ColorSpace& other, CAM method = BRADFORD, bool save = true) + { + if (history.count(other) == 1) + { + + return *history[other]; + } + if (cs.relate(other)) + { + return Color(cs.relation(other).run(colors), other); + } + Operations ops; + ops.add(cs.to).add(XYZ(cs.io).cam(other.io, method)).add(other.from); + std::shared_ptr color(new Color(ops.run(colors), other)); + if (save) + { + history[other] = color; + } + return *color; + } + + /* *\ brief Channels split. + *\ return each channel. + */ + cv::Mat channel(cv::Mat m, int i) + { + cv::Mat dchannels[3]; + split(m, dchannels); + return dchannels[i]; + } + + /* *\ brief To Gray. + */ + cv::Mat toGray(IO io, CAM method = BRADFORD, bool save = true) + { + XYZ xyz(io); + return channel(this->to(xyz, method, save).colors, 1); + } + + /* *\ brief To Luminant. + */ + cv::Mat toLuminant(IO io, CAM method = BRADFORD, bool save = true) + { + Lab lab(io); + return channel(this->to(lab, method, save).colors, 0); + } + + /* *\ brief Diff without IO. + *\ param other type of Color. + *\ param method type of distance. + *\ return distance between self and other + */ + cv::Mat diff(Color& other, DISTANCE_TYPE method = CIE2000) + { + return diff(other, cs.io, method); + } + + /* *\ brief Diff with IO. + *\ param other type of Color. + *\ param io type of IO. + *\ param method type of distance. + *\ return distance between self and other + */ + cv::Mat diff(Color& other, IO io, DISTANCE_TYPE method = CIE2000) + { + Lab lab(io); + switch (method) + { + case cv::ccm::CIE76: + case cv::ccm::CIE94_GRAPHIC_ARTS: + case cv::ccm::CIE94_TEXTILES: + case cv::ccm::CIE2000: + case cv::ccm::CMC_1TO1: + case cv::ccm::CMC_2TO1: + return distance(to(lab).colors, other.to(lab).colors, method); + case cv::ccm::RGB: + return distance(to(*cs.nl).colors, other.to(*cs.nl).colors, method); + case cv::ccm::RGBL: + return distance(to(*cs.l).colors, other.to(*cs.l).colors, method); + default: + throw std::invalid_argument{ "Wrong method!" }; + break; + } + } + + /* *\ brief Calculate gray mask. + */ + void getGray(double JDN = 2.0) + { + if (!grays.empty()) { + return; + } + cv::Mat lab = to(Lab_D65_2).colors; + cv::Mat gray(colors.size(), colors.type()); + int fromto[] = { 0,0, -1,1, -1,2 }; + mixChannels(&lab, 1, &gray, 1, fromto, 3); + cv::Mat d = distance(lab, gray, CIE2000); + this->grays = d < JDN; + this->colored = ~grays; + } + + /* *\ brief Operator for mask copy. + */ + Color operator[](cv::Mat mask) + { + return Color(maskCopyTo(colors, mask), cs); + } + + +}; + + +/* *\ brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls + * see Miscellaneous.md for details. +*/ +const cv::Mat ColorChecker2005_LAB_D50_2 = (cv::Mat_(24, 1) << + cv::Vec3d(37.986, 13.555, 14.059), + cv::Vec3d(65.711, 18.13, 17.81), + cv::Vec3d(49.927, -4.88, -21.925), + cv::Vec3d(43.139, -13.095, 21.905), + cv::Vec3d(55.112, 8.844, -25.399), + cv::Vec3d(70.719, -33.397, -0.199), + cv::Vec3d(62.661, 36.067, 57.096), + cv::Vec3d(40.02, 10.41, -45.964), + cv::Vec3d(51.124, 48.239, 16.248), + cv::Vec3d(30.325, 22.976, -21.587), + cv::Vec3d(72.532, -23.709, 57.255), + cv::Vec3d(71.941, 19.363, 67.857), + cv::Vec3d(28.778, 14.179, -50.297), + cv::Vec3d(55.261, -38.342, 31.37), + cv::Vec3d(42.101, 53.378, 28.19), + cv::Vec3d(81.733, 4.039, 79.819), + cv::Vec3d(51.935, 49.986, -14.574), + cv::Vec3d(51.038, -28.631, -28.638), + cv::Vec3d(96.539, -0.425, 1.186), + cv::Vec3d(81.257, -0.638, -0.335), + cv::Vec3d(66.766, -0.734, -0.504), + cv::Vec3d(50.867, -0.153, -0.27), + cv::Vec3d(35.656, -0.421, -1.231), + cv::Vec3d(20.461, -0.079, -0.973)); + +const cv::Mat ColorChecker2005_LAB_D65_2 = (cv::Mat_(24, 1) << + cv::Vec3d(37.542, 12.018, 13.33), + cv::Vec3d(65.2, 14.821, 17.545), + cv::Vec3d(50.366, -1.573, -21.431), + cv::Vec3d(43.125, -14.63, 22.12), + cv::Vec3d(55.343, 11.449, -25.289), + cv::Vec3d(71.36, -32.718, 1.636), + cv::Vec3d(61.365, 32.885, 55.155), + cv::Vec3d(40.712, 16.908, -45.085), + cv::Vec3d(49.86, 45.934, 13.876), + cv::Vec3d(30.15, 24.915, -22.606), + cv::Vec3d(72.438, -27.464, 58.469), + cv::Vec3d(70.916, 15.583, 66.543), + cv::Vec3d(29.624, 21.425, -49.031), + cv::Vec3d(55.643, -40.76, 33.274), + cv::Vec3d(40.554, 49.972, 25.46), + cv::Vec3d(80.982, -1.037, 80.03), + cv::Vec3d(51.006, 49.876, -16.93), + cv::Vec3d(52.121, -24.61, -26.176), + cv::Vec3d(96.536, -0.694, 1.354), + cv::Vec3d(81.274, -0.61, -0.24), + cv::Vec3d(66.787, -0.647, -0.429), + cv::Vec3d(50.872, -0.059, -0.247), + cv::Vec3d(35.68, -0.22, -1.205), + cv::Vec3d(20.475, 0.049, -0.972)); + +const cv::Mat ColorChecker2005_COLORED_MASK = (cv::Mat_(24, 1) << + 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0); + +const cv::Mat Vinyl_LAB_D50_2 = (Mat_(18, 1) << + Vec3d(1.00000000e+02, 5.20000001e-03, -1.04000000e-02), + Vec3d(7.30833969e+01, -8.19999993e-01, -2.02099991e+00), + Vec3d(6.24930000e+01, 4.25999999e-01, -2.23099995e+00), + Vec3d(5.04640007e+01, 4.46999997e-01, -2.32399988e+00), + Vec3d(3.77970009e+01, 3.59999985e-02, -1.29700005e+00), + Vec3d(0.00000000e+00, 0.00000000e+00, 0.00000000e+00), + Vec3d(5.15880013e+01, 7.35179977e+01, 5.15690002e+01), + Vec3d(9.36989975e+01, -1.57340002e+01, 9.19420013e+01), + Vec3d(6.94079971e+01, -4.65940018e+01, 5.04869995e+01), + Vec3d(6.66100006e+01, -1.36789999e+01, -4.31720009e+01), + Vec3d(1.17110004e+01, 1.69799995e+01, -3.71759987e+01), + Vec3d(5.19739990e+01, 8.19440002e+01, -8.40699959e+00), + Vec3d(4.05489998e+01, 5.04399986e+01, 2.48490009e+01), + Vec3d(6.08160019e+01, 2.60690002e+01, 4.94420013e+01), + Vec3d(5.22529984e+01, -1.99500008e+01, -2.39960003e+01), + Vec3d(5.12859993e+01, 4.84700012e+01, -1.50579996e+01), + Vec3d(6.87070007e+01, 1.22959995e+01, 1.62129993e+01), + Vec3d(6.36839981e+01, 1.02930002e+01, 1.67639999e+01)); + +const cv::Mat Vinyl_COLORED_MASK = (cv::Mat_(18, 1) << + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1); + +/* *\ brief Macbeth ColorChecker with 2deg D50. +*/ +Color Macbeth_D50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2, ColorChecker2005_COLORED_MASK); + +/* *\ brief Macbeth ColorChecker with 2deg D65. +*/ +Color Macbeth_D65_2(ColorChecker2005_LAB_D65_2, Lab_D65_2, ColorChecker2005_COLORED_MASK); + +Color Vinyl_D50_2(Vinyl_LAB_D50_2, Lab_D50_2, Vinyl_COLORED_MASK); + + +} // namespace ccm +} // namespace cv + + +#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp new file mode 100644 index 00000000000..9742344c365 --- /dev/null +++ b/modules/mcc/include/opencv2/mcc/colorspace.hpp @@ -0,0 +1,635 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#ifndef __OPENCV_MCC_COLORSPACE_HPP__ +#define __OPENCV_MCC_COLORSPACE_HPP__ + +#include +#include +#include +#include "opencv2/mcc/io.hpp" +#include "opencv2/mcc/operations.hpp" +#include "opencv2/mcc/utils.hpp" + +namespace cv +{ +namespace ccm +{ +/* *\ brief Basic class for ColorSpace. +*/ +class ColorSpace +{ +public: + IO io; + std::string type; + bool linear; + Operations to; + Operations from; + ColorSpace* l; + ColorSpace* nl; + + ColorSpace() {}; + + ColorSpace(IO io_, std::string type_, bool linear_) :io(io_), type(type_), linear(linear_) {}; + + virtual ~ColorSpace() + { + l = 0; + nl = 0; + }; + + virtual bool relate(const ColorSpace& other) const + { + return (type == other.type) && (io == other.io); + }; + + virtual Operations relation(const ColorSpace& /*other*/) const + { + return IDENTITY_OPS; + }; + + bool operator<(const ColorSpace& other)const + { + return (io < other.io || (io == other.io && type < other.type) || (io == other.io && type == other.type && linear < other.linear)); + } +}; + +/* *\ brief Base of RGB color space; + * the argument values are from AdobeRGB; + * Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space +*/ +class RGBBase_ : public ColorSpace +{ +public: + // primaries + double xr; + double yr; + double xg; + double yg; + double xb; + double yb; + MatFunc toL; + MatFunc fromL; + cv::Mat M_to; + cv::Mat M_from; + + using ColorSpace::ColorSpace; + + /* *\ brief There are 3 kinds of relationships for RGB: + * 1. Different types; - no operation + * 1. Same type, same linear; - copy + * 2. Same type, different linear, self is nonlinear; - 2 toL + * 3. Same type, different linear, self is linear - 3 fromL + *\ param other type of ColorSpace. + *\ return Operations. + */ + Operations relation(const ColorSpace& other) const CV_OVERRIDE + { + if (linear == other.linear) + { + return IDENTITY_OPS; + } + if (linear) + { + return Operations({ Operation(fromL) }); + } + return Operations({ Operation(toL) }); + }; + + /* *\ brief Initial operations. + */ + void init() + { + setParameter(); + calLinear(); + calM(); + calOperations(); + } + + /* *\ brief Produce color space instance with linear and non-linear versions. + *\ param rgbl type of RGBBase_. + */ + void bind(RGBBase_& rgbl) + { + init(); + rgbl.init(); + l = &rgbl; + rgbl.l = &rgbl; + nl = this; + rgbl.nl = this; + } + +private: + virtual void setParameter() {}; + + /* *\ brief Calculation of M_RGBL2XYZ_base. + * see ColorSpace.pdf for details. + */ + virtual void calM() + { + cv::Mat XYZr, XYZg, XYZb, XYZ_rgbl, Srgb; + XYZr = cv::Mat(xyY2XYZ({ xr, yr }), true); + XYZg = cv::Mat(xyY2XYZ({ xg, yg }), true); + XYZb = cv::Mat(xyY2XYZ({ xb, yb }), true); + merge(std::vector{ XYZr, XYZg, XYZb }, XYZ_rgbl); + XYZ_rgbl = XYZ_rgbl.reshape(1, XYZ_rgbl.rows); + cv::Mat XYZw = cv::Mat(illuminants.find(io)->second, true); + solve(XYZ_rgbl, XYZw, Srgb); + merge(std::vector{ Srgb.at(0)* XYZr, + Srgb.at(1)* XYZg, + Srgb.at(2)* XYZb }, M_to); + M_to = M_to.reshape(1, M_to.rows); + M_from = M_to.inv(); + }; + + /* *\ brief operations to or from XYZ. + */ + virtual void calOperations() + { + // rgb -> rgbl + toL = [this](cv::Mat rgb)->cv::Mat {return toLFunc(rgb); }; + + // rgbl -> rgb + fromL = [this](cv::Mat rgbl)->cv::Mat {return fromLFunc(rgbl); }; + + if (linear) + { + to = Operations({ Operation(M_to.t()) }); + from = Operations({ Operation(M_from.t()) }); + } + else + { + to = Operations({ Operation(toL), Operation(M_to.t()) }); + from = Operations({ Operation(M_from.t()), Operation(fromL) }); + } + } + + virtual void calLinear() {} + + virtual cv::Mat toLFunc(cv::Mat& /*rgb*/) + { + return cv::Mat(); + }; + + virtual cv::Mat fromLFunc(cv::Mat& /*rgbl*/) + { + return cv::Mat(); + }; + +}; + +/* *\ brief Base of Adobe RGB color space; +*/ +class AdobeRGBBase_ : public RGBBase_ +{ +public: + using RGBBase_::RGBBase_; + double gamma; + +private: + cv::Mat toLFunc(cv::Mat& rgb) CV_OVERRIDE + { + return gammaCorrection(rgb, gamma); + } + + cv::Mat fromLFunc(cv::Mat& rgbl) CV_OVERRIDE + { + return gammaCorrection(rgbl, 1. / gamma); + } +}; + +/* *\ brief Base of sRGB color space; +*/ +class sRGBBase_ : public RGBBase_ +{ +public: + using RGBBase_::RGBBase_; + double a; + double gamma; + double alpha; + double beta; + double phi; + double K0; + +private: + /* *\ brief linearization parameters + * see ColorSpace.pdf for details; + */ + virtual void calLinear() CV_OVERRIDE + { + alpha = a + 1; + K0 = a / (gamma - 1); + phi = (pow(alpha, gamma) * pow(gamma - 1, gamma - 1)) / (pow(a, gamma - 1) * pow(gamma, gamma)); + beta = K0 / phi; + } + + /* *\ brief Used by toLFunc. + */ + double toLFuncEW(double& x) + { + if (x > K0) + { + return pow(((x + alpha - 1) / alpha), gamma); + } + else if (x >= -K0) + { + return x / phi; + } + else + { + return -(pow(((-x + alpha - 1) / alpha), gamma)); + } + } + + /* *\ brief Linearization. + * see ColorSpace.pdf for details. + *\ param rgb the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat. + */ + cv::Mat toLFunc(cv::Mat& rgb) CV_OVERRIDE + { + return elementWise(rgb, [this](double a_)->double {return toLFuncEW(a_); }); + } + + /* *\ brief Used by fromLFunc. + */ + double fromLFuncEW(double& x) + { + if (x > beta) + { + return alpha * pow(x, 1 / gamma) - (alpha - 1); + } + else if (x >= -beta) + { + return x * phi; + } + else + { + return -(alpha * pow(-x, 1 / gamma) - (alpha - 1)); + } + } + + /* *\ brief Delinearization. + * see ColorSpace.pdf for details. + *\ param rgbl the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat. + */ + cv::Mat fromLFunc(cv::Mat& rgbl) CV_OVERRIDE + { + return elementWise(rgbl, [this](double a_)->double {return fromLFuncEW(a_); }); + } +}; + +/* *\ brief sRGB color space. + * data from https://en.wikipedia.org/wiki/SRGB. +*/ +class sRGB_ :public sRGBBase_ +{ +public: + sRGB_(bool linear_) :sRGBBase_(D65_2, "sRGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE + { + xr = 0.64; + yr = 0.33; + xg = 0.3; + yg = 0.6; + xb = 0.15; + yb = 0.06; + a = 0.055; + gamma = 2.4; + } +}; + +/* *\ brief Adobe RGB color space. +*/ +class AdobeRGB_ : public AdobeRGBBase_ +{ +public: + AdobeRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AdobeRGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE + { + xr = 0.64; + yr = 0.33; + xg = 0.21; + yg = 0.71; + xb = 0.15; + yb = 0.06; + gamma = 2.2; + } +}; + +/* *\ brief Wide-gamut RGB color space. + * data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. +*/ +class WideGamutRGB_ : public AdobeRGBBase_ +{ +public: + WideGamutRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "WideGamutRGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE + { + xr = 0.7347; + yr = 0.2653; + xg = 0.1152; + yg = 0.8264; + xb = 0.1566; + yb = 0.0177; + gamma = 2.2; + } +}; + +/* *\ brief ProPhoto RGB color space. + * data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. +*/ +class ProPhotoRGB_ : public AdobeRGBBase_ +{ +public: + ProPhotoRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "ProPhotoRGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE + { + xr = 0.734699; + yr = 0.265301; + xg = 0.159597; + yg = 0.840403; + xb = 0.036598; + yb = 0.000105; + gamma = 1.8; + } +}; + +/* *\ brief DCI-P3 RGB color space. + * data from https://en.wikipedia.org/wiki/DCI-P3. +*/ +class DCI_P3_RGB_ : public AdobeRGBBase_ +{ +public: + DCI_P3_RGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "DCI_P3_RGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE + { + xr = 0.68; + yr = 0.32; + xg = 0.265; + yg = 0.69; + xb = 0.15; + yb = 0.06; + gamma = 2.2; + } +}; + +/* *\ brief Apple RGB color space. + * data from http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. +*/ +class AppleRGB_ : public AdobeRGBBase_ +{ +public: + AppleRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AppleRGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE + { + xr = 0.625; + yr = 0.34; + xg = 0.28; + yg = 0.595; + xb = 0.155; + yb = 0.07; + gamma = 1.8; + } +}; + +/* *\ brief REC_709 RGB color space. + * data from https://en.wikipedia.org/wiki/Rec._709. +*/ +class REC_709_RGB_ : public sRGBBase_ +{ +public: + REC_709_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_709_RGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE + { + xr = 0.64; + yr = 0.33; + xg = 0.3; + yg = 0.6; + xb = 0.15; + yb = 0.06; + a = 0.099; + gamma = 1 / 0.45; + } +}; + +/* *\ brief REC_2020 RGB color space. + * data from https://en.wikipedia.org/wiki/Rec._2020. +*/ +class REC_2020_RGB_ : public sRGBBase_ +{ +public: + REC_2020_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_2020_RGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE + { + xr = 0.708; + yr = 0.292; + xg = 0.17; + yg = 0.797; + xb = 0.131; + yb = 0.046; + a = 0.09929682680944; + gamma = 1 / 0.45; + } +}; + + +sRGB_ sRGB(false), sRGBL(true); +AdobeRGB_ AdobeRGB(false), AdobeRGBL(true); +WideGamutRGB_ WideGamutRGB(false), WideGamutRGBL(true); +ProPhotoRGB_ ProPhotoRGB(false), ProPhotoRGBL(true); +DCI_P3_RGB_ DCI_P3_RGB(false), DCI_P3_RGBL(true); +AppleRGB_ AppleRGB(false), AppleRGBL(true); +REC_709_RGB_ REC_709_RGB(false), REC_709_RGBL(true); +REC_2020_RGB_ REC_2020_RGB(false), REC_2020_RGBL(true); + +/* *\ brief Bind RGB with RGBL. +*/ +class ColorSpaceInitial +{ +public: + ColorSpaceInitial() + { + sRGB.bind(sRGBL); + AdobeRGB.bind(AdobeRGBL); + WideGamutRGB.bind(WideGamutRGBL); + ProPhotoRGB.bind(ProPhotoRGBL); + DCI_P3_RGB.bind(DCI_P3_RGBL); + AppleRGB.bind(AppleRGBL); + REC_709_RGB.bind(REC_709_RGBL); + REC_2020_RGB.bind(REC_2020_RGBL); + + } +}; + +ColorSpaceInitial color_space_initial; + + +/* *\ brief Enum of the possible types of CAMs. +*/ +enum CAM +{ + IDENTITY, + VON_KRIES, + BRADFORD +}; + +static std::map , cv::Mat > cams; +const static cv::Mat Von_Kries = (cv::Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); +const static cv::Mat Bradford = (cv::Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); +const static std::map > MAs = { + {IDENTITY , { cv::Mat::eye(cv::Size(3,3),CV_64FC1) , cv::Mat::eye(cv::Size(3,3),CV_64FC1)} }, + {VON_KRIES, { Von_Kries ,Von_Kries.inv() }}, + {BRADFORD, { Bradford ,Bradford.inv() }} +}; + +/* *\ brief XYZ color space. + * Chromatic adaption matrices. +*/ +class XYZ :public ColorSpace +{ +public: + XYZ(IO io_) : ColorSpace(io_, "XYZ", true) {}; + Operations cam(IO dio, CAM method = BRADFORD) + { + return (io == dio) ? Operations() : Operations({ Operation(cam_(io, dio, method).t()) }); + } + +private: + /* *\ brief Get cam. + *\ param sio the input IO of src. + *\ param dio the input IO of dst. + *\ param method type of CAM. + *\ return the output array, type of cv::Mat. + */ + cv::Mat cam_(IO sio, IO dio, CAM method = BRADFORD) const + { + if (sio == dio) + { + return cv::Mat::eye(cv::Size(3, 3), CV_64FC1); + } + if (cams.count(std::make_tuple(dio, sio, method)) == 1) + { + return cams[std::make_tuple(dio, sio, method)]; + } + + // Function from http ://www.brucelindbloom.com/index.html?ColorCheckerRGB.html. + cv::Mat XYZws = cv::Mat(illuminants.find(dio)->second); + cv::Mat XYZWd = cv::Mat(illuminants.find(sio)->second); + cv::Mat MA = MAs.at(method)[0]; + cv::Mat MA_inv = MAs.at(method)[1]; + cv::Mat M = MA_inv * cv::Mat::diag((MA * XYZws) / (MA * XYZWd)) * MA; + cams[std::make_tuple(dio, sio, method)] = M; + cams[std::make_tuple(sio, dio, method)] = M.inv(); + return M; + } +}; + +/* *\ brief Define XYZ_D65_2 and XYZ_D50_2. +*/ +const XYZ XYZ_D65_2(D65_2); +const XYZ XYZ_D50_2(D50_2); + + +/* *\ brief Lab color space. +*/ +class Lab :public ColorSpace +{ +public: + Lab(IO io_) : ColorSpace(io_, "Lab", true) + { + to = { Operation([this](cv::Mat src)->cv::Mat {return tosrc(src); }) }; + from = { Operation([this](cv::Mat src)->cv::Mat {return fromsrc(src); }) }; + } + +private: + static constexpr double delta = (6. / 29.); + static constexpr double m = 1. / (3. * delta * delta); + static constexpr double t0 = delta * delta * delta; + static constexpr double c = 4. / 29.; + + cv::Vec3d fromxyz(cv::Vec3d& xyz) + { + double x = xyz[0] / illuminants.find(io)->second[0], y = xyz[1] / illuminants.find(io)->second[1], z = xyz[2] / illuminants.find(io)->second[2]; + auto f = [](double t)->double { return t > t0 ? std::cbrt(t) : (m * t + c); }; + double fx = f(x), fy = f(y), fz = f(z); + return { 116. * fy - 16. ,500 * (fx - fy),200 * (fy - fz) }; + } + + /* *\ brief Calculate From. + *\ param src the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat + */ + cv::Mat fromsrc(cv::Mat& src) + { + return channelWise(src, [this](cv::Vec3d a)->cv::Vec3d {return fromxyz(a); }); + } + + cv::Vec3d tolab(cv::Vec3d& lab) + { + auto f_inv = [](double t)->double {return t > delta ? pow(t, 3.0) : (t - c) / m; }; + double L = (lab[0] + 16.) / 116., a = lab[1] / 500., b = lab[2] / 200.; + return { illuminants.find(io)->second[0] * f_inv(L + a),illuminants.find(io)->second[1] * f_inv(L),illuminants.find(io)->second[2] * f_inv(L - b) }; + } + + /* *\ brief Calculate To. + *\ param src the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat + */ + cv::Mat tosrc(cv::Mat& src) + { + return channelWise(src, [this](cv::Vec3d a)->cv::Vec3d {return tolab(a); }); + } +}; + +/* *\ brief Define Lab_D65_2 and Lab_D50_2. +*/ +const Lab Lab_D65_2(D65_2); +const Lab Lab_D50_2(D50_2); + +} // namespace ccm +} // namespace cv + + +#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/linearize.hpp b/modules/mcc/include/opencv2/mcc/linearize.hpp new file mode 100644 index 00000000000..3dff3b87572 --- /dev/null +++ b/modules/mcc/include/opencv2/mcc/linearize.hpp @@ -0,0 +1,304 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#ifndef __OPENCV_MCC_LINEARIZE_HPP__ +#define __OPENCV_MCC_LINEARIZE_HPP__ + +#include "opencv2/mcc/color.hpp" + +namespace cv +{ +namespace ccm +{ + +/* *\ brief Enum of the possible types of linearization. +*/ +enum LINEAR_TYPE +{ + IDENTITY_, + GAMMA, + COLORPOLYFIT, + COLORLOGPOLYFIT, + GRAYPOLYFIT, + GRAYLOGPOLYFIT +}; + +/* *\ brief Polyfit model. +*/ +class Polyfit +{ +public: + int deg; + cv::Mat p; + + Polyfit() {}; + + /* *\ brief Polyfit method. + https://en.wikipedia.org/wiki/Polynomial_regression + polynomial: yi = a0 + a1*xi + a2*xi^2 + ... + an*xi^deg (i = 1,2,...,n) + and deduct: Ax = y + See linear.pdf for details + */ + Polyfit(cv::Mat x, cv::Mat y, int deg_) :deg(deg_) + { + int n = x.cols * x.rows * x.channels(); + x = x.reshape(1, n); + y = y.reshape(1, n); + cv::Mat_ A = cv::Mat_::ones(n, deg + 1); + for (int i = 0; i < n; ++i) + { + for (int j = 1; j < A.cols; ++j) + { + A.at(i, j) = x.at(i) * A.at(i, j - 1); + } + } + cv::Mat y_(y); + cv::solve(A, y_, p, DECOMP_SVD); + } + + virtual ~Polyfit() {}; + cv::Mat operator()(const cv::Mat& inp) + { + return elementWise(inp, [this](double x)->double {return fromEW(x); }); + }; + +private: + double fromEW(double x) + { + double res = 0; + for (int d = 0; d <= deg; ++d) + { + res += pow(x, d) * p.at(d, 0); + } + return res; + }; +}; + +/* *\ brief Logpolyfit model. +*/ +class LogPolyfit +{ +public: + int deg; + Polyfit p; + + LogPolyfit() {}; + + /* *\ brief Logpolyfit method. + */ + LogPolyfit(cv::Mat x, cv::Mat y, int deg_) :deg(deg_) + { + cv::Mat mask_ = (x > 0) & (y > 0); + cv::Mat src_, dst_, s_, d_; + src_ = maskCopyTo(x, mask_); + dst_ = maskCopyTo(y, mask_); + log(src_, s_); + log(dst_, d_); + p = Polyfit(s_, d_, deg); + } + + virtual ~LogPolyfit() {}; + + cv::Mat operator()(const cv::Mat& inp) + { + cv::Mat mask_ = inp >= 0; + cv::Mat y, y_, res; + log(inp, y); + y = p(y); + exp(y, y_); + y_.copyTo(res, mask_); + return res; + }; +}; + +/* *\ brief Linearization base. +*/ +class Linear +{ +public: + Linear() {}; + + virtual ~Linear() {}; + + /* *\ brief Inference. + *\ param inp the input array, type of cv::Mat. + */ + virtual cv::Mat linearize(cv::Mat inp) + { + return inp; + }; + + /* *\brief Evaluate linearization model. + */ + virtual void value(void) {}; +}; + + +/* *\ brief Linearization identity. + * make no change. +*/ +class LinearIdentity : public Linear {}; + +/* *\ brief Linearization gamma correction. +*/ +class LinearGamma : public Linear +{ +public: + double gamma; + + LinearGamma(double gamma_) :gamma(gamma_) {}; + + cv::Mat linearize(cv::Mat inp) CV_OVERRIDE + { + return gammaCorrection(inp, gamma); + }; +}; + +/* *\ brief Linearization. + * Grayscale polynomial fitting. +*/ +template +class LinearGray :public Linear +{ +public: + int deg; + T p; + + LinearGray(int deg_, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg_) + { + dst.getGray(); + Mat lear_gray_mask = mask & dst.grays; + + // the grayscale function is approximate for src is in relative color space. + src = rgb2gray(maskCopyTo(src, lear_gray_mask)); + cv::Mat dst_ = maskCopyTo(dst.toGray(cs.io), lear_gray_mask); + calc(src, dst_); + } + + /* *\ brief monotonically increase is not guaranteed. + *\ param src the input array, type of cv::Mat. + *\ param dst the input array, type of cv::Mat. + */ + void calc(const cv::Mat& src, const cv::Mat& dst) + { + p = T(src, dst, deg); + }; + + cv::Mat linearize(cv::Mat inp) CV_OVERRIDE + { + return p(inp); + }; +}; + +/* *\ brief Linearization. + * Fitting channels respectively. +*/ +template +class LinearColor :public Linear +{ +public: + int deg; + T pr; + T pg; + T pb; + + LinearColor(int deg_, cv::Mat src_, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg_) + { + Mat src = maskCopyTo(src_, mask); + cv::Mat dst_ = maskCopyTo(dst.to(*cs.l).colors, mask); + calc(src, dst_); + } + + void calc(const cv::Mat& src, const cv::Mat& dst) + { + cv::Mat schannels[3]; + cv::Mat dchannels[3]; + split(src, schannels); + split(dst, dchannels); + pr = T(schannels[0], dchannels[0], deg); + pg = T(schannels[1], dchannels[1], deg); + pb = T(schannels[2], dchannels[2], deg); + }; + + cv::Mat linearize(cv::Mat inp) CV_OVERRIDE + { + cv::Mat channels[3]; + split(inp, channels); + std::vector channel; + cv::Mat res; + merge(std::vector{ pr(channels[0]), pg(channels[1]), pb(channels[2]) }, res); + return res; + }; +}; + + +/* *\ brief Get linearization method. + * used in ccm model. + *\ param gamma used in LinearGamma. + *\ param deg degrees. + *\ param src the input array, type of cv::Mat. + *\ param dst the input array, type of cv::Mat. + *\ param mask the input array, type of cv::Mat. + *\ param cs type of RGBBase_. + *\ param linear_type type of linear. +*/ +std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type); +std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type) +{ + std::shared_ptr p = std::make_shared(); + switch (linear_type) + { + case cv::ccm::IDENTITY_: + p.reset(new LinearIdentity()); + break; + case cv::ccm::GAMMA: + p.reset(new LinearGamma(gamma)); + break; + case cv::ccm::COLORPOLYFIT: + p.reset(new LinearColor(deg, src, dst, mask, cs)); + break; + case cv::ccm::COLORLOGPOLYFIT: + p.reset(new LinearColor(deg, src, dst, mask, cs)); + break; + case cv::ccm::GRAYPOLYFIT: + p.reset(new LinearGray(deg, src, dst, mask, cs)); + break; + case cv::ccm::GRAYLOGPOLYFIT: + p.reset(new LinearGray(deg, src, dst, mask, cs)); + break; + default: + throw std::invalid_argument{ "Wrong linear_type!" }; + break; + } + return p; +}; + +} // namespace ccm +} // namespace cv + + +#endif From 04920141a5e32defef58160177581a1b0eb4a1f8 Mon Sep 17 00:00:00 2001 From: Jinheng Zhang Date: Thu, 10 Sep 2020 21:19:44 +0800 Subject: [PATCH 19/71] Add the dependencies to opencv_imgcodecs in CMakeLists.txt --- modules/mcc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mcc/CMakeLists.txt b/modules/mcc/CMakeLists.txt index 806303505f3..c45daaffab3 100644 --- a/modules/mcc/CMakeLists.txt +++ b/modules/mcc/CMakeLists.txt @@ -1,2 +1,2 @@ set(the_description "Macbeth Chart Detection") -ocv_define_module(mcc opencv_core opencv_imgproc opencv_calib3d opencv_photo opencv_dnn WRAP python) +ocv_define_module(mcc opencv_core opencv_imgproc opencv_imgcodecs opencv_calib3d opencv_photo opencv_dnn WRAP python) From a48a2fda0ac0f67997afa643c36ae78b8d65d3f2 Mon Sep 17 00:00:00 2001 From: Jinheng Zhang Date: Thu, 10 Sep 2020 21:20:57 +0800 Subject: [PATCH 20/71] Add color correction model sample code. Co-authored-by: Chenqi Shan --- .../mcc/samples/color_correction_model.cpp | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 modules/mcc/samples/color_correction_model.cpp diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp new file mode 100644 index 00000000000..fd5ffef8f2b --- /dev/null +++ b/modules/mcc/samples/color_correction_model.cpp @@ -0,0 +1,124 @@ +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace cv; +using namespace mcc; +using namespace ccm; +using namespace std; + +const char *about = "Basic chart detection"; +const char *keys = { + "{ help h usage ? | | show this message }" + "{t | | chartType: 0-Standard, 1-DigitalSG, 2-Vinyl }" + "{v | | Input from video file, if ommited, input comes from camera }" + "{ci | 0 | Camera id if input doesnt come from video (-v) }" + "{f | 1 | Path of the file to process (-v) }" + "{nc | 1 | Maximum number of charts in the image }"}; + +int main(int argc, char *argv[]) +{ + + // ---------------------------------------------------------- + // Scroll down a bit (~40 lines) to find actual relevant code + // ---------------------------------------------------------- + + CommandLineParser parser(argc, argv, keys); + parser.about(about); + + int t = parser.get("t"); + int nc = parser.get("nc"); + string filepath = parser.get("f"); + + CV_Assert(0 <= t && t <= 2); + TYPECHART chartType = TYPECHART(t); + + cout << "t: " << t << " , nc: " << nc << ", \nf: " << filepath << endl; + + if (!parser.check()) + { + parser.printErrors(); + return 0; + } + + Mat image = cv::imread(filepath, IMREAD_COLOR); + if (!image.data) + { + cout << "Invalid Image!" << endl; + return 1; + } + + Mat imageCopy = image.clone(); + Ptr detector = CCheckerDetector::create(); + // Marker type to detect + if (!detector->process(image, chartType, nc)) + { + printf("ChartColor not detected \n"); + return 2; + } + // get checker + vector> checkers = detector->getListColorChecker(); + + for (Ptr checker : checkers) + { + Ptr cdraw = CCheckerDraw::create(checker); + cdraw->draw(image); + Mat chartsRGB = checker->getChartsRGB(); + Mat src = chartsRGB.col(1).clone().reshape(3, 18); + src /= 255.0; + + //compte color correction matrix + ColorCorrectionModel model1(src, Vinyl_D50_2); + + /* brief More models with different parameters, try it & check the document for details. + */ + // ColorCorrectionModel model2(src, Vinyl_D50_2, AdobeRGB, CCM_4x3, CIE2000, GAMMA, 2.2, 3); + // ColorCorrectionModel model3(src, Vinyl_D50_2, WideGamutRGB, CCM_4x3, CIE2000, GRAYPOLYFIT, 2.2, 3); + // ColorCorrectionModel model4(src, Vinyl_D50_2, ProPhotoRGB, CCM_4x3, RGBL, GRAYLOGPOLYFIT, 2.2, 3); + // ColorCorrectionModel model5(src, Vinyl_D50_2, DCI_P3_RGB, CCM_3x3, RGB, IDENTITY_, 2.2, 3); + // ColorCorrectionModel model6(src, Vinyl_D50_2, AppleRGB, CCM_3x3, CIE2000, COLORPOLYFIT, 2.2, 2,{ 0, 0.98 },Mat(),2); + // ColorCorrectionModel model7(src, Vinyl_D50_2, REC_2020_RGB, CCM_3x3, CIE94_GRAPHIC_ARTS, COLORLOGPOLYFIT, 2.2, 3); + + /* If you use a customized ColorChecker, you can use your own reference color values and corresponding color space in a way like: + */ + // cv::Mat ref = = (Mat_(18, 1) << + // Vec3d(1.00000000e+02, 5.20000001e-03, -1.04000000e-02), + // Vec3d(7.30833969e+01, -8.19999993e-01, -2.02099991e+00), + // Vec3d(6.24930000e+01, 4.25999999e-01, -2.23099995e+00), + // Vec3d(5.04640007e+01, 4.46999997e-01, -2.32399988e+00), + // Vec3d(3.77970009e+01, 3.59999985e-02, -1.29700005e+00), + // Vec3d(0.00000000e+00, 0.00000000e+00, 0.00000000e+00), + // Vec3d(5.15880013e+01, 7.35179977e+01, 5.15690002e+01), + // Vec3d(9.36989975e+01, -1.57340002e+01, 9.19420013e+01), + // Vec3d(6.94079971e+01, -4.65940018e+01, 5.04869995e+01), + // Vec3d(6.66100006e+01, -1.36789999e+01, -4.31720009e+01), + // Vec3d(1.17110004e+01, 1.69799995e+01, -3.71759987e+01), + // Vec3d(5.19739990e+01, 8.19440002e+01, -8.40699959e+00), + // Vec3d(4.05489998e+01, 5.04399986e+01, 2.48490009e+01), + // Vec3d(6.08160019e+01, 2.60690002e+01, 4.94420013e+01), + // Vec3d(5.22529984e+01, -1.99500008e+01, -2.39960003e+01), + // Vec3d(5.12859993e+01, 4.84700012e+01, -1.50579996e+01), + // Vec3d(6.87070007e+01, 1.22959995e+01, 1.62129993e+01), + // Vec3d(6.36839981e+01, 1.02930002e+01, 1.67639999e+01)); + + // ColorCorrectionModel model8(src,ref,Lab_D50_2); + + //make color correction + Mat calibratedImage = model1.inferImage(filepath); + + // Save the calibrated image to {FILE_NAME}.calibrated.{FILE_EXT} + string filename = filepath.substr(filepath.find_last_of('/')+1); + int dotIndex = filename.find_last_of('.'); + string baseName = filename.substr(0, dotIndex); + string ext = filename.substr(dotIndex+1, filename.length()-dotIndex); + string calibratedFilePath = baseName + ".calibrated." + ext; + cv::imwrite(calibratedFilePath, calibratedImage); + } + + return 0; +} From c5246fa317288c542f942b0ed8e7e3a4f3eb2a7d Mon Sep 17 00:00:00 2001 From: Jinheng Zhang Date: Thu, 10 Sep 2020 21:21:46 +0800 Subject: [PATCH 21/71] Add the index markdown of color correction tutorial. Co-authored-by: Chenqi Shan --- modules/mcc/tutorials/table_of_content_ccm.markdown | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 modules/mcc/tutorials/table_of_content_ccm.markdown diff --git a/modules/mcc/tutorials/table_of_content_ccm.markdown b/modules/mcc/tutorials/table_of_content_ccm.markdown new file mode 100644 index 00000000000..178f309b993 --- /dev/null +++ b/modules/mcc/tutorials/table_of_content_ccm.markdown @@ -0,0 +1,8 @@ +Color Correction Model {#tutorial_table_of_content_ccm} +=========================== + +- @subpage tutorial_ccm_color_correction_model + + *Author:* riskiest, shanchenqi, JinhengZhang + + How to do color correction, using Color Correction Model. \ No newline at end of file From 8d20535b74adaf6b495141a573bcfd8fcf63b7ab Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Thu, 10 Sep 2020 21:23:04 +0800 Subject: [PATCH 22/71] Add the introduction for color correction sample. --- .../basic_ccm/color_correction_model.markdown | 238 ++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 modules/mcc/tutorials/basic_ccm/color_correction_model.markdown diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown new file mode 100644 index 00000000000..0999c92cd72 --- /dev/null +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -0,0 +1,238 @@ +Color Correction Model{#tutorial_ccm_color_correction_model} +=========================== + +In this tutorial you will learn how to use the 'Color Correction Model' to do a color correction in a image. + +Reference +---- + +See details of ColorCorrection Algorithm at https://github.com/riskiest/color_calibration/tree/v4/doc/pdf/English/Algorithm. + +Building +---- + +When building OpenCV, run the following command to build all the contrib module: + +```make +cmake -D OPENCV_EXTRA_MODULES_PATH=/modules/ +``` + +Or only build the mcc module: + +```make +cmake -D OPENCV_EXTRA_MODULES_PATH=/modules/mcc +``` + +Or make sure you check the mcc module in the GUI version of CMake: cmake-gui. + +Source Code of the sample +----------- + +The sample has two parts of code, the first is the color checker detector model, see details at[basic_chart_detection](https://github.com/opencv/opencv_contrib/tree/master/modules/mcc/tutorials/basic_chart_detection), the second part is to make collor calibration. + +``` +Here are the parameters for ColorCorrectionModel +src : + detected colors of ColorChecker patches; + NOTICE: the color type is RGB not BGR, and the color values are in [0, 1]; + type: cv::Mat; +dst : + the reference colors; + NOTICE: Built-in color card or custom color card are supported; + Built-in: + Macbeth_D50_2: Macbeth ColorChecker with 2deg D50; + Macbeth_D65_2: Macbeth ColorChecker with 2deg D65; + Custom: + You should use Color + For the list of color spaces supported, see the notes below; + If the color type is some RGB, the format is RGB not BGR, and the color values are in [0, 1]; + type: Color; +colorspace : + the absolute color space that detected colors convert to; + NOTICE: it should be some RGB color space; + For the list of RGB color spaces supported, see the notes below; + type: ColorSpace; +ccm_type : + the shape of color correction matrix(CCM); + Supported list: + "CCM_3x3": 3x3 matrix; + "CCM_4x3": 4x3 matrix; + type: enum CCM_TYPE; +distance : + the type of color distance; + Supported list: + "CIE2000"; + "CIE94_GRAPHIC_ARTS"; + "CIE94_TEXTILES"; + "CIE76"; + "CMC_1TO1"; + "CMC_2TO1"; + "RGB" : Euclidean distance of rgb color space; + "RGBL" : Euclidean distance of rgbl color space; + type: enum DISTANCE_TYPE; +linear_type : + the method of linearization; + NOTICE: see Linearization.pdf for details; + Supported list: + "IDENTITY_" : no change is made; + "GAMMA": gamma correction; + Need assign a value to gamma simultaneously; + "COLORPOLYFIT": polynomial fitting channels respectively; + Need assign a value to deg simultaneously; + "GRAYPOLYFIT": grayscale polynomial fitting; + Need assign a value to deg and dst_whites simultaneously; + "COLORLOGPOLYFIT": logarithmic polynomial fitting channels respectively; + Need assign a value to deg simultaneously; + "GRAYLOGPOLYFIT": grayscale Logarithmic polynomial fitting; + Need assign a value to deg and dst_whites simultaneously; + type: enum LINEAR_TYPE; +gamma : + the gamma value of gamma correction; + NOTICE: only valid when linear is set to "gamma"; + type: double; + +deg : + the degree of linearization polynomial; + NOTICE: only valid when linear is set to "COLORPOLYFIT", "GRAYPOLYFIT", + "COLORLOGPOLYFIT" and "GRAYLOGPOLYFIT"; + type: int; +saturated_threshold : + the threshold to determine saturation; + NOTICE: it is a tuple of [low, up]; + The colors in the closed interval [low, up] are reserved to participate + in the calculation of the loss function and initialization parameters. + type: std::vector; +--------------------------------------------------- +There are some ways to set weights: + 1. set weights_list only; + 2. set weights_coeff only; +see CCM.pdf for details; + +weights_list : + the list of weight of each color; + type: cv::Mat; + +weights_coeff : + the exponent number of L* component of the reference color in CIE Lab color space; + type: double; +--------------------------------------------------- +initial_method_type : + the method of calculating CCM initial value; + see CCM.pdf for details; + Supported list: + 'LEAST_SQUARE': least-squre method; + 'WHITE_BALANCE': white balance method; + +max_count, epsilon : + used in MinProblemSolver-DownhillSolver; + Terminal criteria to the algorithm; + type: int, double; + + +--------------------------------------------------- +Supported Color Space: + Supported list of RGB color spaces: + sRGB; + AdobeRGB; + WideGamutRGB; + ProPhotoRGB; + DCI_P3_RGB; + AppleRGB; + REC_709_RGB; + REC_2020_RGB; + + Supported list of linear RGB color spaces: + sRGBL; + AdobeRGBL; + WideGamutRGBL; + ProPhotoRGBL; + DCI_P3_RGBL; + AppleRGBL; + REC_709_RGBL; + REC_2020_RGBL; + + Supported list of non-RGB color spaces: + Lab_D50_2; + Lab_D65_2; + XYZ_D50_2; + XYZ_D65_2; + + Supported IO (You can use Lab(io) or XYZ(io) to create color space): + A_2; + A_10; + D50_2; + D50_10; + D55_2; + D55_10; + D65_2; + D65_10; + D75_2; + D75_10; + E_2; + E_10; +``` + + +## Code + +@include mcc/samples/color_correction_model.cpp + +## Explanation + + The first part is to detect the ColorChecker position. + +@code{.cpp}#include #include #include #include #include #include using namespace std;using namespace cv;using namespace mcc;using namespace ccm;using namespace std;@endcode + +``` +Here is sets of header and namespaces. You can set other namespace like the code above. +``` + +@code{.cpp} + +const char *about = "Basic chart detection";const char *keys = { "{ help h usage ? | | show this message }" "{t | | chartType: 0-Standard, 1-DigitalSG, 2-Vinyl }" "{v | | Input from video file, if ommited, input comes from camera }" "{ci | 0 | Camera id if input doesnt come from video (-v) }" + + "{f | 1 | Path of the file to process (-v) }" "{nc | 1 | Maximum number of charts in the image }"};@ endcode + +``` +Some arguments for ColorChecker detection. +``` + +@code{.cpp} CommandLineParser parser(argc, argv, keys); parser.about(about); int t = parser.get("t"); int nc = parser.get("nc"); string filepath = parser.get("f"); CV_Assert(0 <= t && t <= 2); TYPECHART chartType = TYPECHART(t); cout << "t: " << t << " , nc: " << nc << ", \nf: " << filepath << endl;if (!parser.check()){ parser.printErrors();return 0;} Mat image = cv::imread(filepath, IMREAD_COLOR);if (!image.data) { cout << "Invalid Image!" << endl; return 1; } @endcode + +``` +Preparation for ColorChecker detection to get messages for the image. +``` + +@code{.cpp}Mat imageCopy = image.clone(); + + Ptr detector = CCheckerDetector::create(); if (!detector->process(image, chartType, nc)) { printf("ChartColor not detected \n"); return 2; } vector> checkers = detector->getListColorChecker();@endcode + +``` +The CCheckerDetectorobject is created and uses getListColorChecker function to get ColorChecker message. +``` + +@code{.cpp} for (Ptr checker : checkers) { Ptr cdraw = CCheckerDraw::create(checker); cdraw->draw(image); Mat chartsRGB = checker->getChartsRGB();Mat src = chartsRGB.col(1).clone().reshape(3, 18); src /= 255.0; //compte color correction matrix ColorCorrectionModel model1(src, Vinyl_D50_2);}@endcode + +``` +For every ColorChecker, we can compute a ccm matrix for color correction. Model1 is an object of ColorCorrectionModel class. The parameters should be changed to get the best effect of color correction. See other parameters' detail at the Parameters. +``` + +@code{.cpp}cv::Mat ref = = (Mat_(18, 1) < Date: Thu, 17 Sep 2020 11:04:46 +0800 Subject: [PATCH 23/71] Split operations into .hpp and .cpp --- .../mcc/include/opencv2/mcc/operations.hpp | 73 +++------------ modules/mcc/src/operations.cpp | 92 +++++++++++++++++++ 2 files changed, 106 insertions(+), 59 deletions(-) create mode 100644 modules/mcc/src/operations.cpp diff --git a/modules/mcc/include/opencv2/mcc/operations.hpp b/modules/mcc/include/opencv2/mcc/operations.hpp index 71947306071..ab80eabaa9e 100644 --- a/modules/mcc/include/opencv2/mcc/operations.hpp +++ b/modules/mcc/include/opencv2/mcc/operations.hpp @@ -38,64 +38,41 @@ namespace cv namespace ccm { -typedef std::function MatFunc; +typedef std::function MatFunc; /* *\ brief Operation class contains some operarions used for color space * conversion containing linear transformation and non-linear transformation */ -class Operation +class CV_EXPORTS_W Operation { public: bool linear; - cv::Mat M; + Mat M; MatFunc f; - Operation() : linear(true), M(cv::Mat()) {}; + Operation() : linear(true), M(Mat()) {}; - Operation(cv::Mat M_) :linear(true), M(M_) {}; + Operation(Mat M_) :linear(true), M(M_) {}; Operation(MatFunc f_) : linear(false), f(f_) {}; virtual ~Operation() {}; + /* *\ brief operator function will run operation */ - cv::Mat operator()(cv::Mat& abc) - { - if (!linear) - { - return f(abc); - } - if (M.empty()) - { - return abc; - } - return multiple(abc, M); - }; + Mat operator()(Mat& abc); /* *\ brief add function will conbine this operation * with other linear transformation operation */ - void add(const Operation& other) - { - if (M.empty()) - { - M = other.M.clone(); - } - else - { - M = M * other.M; - } - }; - - void clear() - { - M = cv::Mat(); - }; + void add(const Operation& other); + + void clear(); }; -const Operation IDENTITY_OP([](cv::Mat x) {return x; }); +const Operation IDENTITY_OP([](Mat x) {return x; }); -class Operations +class CV_EXPORTS_W Operations { public: std::vector ops; @@ -108,33 +85,11 @@ class Operations /* *\ brief add function will conbine this operation with other transformation operations */ - Operations& add(const Operations& other) - { - ops.insert(ops.end(), other.ops.begin(), other.ops.end()); - return *this; - }; + Operations& add(const Operations& other); /* *\ brief run operations to make color conversion */ - cv::Mat run(cv::Mat abc) - { - Operation hd; - for (auto& op : ops) - { - if (op.linear) - { - hd.add(op); - } - else - { - abc = hd(abc); - hd.clear(); - abc = op(abc); - } - } - abc = hd(abc); - return abc; - }; + Mat run(Mat abc); }; const Operations IDENTITY_OPS{ IDENTITY_OP }; diff --git a/modules/mcc/src/operations.cpp b/modules/mcc/src/operations.cpp new file mode 100644 index 00000000000..42c05784c72 --- /dev/null +++ b/modules/mcc/src/operations.cpp @@ -0,0 +1,92 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#include "precomp.hpp" + +namespace cv +{ +namespace ccm +{ + +Mat Operation::operator()(Mat& abc) +{ + if (!linear) + { + return f(abc); + } + if (M.empty()) + { + return abc; + } + return multiple(abc, M); +}; + +void Operation::add(const Operation& other) +{ + if (M.empty()) + { + M = other.M.clone(); + } + else + { + M = M * other.M; + } +}; + +void Operation::clear() +{ + M = Mat(); +}; + +Operations& Operations::add(const Operations& other) +{ + ops.insert(ops.end(), other.ops.begin(), other.ops.end()); + return *this; +}; + +Mat Operations::run(Mat abc) +{ + Operation hd; + for (auto& op : ops) + { + if (op.linear) + { + hd.add(op); + } + else + { + abc = hd(abc); + hd.clear(); + abc = op(abc); + } + } + abc = hd(abc); + return abc; +}; + +} // namespace ccm +} // namespace cv \ No newline at end of file From e19da0e7b7ce45c113aa9c1e662e23b47773b70b Mon Sep 17 00:00:00 2001 From: Jinheng Zhang Date: Thu, 17 Sep 2020 11:06:55 +0800 Subject: [PATCH 24/71] Split mcc, color, colorspace and linearize into .cpp & .hpp --- modules/mcc/include/opencv2/mcc/ccm.hpp | 270 ++--------- modules/mcc/include/opencv2/mcc/color.hpp | 119 +---- .../mcc/include/opencv2/mcc/colorspace.hpp | 393 +++------------- modules/mcc/include/opencv2/mcc/linearize.hpp | 139 ++---- modules/mcc/src/ccm.cpp | 253 +++++++++++ modules/mcc/src/color.cpp | 133 ++++++ modules/mcc/src/colorspace.cpp | 428 ++++++++++++++++++ modules/mcc/src/linearize.cpp | 130 ++++++ 8 files changed, 1099 insertions(+), 766 deletions(-) create mode 100644 modules/mcc/src/ccm.cpp create mode 100644 modules/mcc/src/color.cpp create mode 100644 modules/mcc/src/colorspace.cpp create mode 100644 modules/mcc/src/linearize.cpp diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 9a581cf9112..379b55a6625 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -217,15 +217,19 @@ enum INITIAL_METHOD_TYPE /* *\ brief Core class of ccm model. * produce a ColorCorrectionModel instance for inference. */ -class ColorCorrectionModel +class CV_EXPORTS_W ColorCorrectionModel { public: // detected colors, the referenceand the RGB colorspace for conversion - cv::Mat src; + Mat src; Color dst; - + Mat dist; RGBBase_& cs; - cv::Mat mask; + Mat mask; + + // RGBl of detected data and the reference + Mat src_rgbl; + Mat dst_rgbl; // ccm type and shape CCM_TYPE ccm_type; @@ -235,141 +239,47 @@ class ColorCorrectionModel std::shared_ptr linear; DISTANCE_TYPE distance; - cv::Mat weights; - cv::Mat ccm; - cv::Mat ccm0; + Mat weights; + Mat ccm; + Mat ccm0; + int masked_len; double loss; - int max_count; double epsilon; - ColorCorrectionModel(cv::Mat src_, cv::Mat colors_, const ColorSpace& ref_cs_, RGBBase_& cs_=sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, - double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, cv::Mat weights_list = Mat(), double weights_coeff = 0, - INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4) : - ColorCorrectionModel(src_, Color(colors_, ref_cs_), cs_, ccm_type_, distance_, linear_type, - gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} + ColorCorrectionModel(Mat src_, Mat colors_, const ColorSpace& ref_cs_, RGBBase_& cs_=sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, + INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); - ColorCorrectionModel(cv::Mat src_, Color dst_, RGBBase_& cs_= sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, - double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, cv::Mat weights_list = Mat(), double weights_coeff = 0, - INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4) : - src(src_), dst(dst_), cs(cs_), ccm_type(ccm_type_), distance(distance_), max_count(max_count_), epsilon(epsilon_) - { - cv::Mat saturate_mask = saturate(src, saturated_threshold[0], saturated_threshold[1]); - this->linear = getLinear(gamma, deg, this->src, this->dst, saturate_mask, this->cs, linear_type); - calWeightsMasks(weights_list, weights_coeff, saturate_mask); - - src_rgbl = this->linear->linearize(maskCopyTo(this->src, mask)); - dst.colors = maskCopyTo(dst.colors, mask); - dst_rgbl =this->dst.to(*(this->cs.l)).colors; - - // make no change for CCM_3x3, make change for CCM_4x3. - src_rgbl = prepare(src_rgbl); - - - // distance function may affect the loss function and the fitting function - switch (this->distance) - { - case cv::ccm::RGBL: - initialLeastSquare(true); - break; - default: - switch (initial_method_type) - { - case cv::ccm::WHITE_BALANCE: - initialWhiteBalance(); - break; - case cv::ccm::LEAST_SQUARE: - initialLeastSquare(); - break; - default: - throw std::invalid_argument{ "Wrong initial_methoddistance_type!" }; - break; - } - break; - } - - fitting(); - } + ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_= sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, + INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); /* *\ brief Make no change for CCM_3x3. * convert cv::Mat A to [A, 1] in CCM_4x3. *\ param inp the input array, type of cv::Mat. *\ return the output array, type of cv::Mat */ - cv::Mat prepare(const cv::Mat& inp) - { - switch (ccm_type) - { - case cv::ccm::CCM_3x3: - shape = 9; - return inp; - case cv::ccm::CCM_4x3: - { - shape = 12; - cv::Mat arr1 = cv::Mat::ones(inp.size(), CV_64F); - cv::Mat arr_out(inp.size(), CV_64FC4); - cv::Mat arr_channels[3]; - split(inp, arr_channels); - merge(std::vector{arr_channels[0], arr_channels[1], arr_channels[2], arr1}, arr_out); - return arr_out; - } - default: - throw std::invalid_argument{ "Wrong ccm_type!" }; - break; - } - }; + Mat prepare(const Mat& inp); + + /* *\ brief Calculate weights and mask. + *\ param weights_list the input array, type of cv::Mat. + *\ param weights_coeff type of double. + *\ param saturate_list the input array, type of cv::Mat. + */ + void calWeightsMasks(Mat weights_list, double weights_coeff, Mat saturate_mask); /* *\ brief Fitting nonlinear - optimization initial value by white balance. * see CCM.pdf for details. - *\ return the output array, type of cv::Mat + *\ return the output array, type of Mat */ - cv::Mat initialWhiteBalance(void) - { - cv::Mat schannels[3]; - split(src_rgbl, schannels); - cv::Mat dchannels[3]; - split(dst_rgbl, dchannels); - std::vector initial_vec = { sum(dchannels[0])[0] / sum(schannels[0])[0], 0, 0, 0, - sum(dchannels[1])[0] / sum(schannels[1])[0], 0, 0, 0, - sum(dchannels[2])[0] / sum(schannels[2])[0], 0, 0, 0 }; - std::vector initial_vec_(initial_vec.begin(), initial_vec.begin() + shape); - cv::Mat initial_white_balance = cv::Mat(initial_vec_, true).reshape(0, shape / 3); - - return initial_white_balance; - }; + Mat initialWhiteBalance(void); /* *\ brief Fitting nonlinear-optimization initial value by least square. * see CCM.pdf for details *\ param fit if fit is True, return optimalization for rgbl distance function. */ - void initialLeastSquare(bool fit = false) - { - cv::Mat A, B, w; - if (weights.empty()) - { - A = src_rgbl; - B = dst_rgbl; - } - else - { - pow(weights, 0.5, w); - cv::Mat w_; - merge(std::vector{w, w, w}, w_); - A = w_.mul(src_rgbl); - B = w_.mul(dst_rgbl); - } - solve(A.reshape(1, A.rows), B.reshape(1, B.rows), ccm0, DECOMP_SVD); - - // if fit is True, return optimalization for rgbl distance function. - if (fit) - { - ccm = ccm0; - cv::Mat residual = A.reshape(1, A.rows) * ccm.reshape(0, shape / 3) - B.reshape(1, B.rows); - Scalar s = residual.dot(residual); - double sum = s[0]; - loss = sqrt(sum / masked_len); - } - }; + void initialLeastSquare(bool fit = false); /* *\ brief Loss function base on cv::MinProblemSolver::Function. * see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp @@ -391,7 +301,7 @@ class ColorCorrectionModel */ double calc(const double* x) const CV_OVERRIDE { - cv::Mat ccm_(ccm_loss->shape, 1, CV_64F); + Mat ccm_(ccm_loss->shape, 1, CV_64F); for (int i = 0; i < ccm_loss->shape; i++) { ccm_.at(i, 0) = x[i]; @@ -401,68 +311,21 @@ class ColorCorrectionModel } }; - double calc_loss_(Color color) - { - cv::Mat distlist = color.diff(dst, distance); - Color lab = color.to(Lab_D50_2); - cv::Mat dist_; - pow(distlist, 2, dist_); - if (!weights.empty()) - { - dist_ = weights.mul(dist_); - } - Scalar ss = sum(dist_); - return ss[0]; - } + double calc_loss_(Color color); - double calc_loss(const Mat ccm_) - { - Mat converted = src_rgbl.reshape(1, 0) * ccm_; - Color color(converted.reshape(3, 0), *(cs.l)); - return calc_loss_(color); - } + double calc_loss(const Mat ccm_); /* *\ brief Fitting ccm if distance function is associated with CIE Lab color space. * see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp * Set terminal criteria for solver is possible. */ - void fitting(void) - { - cv::Ptr solver = cv::DownhillSolver::create(); - cv::Ptr ptr_F(new LossFunction(this)); - solver->setFunction(ptr_F); - cv::Mat reshapeccm = ccm0.clone().reshape(0, 1); - cv::Mat step = cv::Mat::ones(reshapeccm.size(), CV_64F); - solver->setInitStep(step); - TermCriteria termcrit = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, max_count, epsilon); - solver->setTermCriteria(termcrit); - double res = solver->minimize(reshapeccm); - ccm = reshapeccm.reshape(0, shape/3); - loss = pow((res / masked_len), 0.5); - std::cout << " ccm " << ccm << std::endl; - std::cout << " loss " << loss << std::endl; - }; + void fitting(void); /* *\ brief Infer using fitting ccm. *\ param img the input image, type of cv::Mat. *\ return the output array, type of cv::Mat. */ - cv::Mat infer(const cv::Mat& img, bool islinear = false) - { - if (!ccm.data) - { - throw "No CCM values!"; - } - cv::Mat img_lin = linear->linearize(img); - cv::Mat img_ccm(img_lin.size(), img_lin.type()); - cv::Mat ccm_ = ccm.reshape(0, shape / 3); - img_ccm = multiple(prepare(img_lin), ccm_); - if (islinear == true) - { - return img_ccm; - } - return cs.fromL(img_ccm); - }; + Mat infer(const Mat& img, bool islinear = false); /* *\ brief Infer image and output as an BGR image with uint8 type. * mainly for test or debug. @@ -471,71 +334,8 @@ class ColorCorrectionModel *\ param islinear if linearize or not. *\ return the output array, type of cv::Mat. */ - cv::Mat inferImage(std::string imgfile, bool islinear = false) - { - const int inp_size = 255; - const int out_size = 255; - cv::Mat img = imread(imgfile); - cv::Mat img_; - cvtColor(img, img_, COLOR_BGR2RGB); - img_.convertTo(img_, CV_64F); - img_ = img_ / inp_size; - cv::Mat out = this->infer(img_, islinear); - cv::Mat out_ = out * out_size; - out_.convertTo(out_, CV_8UC3); - cv::Mat img_out = min(max(out_, 0), out_size); - cv::Mat out_img; - cvtColor(img_out, out_img, COLOR_RGB2BGR); - return out_img; - }; - - // void report() { - // std::cout << "CCM0: " << ccm0 << std::endl; - // std::cout << "CCM: " << ccm << std::endl; - // std::cout << "Loss: " << loss << std::endl; - // } - -private: - cv::Mat dist; - int masked_len; - - // RGBl of detected data and the reference - cv::Mat src_rgbl; - cv::Mat dst_rgbl; - - /* *\ brief Calculate weights and mask. - *\ param weights_list the input array, type of cv::Mat. - *\ param weights_coeff type of double. - *\ param saturate_list the input array, type of cv::Mat. - */ - void calWeightsMasks(cv::Mat weights_list, double weights_coeff, cv::Mat saturate_mask) - { - // weights - if (!weights_list.empty()) - { - weights = weights_list; - } - else if (weights_coeff != 0) - { - pow(dst.toLuminant(dst.cs.io), weights_coeff, weights); - } + Mat inferImage(std::string imgfile, bool islinear = false); - // masks - cv::Mat weight_mask = cv::Mat::ones(src.rows, 1, CV_8U); - if (!weights.empty()) - { - weight_mask = weights > 0; - } - this->mask = (weight_mask) & (saturate_mask); - - // weights' mask - if (!weights.empty()) - { - cv::Mat weights_masked = maskCopyTo(this->weights, this->mask); - weights = weights_masked / mean(weights_masked)[0]; - } - masked_len = (int)sum(mask)[0]; - }; }; } // namespace ccm diff --git a/modules/mcc/include/opencv2/mcc/color.hpp b/modules/mcc/include/opencv2/mcc/color.hpp index 1b542e5d45f..ac2c246d8dc 100644 --- a/modules/mcc/include/opencv2/mcc/color.hpp +++ b/modules/mcc/include/opencv2/mcc/color.hpp @@ -40,7 +40,7 @@ namespace ccm /* *\ brief Color defined by color_values and color space */ -class Color +class CV_EXPORTS_W Color { public: @@ -48,17 +48,14 @@ class Color *\ param colored mask of colored color *\ param history storage of historical conversion */ - cv::Mat colors; + Mat colors; const ColorSpace& cs; - cv::Mat grays; - cv::Mat colored; + Mat grays; + Mat colored; std::map> history; - Color(cv::Mat colors_, const ColorSpace& cs_, cv::Mat colored_) : colors(colors_), cs(cs_), colored(colored_) - { - grays= ~colored; - } - Color(cv::Mat colors_, const ColorSpace& cs_) :colors(colors_), cs(cs_) {}; + Color(Mat colors_, const ColorSpace& cs_, Mat colored_); + Color(Mat colors_, const ColorSpace& cs_); virtual ~Color() {}; @@ -69,62 +66,27 @@ class Color *\ param other type of ColorSpace. *\ return Color. */ - Color to(const ColorSpace& other, CAM method = BRADFORD, bool save = true) - { - if (history.count(other) == 1) - { - - return *history[other]; - } - if (cs.relate(other)) - { - return Color(cs.relation(other).run(colors), other); - } - Operations ops; - ops.add(cs.to).add(XYZ(cs.io).cam(other.io, method)).add(other.from); - std::shared_ptr color(new Color(ops.run(colors), other)); - if (save) - { - history[other] = color; - } - return *color; - } + Color to(const ColorSpace& other, CAM method = BRADFORD, bool save = true); /* *\ brief Channels split. *\ return each channel. */ - cv::Mat channel(cv::Mat m, int i) - { - cv::Mat dchannels[3]; - split(m, dchannels); - return dchannels[i]; - } + Mat channel(Mat m, int i); /* *\ brief To Gray. */ - cv::Mat toGray(IO io, CAM method = BRADFORD, bool save = true) - { - XYZ xyz(io); - return channel(this->to(xyz, method, save).colors, 1); - } + Mat toGray(IO io, CAM method = BRADFORD, bool save = true); /* *\ brief To Luminant. */ - cv::Mat toLuminant(IO io, CAM method = BRADFORD, bool save = true) - { - Lab lab(io); - return channel(this->to(lab, method, save).colors, 0); - } + Mat toLuminant(IO io, CAM method = BRADFORD, bool save = true); /* *\ brief Diff without IO. *\ param other type of Color. *\ param method type of distance. *\ return distance between self and other */ - cv::Mat diff(Color& other, DISTANCE_TYPE method = CIE2000) - { - return diff(other, cs.io, method); - } + Mat diff(Color& other, DISTANCE_TYPE method = CIE2000); /* *\ brief Diff with IO. *\ param other type of Color. @@ -132,51 +94,15 @@ class Color *\ param method type of distance. *\ return distance between self and other */ - cv::Mat diff(Color& other, IO io, DISTANCE_TYPE method = CIE2000) - { - Lab lab(io); - switch (method) - { - case cv::ccm::CIE76: - case cv::ccm::CIE94_GRAPHIC_ARTS: - case cv::ccm::CIE94_TEXTILES: - case cv::ccm::CIE2000: - case cv::ccm::CMC_1TO1: - case cv::ccm::CMC_2TO1: - return distance(to(lab).colors, other.to(lab).colors, method); - case cv::ccm::RGB: - return distance(to(*cs.nl).colors, other.to(*cs.nl).colors, method); - case cv::ccm::RGBL: - return distance(to(*cs.l).colors, other.to(*cs.l).colors, method); - default: - throw std::invalid_argument{ "Wrong method!" }; - break; - } - } + Mat diff(Color& other, IO io, DISTANCE_TYPE method = CIE2000); /* *\ brief Calculate gray mask. */ - void getGray(double JDN = 2.0) - { - if (!grays.empty()) { - return; - } - cv::Mat lab = to(Lab_D65_2).colors; - cv::Mat gray(colors.size(), colors.type()); - int fromto[] = { 0,0, -1,1, -1,2 }; - mixChannels(&lab, 1, &gray, 1, fromto, 3); - cv::Mat d = distance(lab, gray, CIE2000); - this->grays = d < JDN; - this->colored = ~grays; - } + void getGray(double JDN = 2.0); /* *\ brief Operator for mask copy. */ - Color operator[](cv::Mat mask) - { - return Color(maskCopyTo(colors, mask), cs); - } - + Color operator[](Mat mask); }; @@ -184,7 +110,7 @@ class Color /* *\ brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls * see Miscellaneous.md for details. */ -const cv::Mat ColorChecker2005_LAB_D50_2 = (cv::Mat_(24, 1) << +const Mat ColorChecker2005_LAB_D50_2 = (Mat_(24, 1) << cv::Vec3d(37.986, 13.555, 14.059), cv::Vec3d(65.711, 18.13, 17.81), cv::Vec3d(49.927, -4.88, -21.925), @@ -210,7 +136,7 @@ const cv::Mat ColorChecker2005_LAB_D50_2 = (cv::Mat_(24, 1) << cv::Vec3d(35.656, -0.421, -1.231), cv::Vec3d(20.461, -0.079, -0.973)); -const cv::Mat ColorChecker2005_LAB_D65_2 = (cv::Mat_(24, 1) << +const Mat ColorChecker2005_LAB_D65_2 = (Mat_(24, 1) << cv::Vec3d(37.542, 12.018, 13.33), cv::Vec3d(65.2, 14.821, 17.545), cv::Vec3d(50.366, -1.573, -21.431), @@ -236,13 +162,13 @@ const cv::Mat ColorChecker2005_LAB_D65_2 = (cv::Mat_(24, 1) << cv::Vec3d(35.68, -0.22, -1.205), cv::Vec3d(20.475, 0.049, -0.972)); -const cv::Mat ColorChecker2005_COLORED_MASK = (cv::Mat_(24, 1) << +const Mat ColorChecker2005_COLORED_MASK = (Mat_(24, 1) << 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0); -const cv::Mat Vinyl_LAB_D50_2 = (Mat_(18, 1) << +const Mat Vinyl_LAB_D50_2 = (Mat_(18, 1) << Vec3d(1.00000000e+02, 5.20000001e-03, -1.04000000e-02), Vec3d(7.30833969e+01, -8.19999993e-01, -2.02099991e+00), Vec3d(6.24930000e+01, 4.25999999e-01, -2.23099995e+00), @@ -262,21 +188,20 @@ const cv::Mat Vinyl_LAB_D50_2 = (Mat_(18, 1) << Vec3d(6.87070007e+01, 1.22959995e+01, 1.62129993e+01), Vec3d(6.36839981e+01, 1.02930002e+01, 1.67639999e+01)); -const cv::Mat Vinyl_COLORED_MASK = (cv::Mat_(18, 1) << +const Mat Vinyl_COLORED_MASK = (Mat_(18, 1) << 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); /* *\ brief Macbeth ColorChecker with 2deg D50. */ -Color Macbeth_D50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2, ColorChecker2005_COLORED_MASK); +CV_EXPORTS_W extern Color Macbeth_D50_2; /* *\ brief Macbeth ColorChecker with 2deg D65. */ -Color Macbeth_D65_2(ColorChecker2005_LAB_D65_2, Lab_D65_2, ColorChecker2005_COLORED_MASK); - -Color Vinyl_D50_2(Vinyl_LAB_D50_2, Lab_D50_2, Vinyl_COLORED_MASK); +CV_EXPORTS_W extern Color Macbeth_D65_2; +CV_EXPORTS_W extern Color Vinyl_D50_2; } // namespace ccm } // namespace cv diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp index 9742344c365..2cb54d07f6d 100644 --- a/modules/mcc/include/opencv2/mcc/colorspace.hpp +++ b/modules/mcc/include/opencv2/mcc/colorspace.hpp @@ -41,7 +41,7 @@ namespace ccm { /* *\ brief Basic class for ColorSpace. */ -class ColorSpace +class CV_EXPORTS_W ColorSpace { public: IO io; @@ -62,27 +62,18 @@ class ColorSpace nl = 0; }; - virtual bool relate(const ColorSpace& other) const - { - return (type == other.type) && (io == other.io); - }; + virtual bool relate(const ColorSpace& other) const; - virtual Operations relation(const ColorSpace& /*other*/) const - { - return IDENTITY_OPS; - }; + virtual Operations relation(const ColorSpace& /*other*/) const; - bool operator<(const ColorSpace& other)const - { - return (io < other.io || (io == other.io && type < other.type) || (io == other.io && type == other.type && linear < other.linear)); - } + bool operator<(const ColorSpace& other)const; }; /* *\ brief Base of RGB color space; * the argument values are from AdobeRGB; * Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space */ -class RGBBase_ : public ColorSpace +class CV_EXPORTS_W RGBBase_ : public ColorSpace { public: // primaries @@ -94,8 +85,8 @@ class RGBBase_ : public ColorSpace double yb; MatFunc toL; MatFunc fromL; - cv::Mat M_to; - cv::Mat M_from; + Mat M_to; + Mat M_from; using ColorSpace::ColorSpace; @@ -107,41 +98,15 @@ class RGBBase_ : public ColorSpace *\ param other type of ColorSpace. *\ return Operations. */ - Operations relation(const ColorSpace& other) const CV_OVERRIDE - { - if (linear == other.linear) - { - return IDENTITY_OPS; - } - if (linear) - { - return Operations({ Operation(fromL) }); - } - return Operations({ Operation(toL) }); - }; + Operations relation(const ColorSpace& other) const CV_OVERRIDE; /* *\ brief Initial operations. */ - void init() - { - setParameter(); - calLinear(); - calM(); - calOperations(); - } - + void init(); /* *\ brief Produce color space instance with linear and non-linear versions. *\ param rgbl type of RGBBase_. */ - void bind(RGBBase_& rgbl) - { - init(); - rgbl.init(); - l = &rgbl; - rgbl.l = &rgbl; - nl = this; - rgbl.nl = this; - } + void bind(RGBBase_& rgbl); private: virtual void setParameter() {}; @@ -149,82 +114,36 @@ class RGBBase_ : public ColorSpace /* *\ brief Calculation of M_RGBL2XYZ_base. * see ColorSpace.pdf for details. */ - virtual void calM() - { - cv::Mat XYZr, XYZg, XYZb, XYZ_rgbl, Srgb; - XYZr = cv::Mat(xyY2XYZ({ xr, yr }), true); - XYZg = cv::Mat(xyY2XYZ({ xg, yg }), true); - XYZb = cv::Mat(xyY2XYZ({ xb, yb }), true); - merge(std::vector{ XYZr, XYZg, XYZb }, XYZ_rgbl); - XYZ_rgbl = XYZ_rgbl.reshape(1, XYZ_rgbl.rows); - cv::Mat XYZw = cv::Mat(illuminants.find(io)->second, true); - solve(XYZ_rgbl, XYZw, Srgb); - merge(std::vector{ Srgb.at(0)* XYZr, - Srgb.at(1)* XYZg, - Srgb.at(2)* XYZb }, M_to); - M_to = M_to.reshape(1, M_to.rows); - M_from = M_to.inv(); - }; + virtual void calM(); /* *\ brief operations to or from XYZ. */ - virtual void calOperations() - { - // rgb -> rgbl - toL = [this](cv::Mat rgb)->cv::Mat {return toLFunc(rgb); }; - - // rgbl -> rgb - fromL = [this](cv::Mat rgbl)->cv::Mat {return fromLFunc(rgbl); }; - - if (linear) - { - to = Operations({ Operation(M_to.t()) }); - from = Operations({ Operation(M_from.t()) }); - } - else - { - to = Operations({ Operation(toL), Operation(M_to.t()) }); - from = Operations({ Operation(M_from.t()), Operation(fromL) }); - } - } - - virtual void calLinear() {} - - virtual cv::Mat toLFunc(cv::Mat& /*rgb*/) - { - return cv::Mat(); - }; + virtual void calOperations(); - virtual cv::Mat fromLFunc(cv::Mat& /*rgbl*/) - { - return cv::Mat(); - }; + virtual void calLinear() {}; + + virtual Mat toLFunc(Mat& /*rgb*/); + + virtual Mat fromLFunc(Mat& /*rgbl*/); }; /* *\ brief Base of Adobe RGB color space; */ -class AdobeRGBBase_ : public RGBBase_ +class CV_EXPORTS_W AdobeRGBBase_ : public RGBBase_ { public: using RGBBase_::RGBBase_; double gamma; private: - cv::Mat toLFunc(cv::Mat& rgb) CV_OVERRIDE - { - return gammaCorrection(rgb, gamma); - } - - cv::Mat fromLFunc(cv::Mat& rgbl) CV_OVERRIDE - { - return gammaCorrection(rgbl, 1. / gamma); - } + Mat toLFunc(Mat& rgb) CV_OVERRIDE; + Mat fromLFunc(Mat& rgbl) CV_OVERRIDE; }; /* *\ brief Base of sRGB color space; */ -class sRGBBase_ : public RGBBase_ +class CV_EXPORTS_W sRGBBase_ : public RGBBase_ { public: using RGBBase_::RGBBase_; @@ -239,272 +158,143 @@ class sRGBBase_ : public RGBBase_ /* *\ brief linearization parameters * see ColorSpace.pdf for details; */ - virtual void calLinear() CV_OVERRIDE - { - alpha = a + 1; - K0 = a / (gamma - 1); - phi = (pow(alpha, gamma) * pow(gamma - 1, gamma - 1)) / (pow(a, gamma - 1) * pow(gamma, gamma)); - beta = K0 / phi; - } - + virtual void calLinear() CV_OVERRIDE; /* *\ brief Used by toLFunc. */ - double toLFuncEW(double& x) - { - if (x > K0) - { - return pow(((x + alpha - 1) / alpha), gamma); - } - else if (x >= -K0) - { - return x / phi; - } - else - { - return -(pow(((-x + alpha - 1) / alpha), gamma)); - } - } + double toLFuncEW(double& x); /* *\ brief Linearization. * see ColorSpace.pdf for details. *\ param rgb the input array, type of cv::Mat. *\ return the output array, type of cv::Mat. */ - cv::Mat toLFunc(cv::Mat& rgb) CV_OVERRIDE - { - return elementWise(rgb, [this](double a_)->double {return toLFuncEW(a_); }); - } + Mat toLFunc(Mat& rgb) CV_OVERRIDE; /* *\ brief Used by fromLFunc. */ - double fromLFuncEW(double& x) - { - if (x > beta) - { - return alpha * pow(x, 1 / gamma) - (alpha - 1); - } - else if (x >= -beta) - { - return x * phi; - } - else - { - return -(alpha * pow(-x, 1 / gamma) - (alpha - 1)); - } - } - + double fromLFuncEW(double& x); /* *\ brief Delinearization. * see ColorSpace.pdf for details. *\ param rgbl the input array, type of cv::Mat. *\ return the output array, type of cv::Mat. */ - cv::Mat fromLFunc(cv::Mat& rgbl) CV_OVERRIDE - { - return elementWise(rgbl, [this](double a_)->double {return fromLFuncEW(a_); }); - } + Mat fromLFunc(Mat& rgbl) CV_OVERRIDE; }; /* *\ brief sRGB color space. * data from https://en.wikipedia.org/wiki/SRGB. */ -class sRGB_ :public sRGBBase_ +class CV_EXPORTS_W sRGB_ :public sRGBBase_ { public: sRGB_(bool linear_) :sRGBBase_(D65_2, "sRGB", linear_) {}; private: - void setParameter() CV_OVERRIDE - { - xr = 0.64; - yr = 0.33; - xg = 0.3; - yg = 0.6; - xb = 0.15; - yb = 0.06; - a = 0.055; - gamma = 2.4; - } + void setParameter() CV_OVERRIDE; }; /* *\ brief Adobe RGB color space. */ -class AdobeRGB_ : public AdobeRGBBase_ +class CV_EXPORTS_W AdobeRGB_ : public AdobeRGBBase_ { public: AdobeRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AdobeRGB", linear_) {}; private: - void setParameter() CV_OVERRIDE - { - xr = 0.64; - yr = 0.33; - xg = 0.21; - yg = 0.71; - xb = 0.15; - yb = 0.06; - gamma = 2.2; - } + void setParameter() CV_OVERRIDE; }; /* *\ brief Wide-gamut RGB color space. * data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. */ -class WideGamutRGB_ : public AdobeRGBBase_ +class CV_EXPORTS_W WideGamutRGB_ : public AdobeRGBBase_ { public: WideGamutRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "WideGamutRGB", linear_) {}; private: - void setParameter() CV_OVERRIDE - { - xr = 0.7347; - yr = 0.2653; - xg = 0.1152; - yg = 0.8264; - xb = 0.1566; - yb = 0.0177; - gamma = 2.2; - } + void setParameter() CV_OVERRIDE; }; /* *\ brief ProPhoto RGB color space. * data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. */ -class ProPhotoRGB_ : public AdobeRGBBase_ +class CV_EXPORTS_W ProPhotoRGB_ : public AdobeRGBBase_ { public: ProPhotoRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "ProPhotoRGB", linear_) {}; private: - void setParameter() CV_OVERRIDE - { - xr = 0.734699; - yr = 0.265301; - xg = 0.159597; - yg = 0.840403; - xb = 0.036598; - yb = 0.000105; - gamma = 1.8; - } + void setParameter() CV_OVERRIDE; }; /* *\ brief DCI-P3 RGB color space. * data from https://en.wikipedia.org/wiki/DCI-P3. */ -class DCI_P3_RGB_ : public AdobeRGBBase_ +class CV_EXPORTS_W DCI_P3_RGB_ : public AdobeRGBBase_ { public: DCI_P3_RGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "DCI_P3_RGB", linear_) {}; private: - void setParameter() CV_OVERRIDE - { - xr = 0.68; - yr = 0.32; - xg = 0.265; - yg = 0.69; - xb = 0.15; - yb = 0.06; - gamma = 2.2; - } + void setParameter() CV_OVERRIDE; }; /* *\ brief Apple RGB color space. * data from http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. */ -class AppleRGB_ : public AdobeRGBBase_ +class CV_EXPORTS_W AppleRGB_ : public AdobeRGBBase_ { public: AppleRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AppleRGB", linear_) {}; private: - void setParameter() CV_OVERRIDE - { - xr = 0.625; - yr = 0.34; - xg = 0.28; - yg = 0.595; - xb = 0.155; - yb = 0.07; - gamma = 1.8; - } + void setParameter() CV_OVERRIDE; }; /* *\ brief REC_709 RGB color space. * data from https://en.wikipedia.org/wiki/Rec._709. */ -class REC_709_RGB_ : public sRGBBase_ +class CV_EXPORTS_W REC_709_RGB_ : public sRGBBase_ { public: REC_709_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_709_RGB", linear_) {}; private: - void setParameter() CV_OVERRIDE - { - xr = 0.64; - yr = 0.33; - xg = 0.3; - yg = 0.6; - xb = 0.15; - yb = 0.06; - a = 0.099; - gamma = 1 / 0.45; - } + void setParameter() CV_OVERRIDE; }; /* *\ brief REC_2020 RGB color space. * data from https://en.wikipedia.org/wiki/Rec._2020. */ -class REC_2020_RGB_ : public sRGBBase_ +class CV_EXPORTS_W REC_2020_RGB_ : public sRGBBase_ { public: REC_2020_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_2020_RGB", linear_) {}; private: - void setParameter() CV_OVERRIDE - { - xr = 0.708; - yr = 0.292; - xg = 0.17; - yg = 0.797; - xb = 0.131; - yb = 0.046; - a = 0.09929682680944; - gamma = 1 / 0.45; - } + void setParameter() CV_OVERRIDE; }; -sRGB_ sRGB(false), sRGBL(true); -AdobeRGB_ AdobeRGB(false), AdobeRGBL(true); -WideGamutRGB_ WideGamutRGB(false), WideGamutRGBL(true); -ProPhotoRGB_ ProPhotoRGB(false), ProPhotoRGBL(true); -DCI_P3_RGB_ DCI_P3_RGB(false), DCI_P3_RGBL(true); -AppleRGB_ AppleRGB(false), AppleRGBL(true); -REC_709_RGB_ REC_709_RGB(false), REC_709_RGBL(true); -REC_2020_RGB_ REC_2020_RGB(false), REC_2020_RGBL(true); +CV_EXPORTS_W extern sRGB_ sRGB, sRGBL; +CV_EXPORTS_W extern AdobeRGB_ AdobeRGB, AdobeRGBL; +CV_EXPORTS_W extern WideGamutRGB_ WideGamutRGB, WideGamutRGBL; +CV_EXPORTS_W extern ProPhotoRGB_ ProPhotoRGB, ProPhotoRGBL; +CV_EXPORTS_W extern DCI_P3_RGB_ DCI_P3_RGB, DCI_P3_RGBL; +CV_EXPORTS_W extern AppleRGB_ AppleRGB, AppleRGBL; +CV_EXPORTS_W extern REC_709_RGB_ REC_709_RGB, REC_709_RGBL; +CV_EXPORTS_W extern REC_2020_RGB_ REC_2020_RGB, REC_2020_RGBL; /* *\ brief Bind RGB with RGBL. */ -class ColorSpaceInitial +class CV_EXPORTS_W ColorSpaceInitial { public: - ColorSpaceInitial() - { - sRGB.bind(sRGBL); - AdobeRGB.bind(AdobeRGBL); - WideGamutRGB.bind(WideGamutRGBL); - ProPhotoRGB.bind(ProPhotoRGBL); - DCI_P3_RGB.bind(DCI_P3_RGBL); - AppleRGB.bind(AppleRGBL); - REC_709_RGB.bind(REC_709_RGBL); - REC_2020_RGB.bind(REC_2020_RGBL); - - } + ColorSpaceInitial(); }; -ColorSpaceInitial color_space_initial; - +extern ColorSpaceInitial color_space_initial; /* *\ brief Enum of the possible types of CAMs. */ @@ -515,11 +305,11 @@ enum CAM BRADFORD }; -static std::map , cv::Mat > cams; -const static cv::Mat Von_Kries = (cv::Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); -const static cv::Mat Bradford = (cv::Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); -const static std::map > MAs = { - {IDENTITY , { cv::Mat::eye(cv::Size(3,3),CV_64FC1) , cv::Mat::eye(cv::Size(3,3),CV_64FC1)} }, +static std::map , Mat > cams; +const static Mat Von_Kries = (Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); +const static Mat Bradford = (Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); +const static std::map > MAs = { + {IDENTITY , { Mat::eye(cv::Size(3,3),CV_64FC1) , Mat::eye(cv::Size(3,3),CV_64FC1)} }, {VON_KRIES, { Von_Kries ,Von_Kries.inv() }}, {BRADFORD, { Bradford ,Bradford.inv() }} }; @@ -527,15 +317,11 @@ const static std::map > MAs = { /* *\ brief XYZ color space. * Chromatic adaption matrices. */ -class XYZ :public ColorSpace +class CV_EXPORTS_W XYZ :public ColorSpace { public: XYZ(IO io_) : ColorSpace(io_, "XYZ", true) {}; - Operations cam(IO dio, CAM method = BRADFORD) - { - return (io == dio) ? Operations() : Operations({ Operation(cam_(io, dio, method).t()) }); - } - + Operations cam(IO dio, CAM method = BRADFORD); private: /* *\ brief Get cam. *\ param sio the input IO of src. @@ -543,27 +329,7 @@ class XYZ :public ColorSpace *\ param method type of CAM. *\ return the output array, type of cv::Mat. */ - cv::Mat cam_(IO sio, IO dio, CAM method = BRADFORD) const - { - if (sio == dio) - { - return cv::Mat::eye(cv::Size(3, 3), CV_64FC1); - } - if (cams.count(std::make_tuple(dio, sio, method)) == 1) - { - return cams[std::make_tuple(dio, sio, method)]; - } - - // Function from http ://www.brucelindbloom.com/index.html?ColorCheckerRGB.html. - cv::Mat XYZws = cv::Mat(illuminants.find(dio)->second); - cv::Mat XYZWd = cv::Mat(illuminants.find(sio)->second); - cv::Mat MA = MAs.at(method)[0]; - cv::Mat MA_inv = MAs.at(method)[1]; - cv::Mat M = MA_inv * cv::Mat::diag((MA * XYZws) / (MA * XYZWd)) * MA; - cams[std::make_tuple(dio, sio, method)] = M; - cams[std::make_tuple(sio, dio, method)] = M.inv(); - return M; - } + Mat cam_(IO sio, IO dio, CAM method = BRADFORD) const; }; /* *\ brief Define XYZ_D65_2 and XYZ_D50_2. @@ -571,56 +337,33 @@ class XYZ :public ColorSpace const XYZ XYZ_D65_2(D65_2); const XYZ XYZ_D50_2(D50_2); - /* *\ brief Lab color space. */ -class Lab :public ColorSpace +class CV_EXPORTS_W Lab :public ColorSpace { public: - Lab(IO io_) : ColorSpace(io_, "Lab", true) - { - to = { Operation([this](cv::Mat src)->cv::Mat {return tosrc(src); }) }; - from = { Operation([this](cv::Mat src)->cv::Mat {return fromsrc(src); }) }; - } - + Lab(IO io_); private: static constexpr double delta = (6. / 29.); static constexpr double m = 1. / (3. * delta * delta); static constexpr double t0 = delta * delta * delta; static constexpr double c = 4. / 29.; - cv::Vec3d fromxyz(cv::Vec3d& xyz) - { - double x = xyz[0] / illuminants.find(io)->second[0], y = xyz[1] / illuminants.find(io)->second[1], z = xyz[2] / illuminants.find(io)->second[2]; - auto f = [](double t)->double { return t > t0 ? std::cbrt(t) : (m * t + c); }; - double fx = f(x), fy = f(y), fz = f(z); - return { 116. * fy - 16. ,500 * (fx - fy),200 * (fy - fz) }; - } + cv::Vec3d fromxyz(cv::Vec3d& xyz); /* *\ brief Calculate From. *\ param src the input array, type of cv::Mat. *\ return the output array, type of cv::Mat */ - cv::Mat fromsrc(cv::Mat& src) - { - return channelWise(src, [this](cv::Vec3d a)->cv::Vec3d {return fromxyz(a); }); - } + Mat fromsrc(Mat& src); - cv::Vec3d tolab(cv::Vec3d& lab) - { - auto f_inv = [](double t)->double {return t > delta ? pow(t, 3.0) : (t - c) / m; }; - double L = (lab[0] + 16.) / 116., a = lab[1] / 500., b = lab[2] / 200.; - return { illuminants.find(io)->second[0] * f_inv(L + a),illuminants.find(io)->second[1] * f_inv(L),illuminants.find(io)->second[2] * f_inv(L - b) }; - } + cv::Vec3d tolab(cv::Vec3d& lab); /* *\ brief Calculate To. *\ param src the input array, type of cv::Mat. *\ return the output array, type of cv::Mat */ - cv::Mat tosrc(cv::Mat& src) - { - return channelWise(src, [this](cv::Vec3d a)->cv::Vec3d {return tolab(a); }); - } + Mat tosrc(Mat& src); }; /* *\ brief Define Lab_D65_2 and Lab_D50_2. @@ -632,4 +375,4 @@ const Lab Lab_D50_2(D50_2); } // namespace cv -#endif \ No newline at end of file +#endif diff --git a/modules/mcc/include/opencv2/mcc/linearize.hpp b/modules/mcc/include/opencv2/mcc/linearize.hpp index 3dff3b87572..e82c0a9b4e1 100644 --- a/modules/mcc/include/opencv2/mcc/linearize.hpp +++ b/modules/mcc/include/opencv2/mcc/linearize.hpp @@ -49,11 +49,11 @@ enum LINEAR_TYPE /* *\ brief Polyfit model. */ -class Polyfit +class CV_EXPORTS_W Polyfit { public: int deg; - cv::Mat p; + Mat p; Polyfit() {}; @@ -63,44 +63,19 @@ class Polyfit and deduct: Ax = y See linear.pdf for details */ - Polyfit(cv::Mat x, cv::Mat y, int deg_) :deg(deg_) - { - int n = x.cols * x.rows * x.channels(); - x = x.reshape(1, n); - y = y.reshape(1, n); - cv::Mat_ A = cv::Mat_::ones(n, deg + 1); - for (int i = 0; i < n; ++i) - { - for (int j = 1; j < A.cols; ++j) - { - A.at(i, j) = x.at(i) * A.at(i, j - 1); - } - } - cv::Mat y_(y); - cv::solve(A, y_, p, DECOMP_SVD); - } + Polyfit(Mat x, Mat y, int deg_); virtual ~Polyfit() {}; - cv::Mat operator()(const cv::Mat& inp) - { - return elementWise(inp, [this](double x)->double {return fromEW(x); }); - }; + + Mat operator()(const Mat& inp); private: - double fromEW(double x) - { - double res = 0; - for (int d = 0; d <= deg; ++d) - { - res += pow(x, d) * p.at(d, 0); - } - return res; - }; + double fromEW(double x); }; /* *\ brief Logpolyfit model. */ -class LogPolyfit +class CV_EXPORTS_W LogPolyfit { public: int deg; @@ -110,34 +85,16 @@ class LogPolyfit /* *\ brief Logpolyfit method. */ - LogPolyfit(cv::Mat x, cv::Mat y, int deg_) :deg(deg_) - { - cv::Mat mask_ = (x > 0) & (y > 0); - cv::Mat src_, dst_, s_, d_; - src_ = maskCopyTo(x, mask_); - dst_ = maskCopyTo(y, mask_); - log(src_, s_); - log(dst_, d_); - p = Polyfit(s_, d_, deg); - } + LogPolyfit(Mat x, Mat y, int deg_); virtual ~LogPolyfit() {}; - cv::Mat operator()(const cv::Mat& inp) - { - cv::Mat mask_ = inp >= 0; - cv::Mat y, y_, res; - log(inp, y); - y = p(y); - exp(y, y_); - y_.copyTo(res, mask_); - return res; - }; + Mat operator()(const Mat& inp); }; /* *\ brief Linearization base. */ -class Linear +class CV_EXPORTS_W Linear { public: Linear() {}; @@ -147,10 +104,7 @@ class Linear /* *\ brief Inference. *\ param inp the input array, type of cv::Mat. */ - virtual cv::Mat linearize(cv::Mat inp) - { - return inp; - }; + virtual Mat linearize(Mat inp); /* *\brief Evaluate linearization model. */ @@ -161,21 +115,18 @@ class Linear /* *\ brief Linearization identity. * make no change. */ -class LinearIdentity : public Linear {}; +class CV_EXPORTS_W LinearIdentity : public Linear {}; /* *\ brief Linearization gamma correction. */ -class LinearGamma : public Linear +class CV_EXPORTS_W LinearGamma : public Linear { public: double gamma; LinearGamma(double gamma_) :gamma(gamma_) {}; - cv::Mat linearize(cv::Mat inp) CV_OVERRIDE - { - return gammaCorrection(inp, gamma); - }; + Mat linearize(Mat inp) CV_OVERRIDE; }; /* *\ brief Linearization. @@ -188,14 +139,14 @@ class LinearGray :public Linear int deg; T p; - LinearGray(int deg_, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg_) + LinearGray(int deg_, Mat src, Color dst, Mat mask, RGBBase_ cs) :deg(deg_) { dst.getGray(); Mat lear_gray_mask = mask & dst.grays; // the grayscale function is approximate for src is in relative color space. src = rgb2gray(maskCopyTo(src, lear_gray_mask)); - cv::Mat dst_ = maskCopyTo(dst.toGray(cs.io), lear_gray_mask); + Mat dst_ = maskCopyTo(dst.toGray(cs.io), lear_gray_mask); calc(src, dst_); } @@ -203,12 +154,12 @@ class LinearGray :public Linear *\ param src the input array, type of cv::Mat. *\ param dst the input array, type of cv::Mat. */ - void calc(const cv::Mat& src, const cv::Mat& dst) + void calc(const Mat& src, const Mat& dst) { p = T(src, dst, deg); }; - cv::Mat linearize(cv::Mat inp) CV_OVERRIDE + Mat linearize(Mat inp) CV_OVERRIDE { return p(inp); }; @@ -226,17 +177,17 @@ class LinearColor :public Linear T pg; T pb; - LinearColor(int deg_, cv::Mat src_, Color dst, cv::Mat mask, RGBBase_ cs) :deg(deg_) + LinearColor(int deg_, Mat src_, Color dst, Mat mask, RGBBase_ cs) :deg(deg_) { Mat src = maskCopyTo(src_, mask); - cv::Mat dst_ = maskCopyTo(dst.to(*cs.l).colors, mask); + Mat dst_ = maskCopyTo(dst.to(*cs.l).colors, mask); calc(src, dst_); } - void calc(const cv::Mat& src, const cv::Mat& dst) + void calc(const Mat& src, const Mat& dst) { - cv::Mat schannels[3]; - cv::Mat dchannels[3]; + Mat schannels[3]; + Mat dchannels[3]; split(src, schannels); split(dst, dchannels); pr = T(schannels[0], dchannels[0], deg); @@ -244,18 +195,17 @@ class LinearColor :public Linear pb = T(schannels[2], dchannels[2], deg); }; - cv::Mat linearize(cv::Mat inp) CV_OVERRIDE + Mat linearize(Mat inp) CV_OVERRIDE { - cv::Mat channels[3]; + Mat channels[3]; split(inp, channels); - std::vector channel; - cv::Mat res; - merge(std::vector{ pr(channels[0]), pg(channels[1]), pb(channels[2]) }, res); + std::vector channel; + Mat res; + merge(std::vector{ pr(channels[0]), pg(channels[1]), pb(channels[2]) }, res); return res; }; }; - /* *\ brief Get linearization method. * used in ccm model. *\ param gamma used in LinearGamma. @@ -266,39 +216,10 @@ class LinearColor :public Linear *\ param cs type of RGBBase_. *\ param linear_type type of linear. */ -std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type); -std::shared_ptr getLinear(double gamma, int deg, cv::Mat src, Color dst, cv::Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type) -{ - std::shared_ptr p = std::make_shared(); - switch (linear_type) - { - case cv::ccm::IDENTITY_: - p.reset(new LinearIdentity()); - break; - case cv::ccm::GAMMA: - p.reset(new LinearGamma(gamma)); - break; - case cv::ccm::COLORPOLYFIT: - p.reset(new LinearColor(deg, src, dst, mask, cs)); - break; - case cv::ccm::COLORLOGPOLYFIT: - p.reset(new LinearColor(deg, src, dst, mask, cs)); - break; - case cv::ccm::GRAYPOLYFIT: - p.reset(new LinearGray(deg, src, dst, mask, cs)); - break; - case cv::ccm::GRAYLOGPOLYFIT: - p.reset(new LinearGray(deg, src, dst, mask, cs)); - break; - default: - throw std::invalid_argument{ "Wrong linear_type!" }; - break; - } - return p; -}; +std::shared_ptr getLinear(double gamma, int deg, Mat src, Color dst, Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type); } // namespace ccm } // namespace cv -#endif +#endif \ No newline at end of file diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp new file mode 100644 index 00000000000..163a79609b9 --- /dev/null +++ b/modules/mcc/src/ccm.cpp @@ -0,0 +1,253 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#include "precomp.hpp" + +namespace cv +{ +namespace ccm +{ + +ColorCorrectionModel::ColorCorrectionModel(Mat src_, Mat colors_, const ColorSpace& ref_cs_, RGBBase_& cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, + double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, + INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : + ColorCorrectionModel(src_, Color(colors_, ref_cs_), cs_, ccm_type_, distance_, linear_type, + gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} + +ColorCorrectionModel::ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, + double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, + INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : + src(src_), dst(dst_), cs(cs_), ccm_type(ccm_type_), distance(distance_), max_count(max_count_), epsilon(epsilon_) +{ + Mat saturate_mask = saturate(src, saturated_threshold[0], saturated_threshold[1]); + this->linear = getLinear(gamma, deg, this->src, this->dst, saturate_mask, this->cs, linear_type); + calWeightsMasks(weights_list, weights_coeff, saturate_mask); + + src_rgbl = this->linear->linearize(maskCopyTo(this->src, mask)); + dst.colors = maskCopyTo(dst.colors, mask); + dst_rgbl = this->dst.to(*(this->cs.l)).colors; + + // make no change for CCM_3x3, make change for CCM_4x3. + src_rgbl = prepare(src_rgbl); + + // distance function may affect the loss function and the fitting function + switch (this->distance) + { + case cv::ccm::RGBL: + initialLeastSquare(true); + break; + default: + switch (initial_method_type) + { + case cv::ccm::WHITE_BALANCE: + initialWhiteBalance(); + break; + case cv::ccm::LEAST_SQUARE: + initialLeastSquare(); + break; + default: + throw std::invalid_argument{ "Wrong initial_methoddistance_type!" }; + break; + } + break; + } + + fitting(); +} + +Mat ColorCorrectionModel::prepare(const Mat& inp) +{ + switch (ccm_type) + { + case cv::ccm::CCM_3x3: + shape = 9; + return inp; + case cv::ccm::CCM_4x3: + { + shape = 12; + Mat arr1 = Mat::ones(inp.size(), CV_64F); + Mat arr_out(inp.size(), CV_64FC4); + Mat arr_channels[3]; + split(inp, arr_channels); + merge(std::vector{arr_channels[0], arr_channels[1], arr_channels[2], arr1}, arr_out); + return arr_out; + } + default: + throw std::invalid_argument{ "Wrong ccm_type!" }; + break; + } +} + +void ColorCorrectionModel::calWeightsMasks(Mat weights_list, double weights_coeff, Mat saturate_mask) +{ + // weights + if (!weights_list.empty()) + { + weights = weights_list; + } + else if (weights_coeff != 0) + { + pow(dst.toLuminant(cs.io), weights_coeff, weights); + } + + // masks + Mat weight_mask = Mat::ones(src.rows, 1, CV_8U); + if (!weights.empty()) + { + weight_mask = weights > 0; + } + this->mask = (weight_mask) & (saturate_mask); + + // weights' mask + if (!weights.empty()) + { + Mat weights_masked = maskCopyTo(this->weights, this->mask); + weights = weights_masked / mean(weights_masked)[0]; + } + masked_len = (int)sum(mask)[0]; +} + +Mat ColorCorrectionModel::initialWhiteBalance(void) +{ + Mat schannels[3]; + split(src_rgbl, schannels); + Mat dchannels[3]; + split(dst_rgbl, dchannels); + std::vector initial_vec = { sum(dchannels[0])[0] / sum(schannels[0])[0], 0, 0, 0, + sum(dchannels[1])[0] / sum(schannels[1])[0], 0, 0, 0, + sum(dchannels[2])[0] / sum(schannels[2])[0], 0, 0, 0 }; + std::vector initial_vec_(initial_vec.begin(), initial_vec.begin() + shape); + Mat initial_white_balance = Mat(initial_vec_, true).reshape(0, shape / 3); + + return initial_white_balance; +} + +void ColorCorrectionModel::initialLeastSquare(bool fit) +{ + Mat A, B, w; + if (weights.empty()) + { + A = src_rgbl; + B = dst_rgbl; + } + else + { + pow(weights, 0.5, w); + Mat w_; + merge(std::vector{w, w, w}, w_); + A = w_.mul(src_rgbl); + B = w_.mul(dst_rgbl); + } + solve(A.reshape(1, A.rows), B.reshape(1, B.rows), ccm0, DECOMP_SVD); + + // if fit is True, return optimalization for rgbl distance function. + if (fit) + { + ccm = ccm0; + Mat residual = A.reshape(1, A.rows) * ccm.reshape(0, shape / 3) - B.reshape(1, B.rows); + Scalar s = residual.dot(residual); + double sum = s[0]; + loss = sqrt(sum / masked_len); + } +} + +double ColorCorrectionModel::calc_loss_(Color color) +{ + Mat distlist = color.diff(dst, distance); + Color lab = color.to(Lab_D50_2); + Mat dist_; + pow(distlist, 2, dist_); + if (!weights.empty()) + { + dist_ = weights.mul(dist_); + } + Scalar ss = sum(dist_); + return ss[0]; +} + +double ColorCorrectionModel::calc_loss(const Mat ccm_) +{ + Mat converted = src_rgbl.reshape(1, 0) * ccm_; + Color color(converted.reshape(3, 0), *(cs.l)); + return calc_loss_(color); +} + +void ColorCorrectionModel::fitting(void) +{ + cv::Ptr solver = cv::DownhillSolver::create(); + cv::Ptr ptr_F(new LossFunction(this)); + solver->setFunction(ptr_F); + Mat reshapeccm = ccm0.clone().reshape(0, 1); + Mat step = Mat::ones(reshapeccm.size(), CV_64F); + solver->setInitStep(step); + TermCriteria termcrit = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, max_count, epsilon); + solver->setTermCriteria(termcrit); + double res = solver->minimize(reshapeccm); + ccm = reshapeccm.reshape(0, shape/3); + loss = pow((res / masked_len), 0.5); + std::cout << " ccm " << ccm << std::endl; + std::cout << " loss " << loss << std::endl; +} + +Mat ColorCorrectionModel::infer(const Mat& img, bool islinear) +{ + if (!ccm.data) + { + throw "No CCM values!"; + } + Mat img_lin = linear->linearize(img); + Mat img_ccm(img_lin.size(), img_lin.type()); + Mat ccm_ = ccm.reshape(0, shape / 3); + img_ccm = multiple(prepare(img_lin), ccm_); + if (islinear == true) + { + return img_ccm; + } + return cs.fromL(img_ccm); +} + +Mat ColorCorrectionModel::inferImage(std::string imgfile, bool islinear) +{ + const int inp_size = 255; + const int out_size = 255; + Mat img = imread(imgfile); + Mat img_; + cvtColor(img, img_, COLOR_BGR2RGB); + img_.convertTo(img_, CV_64F); + img_ = img_ / inp_size; + Mat out = this->infer(img_, islinear); + Mat out_ = out * out_size; + out_.convertTo(out_, CV_8UC3); + Mat img_out = min(max(out_, 0), out_size); + Mat out_img; + cvtColor(img_out, out_img, COLOR_RGB2BGR); + return out_img; +} + + +} // namespace ccm +} // namespace cv diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp new file mode 100644 index 00000000000..a94b0f1d600 --- /dev/null +++ b/modules/mcc/src/color.cpp @@ -0,0 +1,133 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#include "precomp.hpp" + +namespace cv +{ +namespace ccm +{ + +Color::Color(Mat colors_, const ColorSpace& cs_, Mat colored_) : colors(colors_), cs(cs_), colored(colored_) +{ + grays= ~colored; +} + +Color::Color(Mat colors_, const ColorSpace& cs_) : colors(colors_), cs(cs_) {}; + +Color Color::to(const ColorSpace& other, CAM method, bool save) +{ + if (history.count(other) == 1) + { + return *history[other]; + } + if (cs.relate(other)) + { + return Color(cs.relation(other).run(colors), other); + } + Operations ops; + ops.add(cs.to).add(XYZ(cs.io).cam(other.io, method)).add(other.from); + std::shared_ptr color(new Color(ops.run(colors), other)); + if (save) + { + history[other] = color; + } + return *color; +} + +Mat Color::channel(Mat m, int i) +{ + Mat dchannels[3]; + split(m, dchannels); + return dchannels[i]; +} + +Mat Color::toGray(IO io, CAM method, bool save) +{ + XYZ xyz(io); + return channel(this->to(xyz, method, save).colors, 1); +} + +Mat Color::toLuminant(IO io, CAM method, bool save) +{ + Lab lab(io); + return channel(this->to(lab, method, save).colors, 0); +} + +Mat Color::diff(Color& other, DISTANCE_TYPE method) +{ + return diff(other, cs.io, method); +} + +Mat Color::diff(Color& other, IO io, DISTANCE_TYPE method) +{ + Lab lab(io); + switch (method) + { + case cv::ccm::CIE76: + case cv::ccm::CIE94_GRAPHIC_ARTS: + case cv::ccm::CIE94_TEXTILES: + case cv::ccm::CIE2000: + case cv::ccm::CMC_1TO1: + case cv::ccm::CMC_2TO1: + return distance(to(lab).colors, other.to(lab).colors, method); + case cv::ccm::RGB: + return distance(to(*cs.nl).colors, other.to(*cs.nl).colors, method); + case cv::ccm::RGBL: + return distance(to(*cs.l).colors, other.to(*cs.l).colors, method); + default: + throw std::invalid_argument{ "Wrong method!" }; + break; + } +} + +void Color::getGray(double JDN) +{ + if (!grays.empty()) + { + return; + } + Mat lab = to(Lab_D65_2).colors; + Mat gray(colors.size(), colors.type()); + int fromto[] = { 0,0, -1,1, -1,2 }; + mixChannels(&lab, 1, &gray, 1, fromto, 3); + Mat d = distance(lab, gray, CIE2000); + this->grays = d < JDN; + this->colored = ~grays; +} + +Color Color::operator[](Mat mask) +{ + return Color(maskCopyTo(colors, mask), cs); +} + +Color Macbeth_D50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2, ColorChecker2005_COLORED_MASK); +Color Macbeth_D65_2(ColorChecker2005_LAB_D65_2, Lab_D65_2, ColorChecker2005_COLORED_MASK); +Color Vinyl_D50_2(Vinyl_LAB_D50_2, Lab_D50_2, Vinyl_COLORED_MASK); + +} // namespace ccm +} // namespace cv \ No newline at end of file diff --git a/modules/mcc/src/colorspace.cpp b/modules/mcc/src/colorspace.cpp new file mode 100644 index 00000000000..55b2bd62416 --- /dev/null +++ b/modules/mcc/src/colorspace.cpp @@ -0,0 +1,428 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level +// directory of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#include "precomp.hpp" + +namespace cv { +namespace ccm { + +static std::map> illuminants = { + {A_2, { 1.098466069456375, 1, 0.3558228003436005 }}, + {A_10, { 1.111420406956693, 1, 0.3519978321919493 }}, + {D50_2, { 0.9642119944211994, 1, 0.8251882845188288 }}, + {D50_10, { 0.9672062750333777, 1, 0.8142801513128616 }}, + {D55_2, { 0.956797052643698, 1, 0.9214805860173273 }}, + {D55_10, { 0.9579665682254781, 1, 0.9092525159847462 }}, + {D65_2, { 0.95047, 1., 1.08883 }}, + {D65_10, { 0.94811, 1., 1.07304 }}, + {D75_2, { 0.9497220898840717, 1, 1.226393520724154 }}, + {D75_10, { 0.9441713925645873, 1, 1.2064272211720228 }}, + {E_2, { 1., 1., 1. }}, + {E_10, { 1., 1., 1. }}, +}; + +/* *\ brief Basic class for ColorSpace. + */ +bool ColorSpace::relate(const ColorSpace& other) const { + return (type == other.type) && (io == other.io); +}; + +Operations ColorSpace::relation(const ColorSpace& /*other*/) const { + return IDENTITY_OPS; +}; + +bool ColorSpace::operator<(const ColorSpace& other) const { + return (io < other.io || (io == other.io && type < other.type) || + (io == other.io && type == other.type && linear < other.linear)); +} + +/* *\ brief Base of RGB color space; + * the argument values are from AdobeRGB; + * Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space + */ +Operations RGBBase_::relation(const ColorSpace& other) const { + if (linear == other.linear) { + return IDENTITY_OPS; + } + if (linear) { + return Operations({Operation(fromL)}); + } + return Operations({Operation(toL)}); +}; + +/* *\ brief Initial operations. + */ +void RGBBase_::init() { + setParameter(); + calLinear(); + calM(); + calOperations(); +} + +/* *\ brief Produce color space instance with linear and non-linear versions. + *\ param rgbl type of RGBBase_. + */ +void RGBBase_::bind(RGBBase_& rgbl) { + init(); + rgbl.init(); + l = &rgbl; + rgbl.l = &rgbl; + nl = this; + rgbl.nl = this; +} + +/* *\ brief Calculation of M_RGBL2XYZ_base. + * see ColorSpace.pdf for details. + */ +void RGBBase_::calM() { + Mat XYZr, XYZg, XYZb, XYZ_rgbl, Srgb; + XYZr = Mat(xyY2XYZ({xr, yr}), true); + XYZg = Mat(xyY2XYZ({xg, yg}), true); + XYZb = Mat(xyY2XYZ({xb, yb}), true); + merge(std::vector{XYZr, XYZg, XYZb}, XYZ_rgbl); + XYZ_rgbl = XYZ_rgbl.reshape(1, XYZ_rgbl.rows); + Mat XYZw = Mat(illuminants.find(io)->second, true); + solve(XYZ_rgbl, XYZw, Srgb); + merge(std::vector{Srgb.at(0) * XYZr, Srgb.at(1) * XYZg, + Srgb.at(2) * XYZb}, + M_to); + M_to = M_to.reshape(1, M_to.rows); + M_from = M_to.inv(); +}; + +/* *\ brief operations to or from XYZ. + */ +void RGBBase_::calOperations() { + // rgb -> rgbl + toL = [this](Mat rgb) -> Mat { return toLFunc(rgb); }; + + // rgbl -> rgb + fromL = [this](Mat rgbl) -> Mat { return fromLFunc(rgbl); }; + + if (linear) { + to = Operations({Operation(M_to.t())}); + from = Operations({Operation(M_from.t())}); + } else { + to = Operations({Operation(toL), Operation(M_to.t())}); + from = Operations({Operation(M_from.t()), Operation(fromL)}); + } +} + +Mat RGBBase_::toLFunc(Mat& /*rgb*/) { return Mat(); } + +Mat RGBBase_::fromLFunc(Mat& /*rgbl*/) { return Mat(); } + +/* *\ brief Base of Adobe RGB color space; + */ + +Mat AdobeRGBBase_::toLFunc(Mat& rgb) { return gammaCorrection(rgb, gamma); } + +Mat AdobeRGBBase_::fromLFunc(Mat& rgbl) { + return gammaCorrection(rgbl, 1. / gamma); +} + +/* *\ brief Base of sRGB color space; + */ + +void sRGBBase_::calLinear() { + alpha = a + 1; + K0 = a / (gamma - 1); + phi = (pow(alpha, gamma) * pow(gamma - 1, gamma - 1)) / + (pow(a, gamma - 1) * pow(gamma, gamma)); + beta = K0 / phi; +} + +/* *\ brief Used by toLFunc. + */ +double sRGBBase_::toLFuncEW(double& x) { + if (x > K0) { + return pow(((x + alpha - 1) / alpha), gamma); + } else if (x >= -K0) { + return x / phi; + } else { + return -(pow(((-x + alpha - 1) / alpha), gamma)); + } +} + +/* *\ brief Linearization. + * see ColorSpace.pdf for details. + *\ param rgb the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat. + */ +Mat sRGBBase_::toLFunc(Mat& rgb) { + return elementWise(rgb, + [this](double a_) -> double { return toLFuncEW(a_); }); +} + +/* *\ brief Used by fromLFunc. + */ +double sRGBBase_::fromLFuncEW(double& x) { + if (x > beta) { + return alpha * pow(x, 1 / gamma) - (alpha - 1); + } else if (x >= -beta) { + return x * phi; + } else { + return -(alpha * pow(-x, 1 / gamma) - (alpha - 1)); + } +} + +/* *\ brief Delinearization. + * see ColorSpace.pdf for details. + *\ param rgbl the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat. + */ +Mat sRGBBase_::fromLFunc(Mat& rgbl) { + return elementWise(rgbl, + [this](double a_) -> double { return fromLFuncEW(a_); }); +} + +/* *\ brief sRGB color space. + * data from https://en.wikipedia.org/wiki/SRGB. + */ + +void sRGB_::setParameter() { + xr = 0.64; + yr = 0.33; + xg = 0.3; + yg = 0.6; + xb = 0.15; + yb = 0.06; + a = 0.055; + gamma = 2.4; +} + +/* *\ brief Adobe RGB color space. + */ + +void AdobeRGB_::setParameter() { + xr = 0.64; + yr = 0.33; + xg = 0.21; + yg = 0.71; + xb = 0.15; + yb = 0.06; + gamma = 2.2; +} + +/* *\ brief Wide-gamut RGB color space. + * data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. + */ + +void WideGamutRGB_::setParameter() { + xr = 0.7347; + yr = 0.2653; + xg = 0.1152; + yg = 0.8264; + xb = 0.1566; + yb = 0.0177; + gamma = 2.2; +} + +/* *\ brief ProPhoto RGB color space. + * data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. + */ + +void ProPhotoRGB_::setParameter() { + xr = 0.734699; + yr = 0.265301; + xg = 0.159597; + yg = 0.840403; + xb = 0.036598; + yb = 0.000105; + gamma = 1.8; +} + +/* *\ brief DCI-P3 RGB color space. + * data from https://en.wikipedia.org/wiki/DCI-P3. + */ + +void DCI_P3_RGB_::setParameter() { + xr = 0.68; + yr = 0.32; + xg = 0.265; + yg = 0.69; + xb = 0.15; + yb = 0.06; + gamma = 2.2; +} + +/* *\ brief Apple RGB color space. + * data from + * http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. + */ + +void AppleRGB_::setParameter() { + xr = 0.625; + yr = 0.34; + xg = 0.28; + yg = 0.595; + xb = 0.155; + yb = 0.07; + gamma = 1.8; +} + +/* *\ brief REC_709 RGB color space. + * data from https://en.wikipedia.org/wiki/Rec._709. + */ + +void REC_709_RGB_::setParameter() { + xr = 0.64; + yr = 0.33; + xg = 0.3; + yg = 0.6; + xb = 0.15; + yb = 0.06; + a = 0.099; + gamma = 1 / 0.45; +} + +/* *\ brief REC_2020 RGB color space. + * data from https://en.wikipedia.org/wiki/Rec._2020. + */ + +void REC_2020_RGB_::setParameter() { + xr = 0.708; + yr = 0.292; + xg = 0.17; + yg = 0.797; + xb = 0.131; + yb = 0.046; + a = 0.09929682680944; + gamma = 1 / 0.45; +} + +sRGB_ sRGB = sRGB_(false); +sRGB_ sRGBL = sRGB_(true); +AdobeRGB_ AdobeRGB = AdobeRGB_(false); +AdobeRGB_ AdobeRGBL = AdobeRGB_(true); +WideGamutRGB_ WideGamutRGB = WideGamutRGB_(false); +WideGamutRGB_ WideGamutRGBL = WideGamutRGB_(true); +ProPhotoRGB_ ProPhotoRGB = ProPhotoRGB_(false); +ProPhotoRGB_ ProPhotoRGBL = ProPhotoRGB_(true); +DCI_P3_RGB_ DCI_P3_RGB = DCI_P3_RGB_(false); +DCI_P3_RGB_ DCI_P3_RGBL = DCI_P3_RGB_(true); +AppleRGB_ AppleRGB = AppleRGB_(false); +AppleRGB_ AppleRGBL = AppleRGB_(true); +REC_709_RGB_ REC_709_RGB = REC_709_RGB_(false); +REC_709_RGB_ REC_709_RGBL = REC_709_RGB_(true); +REC_2020_RGB_ REC_2020_RGB = REC_2020_RGB_(false); +REC_2020_RGB_ REC_2020_RGBL = REC_2020_RGB_(true); + +/* *\ brief Bind RGB with RGBL. + */ + +ColorSpaceInitial::ColorSpaceInitial() { + sRGB.bind(sRGBL); + AdobeRGB.bind(AdobeRGBL); + WideGamutRGB.bind(WideGamutRGBL); + ProPhotoRGB.bind(ProPhotoRGBL); + DCI_P3_RGB.bind(DCI_P3_RGBL); + AppleRGB.bind(AppleRGBL); + REC_709_RGB.bind(REC_709_RGBL); + REC_2020_RGB.bind(REC_2020_RGBL); +} + +ColorSpaceInitial color_space_initial; + +/* *\ brief Enum of the possible types of CAMs. + */ + +/* *\ brief XYZ color space. + * Chromatic adaption matrices. + */ +Operations XYZ::cam(IO dio, CAM method) { + return (io == dio) ? Operations() + : Operations({Operation(cam_(io, dio, method).t())}); +} +Mat XYZ::cam_(IO sio, IO dio, CAM method) const { + if (sio == dio) { + return Mat::eye(cv::Size(3, 3), CV_64FC1); + } + if (cams.count(std::make_tuple(dio, sio, method)) == 1) { + return cams[std::make_tuple(dio, sio, method)]; + } + + // Function from http + // ://www.brucelindbloom.com/index.html?ColorCheckerRGB.html. + Mat XYZws = Mat(illuminants.find(dio)->second); + Mat XYZWd = Mat(illuminants.find(sio)->second); + Mat MA = MAs.at(method)[0]; + Mat MA_inv = MAs.at(method)[1]; + Mat M = MA_inv * Mat::diag((MA * XYZws) / (MA * XYZWd)) * MA; + cams[std::make_tuple(dio, sio, method)] = M; + cams[std::make_tuple(sio, dio, method)] = M.inv(); + return M; +} + +/* *\ brief Lab color space. + */ +Lab::Lab(IO io_) : ColorSpace(io_, "Lab", true) { + to = {Operation([this](Mat src) -> Mat { return tosrc(src); })}; + from = {Operation([this](Mat src) -> Mat { return fromsrc(src); })}; +} + +Vec3d Lab::fromxyz(cv::Vec3d& xyz) { + double x = xyz[0] / illuminants.find(io)->second[0], + y = xyz[1] / illuminants.find(io)->second[1], + z = xyz[2] / illuminants.find(io)->second[2]; + auto f = [](double t) -> double { + return t > t0 ? std::cbrt(t) : (m * t + c); + }; + double fx = f(x), fy = f(y), fz = f(z); + return {116. * fy - 16., 500 * (fx - fy), 200 * (fy - fz)}; +} + +/* *\ brief Calculate From. + *\ param src the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat + */ +Mat Lab::fromsrc(Mat& src) { + return channelWise(src, + [this](cv::Vec3d a) -> cv::Vec3d { return fromxyz(a); }); +} + +Vec3d Lab::tolab(cv::Vec3d& lab) { + auto f_inv = [](double t) -> double { + return t > delta ? pow(t, 3.0) : (t - c) / m; + }; + double L = (lab[0] + 16.) / 116., a = lab[1] / 500., b = lab[2] / 200.; + return {illuminants.find(io)->second[0] * f_inv(L + a), + illuminants.find(io)->second[1] * f_inv(L), + illuminants.find(io)->second[2] * f_inv(L - b)}; +} + +/* *\ brief Calculate To. + *\ param src the input array, type of cv::Mat. + *\ return the output array, type of cv::Mat + */ +Mat Lab::tosrc(Mat& src) { + return channelWise(src, + [this](cv::Vec3d a) -> cv::Vec3d { return tolab(a); }); +} + +} // namespace ccm +} // namespace cv diff --git a/modules/mcc/src/linearize.cpp b/modules/mcc/src/linearize.cpp new file mode 100644 index 00000000000..cfa2f661282 --- /dev/null +++ b/modules/mcc/src/linearize.cpp @@ -0,0 +1,130 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#include "precomp.hpp" + +namespace cv +{ +namespace ccm +{ + +Polyfit::Polyfit(Mat x, Mat y, int deg_) :deg(deg_) +{ + int n = x.cols * x.rows * x.channels(); + x = x.reshape(1, n); + y = y.reshape(1, n); + Mat_ A = Mat_::ones(n, deg + 1); + for (int i = 0; i < n; ++i) + { + for (int j = 1; j < A.cols; ++j) + { + A.at(i, j) = x.at(i) * A.at(i, j - 1); + } + } + Mat y_(y); + cv::solve(A, y_, p, DECOMP_SVD); +} + +Mat Polyfit::operator()(const Mat& inp) +{ + return elementWise(inp, [this](double x)->double {return fromEW(x); }); +}; + +double Polyfit::fromEW(double x) +{ + double res = 0; + for (int d = 0; d <= deg; ++d) + { + res += pow(x, d) * p.at(d, 0); + } + return res; +}; + +LogPolyfit::LogPolyfit(Mat x, Mat y, int deg_) :deg(deg_) +{ + Mat mask_ = (x > 0) & (y > 0); + Mat src_, dst_, s_, d_; + src_ = maskCopyTo(x, mask_); + dst_ = maskCopyTo(y, mask_); + log(src_, s_); + log(dst_, d_); + p = Polyfit(s_, d_, deg); +} + +Mat LogPolyfit::operator()(const Mat& inp) +{ + Mat mask_ = inp >= 0; + Mat y, y_, res; + log(inp, y); + y = p(y); + exp(y, y_); + y_.copyTo(res, mask_); + return res; +}; + +Mat Linear::linearize(Mat inp) +{ + return inp; +}; + +Mat LinearGamma::linearize(Mat inp) +{ + return gammaCorrection(inp, gamma); +}; + +std::shared_ptr getLinear(double gamma, int deg, Mat src, Color dst, Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type) +{ + std::shared_ptr p = std::make_shared(); + switch (linear_type) + { + case cv::ccm::IDENTITY_: + p.reset(new LinearIdentity()); + break; + case cv::ccm::GAMMA: + p.reset(new LinearGamma(gamma)); + break; + case cv::ccm::COLORPOLYFIT: + p.reset(new LinearColor(deg, src, dst, mask, cs)); + break; + case cv::ccm::COLORLOGPOLYFIT: + p.reset(new LinearColor(deg, src, dst, mask, cs)); + break; + case cv::ccm::GRAYPOLYFIT: + p.reset(new LinearGray(deg, src, dst, mask, cs)); + break; + case cv::ccm::GRAYLOGPOLYFIT: + p.reset(new LinearGray(deg, src, dst, mask, cs)); + break; + default: + throw std::invalid_argument{ "Wrong linear_type!" }; + break; + } + return p; +}; + +} // namespace ccm +} // namespace cv \ No newline at end of file From 25d0b8aadaa8eee47e3682794e16f762f01b10b4 Mon Sep 17 00:00:00 2001 From: Jinheng Zhang Date: Thu, 17 Sep 2020 11:08:37 +0800 Subject: [PATCH 25/71] Update test cases --- modules/mcc/test/test_ccm.cpp | 149 +++++++++++++++++ modules/mcc/test/test_color.cpp | 165 +++++++++++++++++++ modules/mcc/test/test_colorspace.cpp | 84 ++++++++++ modules/mcc/test/test_io.cpp | 44 +++++ modules/mcc/test/test_linearize.cpp | 232 +++++++++++++++++++++++++++ modules/mcc/test/test_precomp.hpp | 2 + modules/mcc/test/test_utils.cpp | 50 ++++++ 7 files changed, 726 insertions(+) create mode 100644 modules/mcc/test/test_ccm.cpp create mode 100644 modules/mcc/test/test_color.cpp create mode 100644 modules/mcc/test/test_colorspace.cpp create mode 100644 modules/mcc/test/test_io.cpp create mode 100644 modules/mcc/test/test_linearize.cpp create mode 100644 modules/mcc/test/test_utils.cpp diff --git a/modules/mcc/test/test_ccm.cpp b/modules/mcc/test/test_ccm.cpp new file mode 100644 index 00000000000..08763ebc4ad --- /dev/null +++ b/modules/mcc/test/test_ccm.cpp @@ -0,0 +1,149 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include "test_precomp.hpp" + +#include + +namespace opencv_test +{ +namespace +{ + +Mat s = (Mat_(24, 1) << + Vec3d(214.11, 98.67, 37.97), + Vec3d(231.94, 153.1, 85.27), + Vec3d(204.08, 143.71, 78.46), + Vec3d(190.58, 122.99, 30.84), + Vec3d(230.93, 148.46, 100.84), + Vec3d(228.64, 206.97, 97.5), + Vec3d(229.09, 137.07, 55.29), + Vec3d(189.21, 111.22, 92.66), + Vec3d(223.5, 96.42, 75.45), + Vec3d(201.82, 69.71, 50.9), + Vec3d(240.52, 196.47, 59.3), + Vec3d(235.73, 172.13, 54.), + Vec3d(131.6, 75.04, 68.86), + Vec3d(189.04, 170.43, 42.05), + Vec3d(222.23, 74., 71.95), + Vec3d(241.01, 199.1, 61.15), + Vec3d(224.99, 101.4, 100.24), + Vec3d(174.58, 152.63, 91.52), + Vec3d(248.06, 227.69, 140.5), + Vec3d(241.15, 201.38, 115.58), + Vec3d(236.49, 175.87, 88.86), + Vec3d(212.19, 133.49, 54.79), + Vec3d(181.17, 102.94, 36.18), + Vec3d(115.1, 53.77, 15.23)); + +TEST(CV_ccmRunColorCorrection, test_model) +{ + ColorCorrectionModel model(s / 255, Color(ColorChecker2005_LAB_D50_2, Lab_D50_2)); + Mat src_rgbl = (Mat_(24, 1) << + Vec3d(0.68078957, 0.12382801, 0.01514889), + Vec3d(0.81177942, 0.32550452, 0.089818), + Vec3d(0.61259378, 0.2831933, 0.07478902), + Vec3d(0.52696493, 0.20105976, 0.00958657), + Vec3d(0.80402284, 0.30419523, 0.12989841), + Vec3d(0.78658646, 0.63184111, 0.12062068), + Vec3d(0.78999637, 0.25520249, 0.03462853), + Vec3d(0.51866697, 0.16114393, 0.1078387), + Vec3d(0.74820768, 0.11770076, 0.06862177), + Vec3d(0.59776825, 0.05765816, 0.02886627), + Vec3d(0.8793145, 0.56346033, 0.0403954), + Vec3d(0.84124847, 0.42120746, 0.03287592), + Vec3d(0.23333214, 0.06780408, 0.05612276), + Vec3d(0.5176423, 0.41210976, 0.01896255), + Vec3d(0.73888613, 0.06575388, 0.06181293), + Vec3d(0.88326036, 0.58018751, 0.04321991), + Vec3d(0.75922531, 0.13149072, 0.1282041), + Vec3d(0.4345097, 0.32331019, 0.10494139), + Vec3d(0.94110142, 0.77941419, 0.26946323), + Vec3d(0.88438952, 0.5949049 , 0.17536928), + Vec3d(0.84722687, 0.44160449, 0.09834799), + Vec3d(0.66743106, 0.24076803, 0.03394333), + Vec3d(0.47141286, 0.13592419, 0.01362205), + Vec3d(0.17377101, 0.03256864, 0.00203026)); + ASSERT_MAT_NEAR(src_rgbl, model.src_rgbl, 1e-4); + + Mat dst_rgbl = (Mat_(24, 1) << + Vec3d(0.17303173, 0.08211037, 0.05672686), + Vec3d(0.56832031, 0.29269488, 0.21835529), + Vec3d(0.10365019, 0.19588357, 0.33140475), + Vec3d(0.10159676, 0.14892193, 0.05188294), + Vec3d(0.22159627, 0.21584476, 0.43461196), + Vec3d(0.10806379, 0.51437196, 0.41264213), + Vec3d(0.74736423, 0.20062878, 0.02807988), + Vec3d(0.05757947, 0.10516793, 0.40296109), + Vec3d(0.56676218, 0.08424805, 0.11969461), + Vec3d(0.11099515, 0.04230796, 0.14292554), + Vec3d(0.34546869, 0.50872001, 0.04944204), + Vec3d(0.79461323, 0.35942459, 0.02051968), + Vec3d(0.01710416, 0.05022043, 0.29220674), + Vec3d(0.05598012, 0.30021149, 0.06871162), + Vec3d(0.45585457, 0.03033727, 0.04085654), + Vec3d(0.85737614, 0.56757335, 0.0068503), + Vec3d(0.53348585, 0.08861148, 0.30750446), + Vec3d(-0.0374061, 0.24699498, 0.40041217), + Vec3d(0.91262695, 0.91493909, 0.89367049), + Vec3d(0.57981916, 0.59200418, 0.59328881), + Vec3d(0.35490581, 0.36544831, 0.36755375), + Vec3d(0.19007357, 0.19186587, 0.19308397), + Vec3d(0.08529188, 0.08887994, 0.09257601), + Vec3d(0.0303193, 0.03113818, 0.03274845)); + ASSERT_MAT_NEAR(dst_rgbl, model.dst_rgbl, 1e-4); + + Mat ccm = (Mat_(3, 3) << + 0.37408717, 0.02066172, 0.05796725, + 0.12684056, 0.77364991, -0.01566532, + -0.27464866, 0.00652140, 2.74593262); + ASSERT_MAT_NEAR(model.ccm, ccm, 1e-4); + + Mat mask = Mat::ones(24, 1, CV_8U); + ASSERT_MAT_NEAR(model.mask, mask, 0.0); +} + +TEST(CV_ccmRunColorCorrection, test_masks_weights_1) +{ + Mat weights_list_ = (Mat_(24, 1) << + 1.1, 0, 0, 1.2, 0, 0, + 1.3, 0, 0, 1.4, 0, 0, + 0.5, 0, 0, 0.6, 0, 0, + 0.7, 0, 0, 0.8, 0, 0); + ColorCorrectionModel model1(s / 255, Macbeth_D50_2, sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, { 0, 0.98 }, weights_list_, 1.5); + + Mat weights = (Mat_(8, 1) << + 1.15789474, 1.26315789, 1.36842105, 1.47368421, + 0.52631579, 0.63157895, 0.73684211, 0.84210526); + ASSERT_MAT_NEAR(model1.weights, weights, 1e-4); + + Mat mask = (Mat_(24, 1) << + true, false, false, true, false, false, + true, false, false, true, false, false, + true, false, false, true, false, false, + true, false, false, true, false, false); + ASSERT_MAT_NEAR(model1.mask, mask, 0.0); +} + +TEST(CV_ccmRunColorCorrection, test_masks_weights_2) +{ + ColorCorrectionModel model2(s / 255, Macbeth_D50_2, sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, {0.05, 0.93}, Mat(), 1.5); + + Mat weights = (Mat_(20, 1) << + 0.65554256, 1.49454705, 1.00499244, 0.79735434, 1.16327759, + 1.68623868, 1.37973155, 0.73213388, 1.0169629, 0.47430246, + 1.70312161, 0.45414218, 1.15910007, 0.7540434, 1.05049802, + 1.04551645, 1.54082353, 1.02453421, 0.6015915, 0.26154558); + ASSERT_MAT_NEAR(model2.weights, weights, 1e-4); + + Mat mask = (Mat_(24, 1) << + true, true, true, true, true, true, + true, true, true, true, false, true, + true, true, true, false, true, true, + false, false, true, true, true, true); + ASSERT_MAT_NEAR(model2.mask, mask, 0.0); +} + +} // namespace +} // namespace opencv_test diff --git a/modules/mcc/test/test_color.cpp b/modules/mcc/test/test_color.cpp new file mode 100644 index 00000000000..2b285579de4 --- /dev/null +++ b/modules/mcc/test/test_color.cpp @@ -0,0 +1,165 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include "test_precomp.hpp" + +namespace opencv_test +{ +namespace +{ + +TEST(CV_ccmColor, test_srgb) +{ + Color color = Color((Mat_(1, 1) << Vec3d(0.3, 0.2, 0.5)), sRGB); + Color color_rgb = color.to(sRGB); + Color color_rgbl = color.to(sRGBL); + Color color_xyz = color.to(XYZ_D65_2); + Color color_lab = color.to(Lab_D65_2); + Color color_xyz_d50 = color.to(XYZ_D50_2); + Color color_lab_d50 = color.to(Lab_D50_2); + + Mat color_rgb_M = (Mat_(1, 1) << Vec3d(0.3, 0.2, 0.5)); + Mat color_rgbl_M = (Mat_(1, 1) << Vec3d(0.07323896, 0.03310477, 0.21404114)); + Mat color_xyz_M = (Mat_(1, 1) << Vec3d(0.080666, 0.054699, 0.208766)); + Mat color_lab_M = (Mat_(1, 1) << Vec3d(28.0337, 29.9289, -39.4065)); + Mat color_xyz_d50_M = (Mat_(1, 1) << Vec3d(0.075310, 0.053003, 0.157097)); + Mat color_lab_d50_M = (Mat_(1, 1) << Vec3d(27.5736, 25.9112, -39.9261)); + + ASSERT_MAT_NEAR(color_rgb.colors, color_rgb_M, 1e-4); + ASSERT_MAT_NEAR(color_rgbl.colors, color_rgbl_M, 1e-4); + ASSERT_MAT_NEAR(color_xyz.colors, color_xyz_M, 1e-4); + ASSERT_MAT_NEAR(color_lab.colors, color_lab_M, 1e-2); + ASSERT_MAT_NEAR(color_xyz_d50.colors, color_xyz_d50_M, 1e-4); + ASSERT_MAT_NEAR(color_lab_d50.colors, color_lab_d50_M, 1e-2); +} + +TEST(CV_ccmColor, test_adobergbl) +{ + Color color = Color((Mat_(2, 1) << Vec3d(0.3, 0.2, 0.5), Vec3d(0.7, 0.1, 0.4)), AdobeRGBL); + Color color_rgb = color.to(AdobeRGB); + Color color_rgbl = color.to(AdobeRGBL); + Color color_xyz = color.to(XYZ_D65_2); + Color color_lab = color.to(Lab_D65_2); + Color color_xyz_d50 = color.to(XYZ_D50_2); + Color color_lab_d50 = color.to(Lab_D50_2); + + Mat color_rgb_M = (Mat_(2, 1) << Vec3d(0.578533, 0.481157, 0.729740), Vec3d(0.850335, 0.351119, 0.659353)); + Mat color_rgbl_M = (Mat_(2, 1) << Vec3d(0.3, 0.2, 0.5), Vec3d(0.7, 0.1, 0.4)); + Mat color_xyz_M = (Mat_(2, 1) << Vec3d(0.304223, 0.252320, 0.517802), Vec3d(0.497541, 0.301008, 0.422436)); + Mat color_lab_M = (Mat_(2, 1) << Vec3d(57.3008, 26.0707, -29.7295), Vec3d(61.7411, 67.8735, -11.8328)); + Mat color_xyz_d50_M = (Mat_(2, 1) << Vec3d(0.298587, 0.250078, 0.390442), Vec3d(0.507043, 0.305640, 0.317661)); + Mat color_lab_d50_M = (Mat_(2, 1) << Vec3d(57.0831, 23.2605, -29.8401), Vec3d(62.1379, 66.7756, -10.7684)); + + ASSERT_MAT_NEAR(color_rgb.colors, color_rgb_M, 1e-4); + ASSERT_MAT_NEAR(color_rgbl.colors, color_rgbl_M, 1e-4); + ASSERT_MAT_NEAR(color_xyz.colors, color_xyz_M, 1e-4); + ASSERT_MAT_NEAR(color_lab.colors, color_lab_M, 1e-2); + ASSERT_MAT_NEAR(color_xyz_d50.colors, color_xyz_d50_M, 1e-4); + ASSERT_MAT_NEAR(color_lab_d50.colors, color_lab_d50_M, 1e-2); +} + +TEST(CV_ccmColor, test_xyz) +{ + Color color = Color((Mat_(1, 1) << Vec3d(0.3, 0.2, 0.5)), XYZ_D65_2); + Color color_rgb = color.to(ProPhotoRGB, VON_KRIES); + Color color_rgbl = color.to(ProPhotoRGBL, VON_KRIES); + Color color_xyz = color.to(XYZ_D65_2, VON_KRIES); + Color color_lab = color.to(Lab_D65_2, VON_KRIES); + Color color_xyz_d50 = color.to(XYZ_D50_2, VON_KRIES); + Color color_lab_d50 = color.to(Lab_D50_2, VON_KRIES); + + Mat color_rgb_M = (Mat_(1, 1) << Vec3d(0.530513, 0.351224, 0.648975)); + Mat color_rgbl_M = (Mat_(1, 1) << Vec3d(0.319487, 0.152073, 0.459209)); + Mat color_xyz_M = (Mat_(1, 1) << Vec3d(0.3, 0.2, 0.5)); + Mat color_lab_M = (Mat_(1, 1) << Vec3d(51.8372, 48.0307, -37.3395)); + Mat color_xyz_d50_M = (Mat_(1, 1) << Vec3d(0.289804, 0.200321, 0.378944)); + Mat color_lab_d50_M = (Mat_(1, 1) << Vec3d(51.8735, 42.3654, -37.2770)); + + ASSERT_MAT_NEAR(color_rgb.colors, color_rgb_M, 1e-4); + ASSERT_MAT_NEAR(color_rgbl.colors, color_rgbl_M, 1e-4); + ASSERT_MAT_NEAR(color_xyz.colors, color_xyz_M, 1e-4); + ASSERT_MAT_NEAR(color_lab.colors, color_lab_M, 1e-2); + ASSERT_MAT_NEAR(color_xyz_d50.colors, color_xyz_d50_M, 1e-4); + ASSERT_MAT_NEAR(color_lab_d50.colors, color_lab_d50_M, 1e-2); +} + +TEST(CV_ccmColor, test_lab) +{ + Color color = Color((Mat_(1, 1) << Vec3d(30., 20., 10.)), Lab_D50_2); + Color color_rgb = color.to(AppleRGB, IDENTITY); + Color color_rgbl = color.to(AppleRGBL, IDENTITY); + Color color_xyz = color.to(XYZ_D65_2, IDENTITY); + Color color_lab = color.to(Lab_D65_2, IDENTITY); + Color color_xyz_d50 = color.to(XYZ_D50_2, IDENTITY); + Color color_lab_d50 = color.to(Lab_D50_2, IDENTITY); + + Mat color_rgb_M = (Mat_(1, 1) << Vec3d(0.323999, 0.167314, 0.165874)); + Mat color_rgbl_M = (Mat_(1, 1) << Vec3d(0.131516, 0.040028, 0.039410)); + Mat color_xyz_M = (Mat_(1, 1) << Vec3d(0.079076, 0.062359, 0.045318)); + Mat color_lab_M = (Mat_(1, 1) << Vec3d(30.0001, 19.9998, 9.9999)); + Mat color_xyz_d50_M = (Mat_(1, 1) << Vec3d(0.080220, 0.062359, 0.034345)); + Mat color_lab_d50_M = (Mat_(1, 1) << Vec3d(30., 20., 10.)); + + ASSERT_MAT_NEAR(color_rgb.colors, color_rgb_M, 1e-4); + ASSERT_MAT_NEAR(color_rgbl.colors, color_rgbl_M, 1e-4); + ASSERT_MAT_NEAR(color_xyz.colors, color_xyz_M, 1e-4); + ASSERT_MAT_NEAR(color_lab.colors, color_lab_M, 1e-2); + ASSERT_MAT_NEAR(color_xyz_d50.colors, color_xyz_d50_M, 1e-4); + ASSERT_MAT_NEAR(color_lab_d50.colors, color_lab_d50_M, 1e-2); +} + +TEST(CV_ccmColor, test_grays) +{ + Color color_d50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2); + Color color_d65_2(ColorChecker2005_LAB_D65_2, Lab_D65_2); + + Mat grays = (Mat_(24, 1) << + false, false, false, false, false, false, + false, false, false, false, false, false, + false, false, false, false, false, false, + true, true, true, true, true, true); + color_d50_2.getGray(); + color_d65_2.getGray(); + + ASSERT_MAT_NEAR(color_d50_2.grays > 0, grays > 0, 0.0); + ASSERT_MAT_NEAR(color_d65_2.grays > 0, grays > 0, 0.0); +} + +TEST(CV_ccmColor, test_gray_luminant) +{ + Color color1 = Color((Mat_(1, 1) << Vec3d(0.3, 0.2, 0.5)), sRGB); + Mat toGray1 = (Mat_(1, 1) <<0.054699); + Mat toLuminant1 = (Mat_(1, 1) <<28.0337); + ASSERT_MAT_NEAR(color1.toGray(color1.cs.io), toGray1, 1e-4); + ASSERT_MAT_NEAR(color1.toLuminant(color1.cs.io), toLuminant1, 1e-4); + + Color color2 = Color((Mat_(2, 1) << Vec3d(0.3, 0.2, 0.5), Vec3d(0.7, 0.1, 0.4)), sRGB); + Mat toGray2 = (Mat_(2, 1) <<0.054699, 0.112033); + Mat toLuminant2 = (Mat_(2, 1) <<28.0337, 39.9207); + ASSERT_MAT_NEAR(color2.toGray(color2.cs.io), toGray2, 1e-4); + ASSERT_MAT_NEAR(color2.toLuminant(color2.cs.io), toLuminant2, 1e-4); +} + +TEST(CV_ccmColor, test_diff) +{ + Color color1 = Color((Mat_(1, 1) << Vec3d(0.3, 0.2, 0.5)), sRGB); + Color color2 = Color((Mat_(1, 1) << Vec3d(0.3, 0.2, 0.5)), XYZ_D50_2); + + Mat diff_CIE2000 = (Mat_(1, 1) <<22.58031); + Mat diff_CIE94_GRAPHIC_ARTS = (Mat_(1, 1) <<25.701214); + Mat diff_CIE76 = (Mat_(1, 1) <<34.586351); + Mat diff_CMC_1TO1 = (Mat_(1, 1) <<33.199419); + Mat diff_RGB = (Mat_(1, 1) <<0.51057); + Mat diff_RGBL = (Mat_(1, 1) <<0.556741); + + ASSERT_MAT_NEAR(color1.diff(color2, D65_2, CIE2000), diff_CIE2000, 1e-2); + ASSERT_MAT_NEAR(color1.diff(color2, D65_2, CIE94_GRAPHIC_ARTS), diff_CIE94_GRAPHIC_ARTS, 1e-2); + ASSERT_MAT_NEAR(color1.diff(color2, D65_2, CIE76), diff_CIE76, 1e-2); + ASSERT_MAT_NEAR(color1.diff(color2, D65_2, CMC_1TO1), diff_CMC_1TO1, 1e-2); + ASSERT_MAT_NEAR(color1.diff(color2, D65_2, RGB), diff_RGB, 1e-4); + ASSERT_MAT_NEAR(color1.diff(color2, D65_2, RGBL), diff_RGBL, 1e-4); +} + +} // namespace +} // namespace opencv_test \ No newline at end of file diff --git a/modules/mcc/test/test_colorspace.cpp b/modules/mcc/test/test_colorspace.cpp new file mode 100644 index 00000000000..fc6fbea7543 --- /dev/null +++ b/modules/mcc/test/test_colorspace.cpp @@ -0,0 +1,84 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include "test_precomp.hpp" + +namespace opencv_test +{ +namespace +{ + +TEST(CV_ccmColorspace, test_sRGB_M) +{ + Mat to = (Mat_(3, 3) << + 0.4124564, 0.3575761, 0.1804375, + 0.2126729, 0.7151522, 0.0721750, + 0.0193339, 0.1191920, 0.9503041); + Mat from = (Mat_(3, 3) << + 3.2404542, -1.5371385, -0.4985314, + -0.9692660, 1.8760108, 0.0415560, + 0.0556434, -0.2040259, 1.0572252); + ASSERT_MAT_NEAR(sRGB.M_to, to, 1e-4); + ASSERT_MAT_NEAR(sRGB.M_from, from, 1e-4); +} + +TEST(CV_ccmColorspace, test_AdobeRGB_M) +{ + Mat to = (Mat_(3, 3) << + 0.5767309, 0.1855540, 0.1881852, + 0.2973769, 0.6273491, 0.0752741, + 0.0270343, 0.0706872, 0.9911085); + Mat from = (Mat_(3, 3) << + 2.0413690, -0.5649464, -0.3446944, + -0.9692660, 1.8760108, 0.0415560, + 0.0134474, -0.1183897, 1.0154096); + ASSERT_MAT_NEAR(AdobeRGB.M_to, to, 1e-4); + ASSERT_MAT_NEAR(AdobeRGB.M_from, from, 1e-4); +} + +TEST(CV_ccmColorspace, test_WideGamutRGB_M) +{ + Mat to = (Mat_(3, 3) << + 0.7161046, 0.1009296, 0.1471858, + 0.2581874, 0.7249378, 0.0168748, + 0.0000000, 0.0517813, 0.7734287); + Mat from = (Mat_(3, 3) << + 1.4628067, -0.1840623, -0.2743606, + -0.5217933, 1.4472381, 0.0677227, + 0.0349342, -0.0968930, 1.2884099); + ASSERT_MAT_NEAR(WideGamutRGB.M_to, to, 1e-2); + ASSERT_MAT_NEAR(WideGamutRGB.M_from, from, 1e-2); +} + +// wont' work +//TEST(CV_ccmColorspace, test_WideGamutRGB_M) +//{ +// Mat to = (Mat_(3, 3) << +// 0.7161046, 0.1009296, 0.1471858, +// 0.2581874, 0.7249378, 0.0168748, +// 0.0000000, 0.0517813, 0.7734287); +// Mat from = (Mat_(3, 3) << +// 1.4628067, -0.1840623, -0.2743606, +// -0.5217933, 1.4472381, 0.0677227, +// 0.0349342, -0.0968930, 1.2884099) +// ASSERT_MAT_NEAR(WideGamutRGB.M_to, to, 1e-2); +// ASSERT_MAT_NEAR(WideGamutRGB.M_from, from, 1e-2); +//} +// +TEST(CV_ccmColorspace, test_ProPhotoRGB_M) +{ + Mat to = (Mat_(3, 3) << + 0.7976749, 0.1351917, 0.0313534, + 0.2880402, 0.7118741, 0.0000857, + 0.0000000, 0.0000000, 0.8252100); + Mat from = (Mat_(3, 3) << + 1.3459433, -0.2556075, -0.0511118, + -0.5445989, 1.5081673, 0.0205351, + 0.0000000, 0.0000000, 1.2118128); + ASSERT_MAT_NEAR(ProPhotoRGB.M_to, to, 1e-2); + ASSERT_MAT_NEAR(ProPhotoRGB.M_from, from, 1e-2); +} + +} // namespace +} // namespace opencv_test diff --git a/modules/mcc/test/test_io.cpp b/modules/mcc/test/test_io.cpp new file mode 100644 index 00000000000..daf33080d54 --- /dev/null +++ b/modules/mcc/test/test_io.cpp @@ -0,0 +1,44 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include "test_precomp.hpp" + +#include +#include + +namespace opencv_test +{ +namespace +{ + +using namespace std; + +/* +std::map> illuminants_test = +{ + {A_2, { 1.098466069456375, 1, 0.3558228003436005 }}, + {A_10, { 1.111420406956693, 1, 0.3519978321919493 }}, + {D50_2, { 0.9642119944211994, 1, 0.8251882845188288 }}, + {D50_10, { 0.9672062750333777, 1, 0.8142801513128616 }}, + {D55_2, { 0.956797052643698, 1, 0.9214805860173273 }}, + {D55_10, { 0.9579665682254781, 1, 0.9092525159847462 }}, + {D65_2, { 0.95047, 1., 1.08883 }}, + {D65_10, { 0.94811, 1., 1.07304 }}, + {D75_2, { 0.9497220898840717, 1, 1.226393520724154 }}, + {D75_10, { 0.9441713925645873, 1, 1.2064272211720228 }}, + {E_2, { 1., 1., 1. }}, + {E_10, { 1., 1., 1. }}, +}; + +TEST(CV_ccmIO, test_illuminants) +{ + for (auto i = illuminants.begin(); i != illuminants.end(); ++i) + { + ASSERT_EQ(illuminants[i->first], illuminants_test[i->first]); + } +} +*/ + +} // namespace +} // namespace opencv_test diff --git a/modules/mcc/test/test_linearize.cpp b/modules/mcc/test/test_linearize.cpp new file mode 100644 index 00000000000..ca62b44d790 --- /dev/null +++ b/modules/mcc/test/test_linearize.cpp @@ -0,0 +1,232 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include "test_precomp.hpp" + +namespace opencv_test +{ +namespace +{ + +Mat s_origin = (Mat_(24, 1) << + Vec3d(214.11, 98.67, 37.97), + Vec3d(231.94, 153.1, 85.27), + Vec3d(204.08, 143.71, 78.46), + Vec3d(190.58, 122.99, 30.84), + Vec3d(230.93, 148.46, 100.84), + Vec3d(228.64, 206.97, 97.5), + Vec3d(229.09, 137.07, 55.29), + Vec3d(189.21, 111.22, 92.66), + Vec3d(223.5, 96.42, 75.45), + Vec3d(201.82, 69.71, 50.9), + Vec3d(240.52, 196.47, 59.3), + Vec3d(235.73, 172.13, 54.), + Vec3d(131.6, 75.04, 68.86), + Vec3d(189.04, 170.43, 42.05), + Vec3d(222.23, 74., 71.95), + Vec3d(241.01, 199.1, 61.15), + Vec3d(224.99, 101.4, 100.24), + Vec3d(174.58, 152.63, 91.52), + Vec3d(248.06, 227.69, 140.5), + Vec3d(241.15, 201.38, 115.58), + Vec3d(236.49, 175.87, 88.86), + Vec3d(212.19, 133.49, 54.79), + Vec3d(181.17, 102.94, 36.18), + Vec3d(115.1, 53.77, 15.23)); +Mat s = s_origin / 255; +double gamma = 2.2; +int deg = 3; + +Color color = Macbeth_D50_2; +RGBBase_ cs = sRGB; +Mat mask = saturate(s, 0.05, 0.93); + +TEST(CV_ccmLinearize, test_identity) +{ + Mat y = (Mat_(24, 1) << + Vec3d(0.83964706, 0.38694118, 0.14890196), + Vec3d(0.90956863, 0.60039216, 0.33439216), + Vec3d(0.80031373, 0.56356863, 0.30768627), + Vec3d(0.74737255, 0.48231373, 0.12094118), + Vec3d(0.90560784, 0.58219608, 0.39545098), + Vec3d(0.89662745, 0.81164706, 0.38235294), + Vec3d(0.89839216, 0.53752941, 0.21682353), + Vec3d(0.742, 0.43615686, 0.36337255), + Vec3d(0.87647059, 0.37811765, 0.29588235), + Vec3d(0.79145098, 0.27337255, 0.19960784), + Vec3d(0.94321569, 0.77047059, 0.23254902), + Vec3d(0.92443137, 0.67501961, 0.21176471), + Vec3d(0.51607843, 0.29427451, 0.27003922), + Vec3d(0.74133333, 0.66835294, 0.16490196), + Vec3d(0.8714902, 0.29019608, 0.28215686), + Vec3d(0.94513725, 0.78078431, 0.23980392), + Vec3d(0.88231373, 0.39764706, 0.39309804), + Vec3d(0.68462745, 0.59854902, 0.35890196), + Vec3d(0.97278431, 0.89290196, 0.55098039), + Vec3d(0.94568627, 0.78972549, 0.4532549), + Vec3d(0.92741176, 0.68968627, 0.34847059), + Vec3d(0.83211765, 0.5234902 , 0.21486275), + Vec3d(0.71047059, 0.40368627, 0.14188235), + Vec3d(0.45137255, 0.21086275, 0.05972549)); + + ASSERT_MAT_NEAR(LinearIdentity().linearize(s), y, 1e-4); +} + +TEST(CV_ccmLinearize, test_gamma) +{ + Mat y = (Mat_(24, 1) << + Vec3d(0.68078957, 0.12382801, 0.01514889), + Vec3d(0.81177942, 0.32550452, 0.089818), + Vec3d(0.61259378, 0.2831933 , 0.07478902), + Vec3d(0.52696493, 0.20105976, 0.00958657), + Vec3d(0.80402284, 0.30419523, 0.12989841), + Vec3d(0.78658646, 0.63184111, 0.12062068), + Vec3d(0.78999637, 0.25520249, 0.03462853), + Vec3d(0.51866697, 0.16114393, 0.1078387), + Vec3d(0.74820768, 0.11770076, 0.06862177), + Vec3d(0.59776825, 0.05765816, 0.02886627), + Vec3d(0.8793145, 0.56346033, 0.0403954), + Vec3d(0.84124847, 0.42120746, 0.03287592), + Vec3d(0.23333214, 0.06780408, 0.05612276), + Vec3d(0.5176423, 0.41210976, 0.01896255), + Vec3d(0.73888613, 0.06575388, 0.06181293), + Vec3d(0.88326036, 0.58018751, 0.04321991), + Vec3d(0.75922531, 0.13149072, 0.1282041), + Vec3d(0.4345097, 0.32331019, 0.10494139), + Vec3d(0.94110142, 0.77941419, 0.26946323), + Vec3d(0.88438952, 0.5949049 , 0.17536928), + Vec3d(0.84722687, 0.44160449, 0.09834799), + Vec3d(0.66743106, 0.24076803, 0.03394333), + Vec3d(0.47141286, 0.13592419, 0.01362205), + Vec3d(0.17377101, 0.03256864, 0.00203026)); + + ASSERT_MAT_NEAR(LinearGamma(gamma).linearize(s), y, 1e-4); +} + +TEST(CV_ccmLinearize, test_color_polyfit) +{ + Mat y = (Mat_(24, 1) << + Vec3d(2.63480590e-01, 8.19784230e-02, 5.88380570e-02), + Vec3d(5.00308824e-01, 2.55670153e-01, 2.84774400e-01), + Vec3d(1.65547676e-01, 2.18326729e-01, 2.34834241e-01), + Vec3d(6.91579431e-02, 1.46243551e-01, 4.85506219e-02), + Vec3d(4.84584944e-01, 2.36873580e-01, 4.21828895e-01), + Vec3d(4.49999903e-01, 5.15593650e-01, 3.89716261e-01), + Vec3d(4.56680121e-01, 1.93624454e-01, 1.09260805e-01), + Vec3d(6.14667752e-02, 1.12219287e-01, 3.45822331e-01), + Vec3d(3.77645006e-01, 7.72485552e-02, 2.14671313e-01), + Vec3d(1.46690033e-01, 3.83676678e-02, 9.30261311e-02), + Vec3d(6.45841448e-01, 4.59722537e-01, 1.26168624e-01), + Vec3d(5.61924874e-01, 3.39304873e-01, 1.04244341e-01), + Vec3d(-1.24921202e-03, 4.34819857e-02, 1.74574965e-01), + Vec3d(6.05378564e-02, 3.31429676e-01, 6.74475908e-02), + Vec3d(3.60866062e-01, 4.23768038e-02, 1.92686670e-01), + Vec3d(6.54814616e-01, 4.73515714e-01, 1.34642338e-01), + Vec3d(3.97880165e-01, 8.80047529e-02, 4.15950016e-01), + Vec3d(8.88761384e-04, 2.53736288e-01, 3.35935826e-01), + Vec3d(7.92140863e-01, 6.31444183e-01, 9.20127919e-01), + Vec3d(6.57391804e-01, 4.85584457e-01, 5.81564694e-01), + Vec3d(5.74784077e-01, 3.56891943e-01, 3.13534251e-01), + Vec3d(2.42877023e-01, 1.80918764e-01, 1.07292088e-01), + Vec3d(2.34750448e-02, 9.15416417e-02, 5.56885760e-02), + Vec3d(4.16360011e-02, 3.14799517e-02, 4.67810688e-02)); + color.getGray(); + ASSERT_MAT_NEAR(LinearColor(deg, s, color, mask, cs).linearize(s), y, 1e-4); +} + +TEST(CV_ccmLinearize, test_color_logpolyfit) +{ + Mat y = (Mat_(24, 1) << + Vec3d(0.21210199, 0.08042872, 0.06177358), + Vec3d(0.43902276, 0.25803696, 0.22625212), + Vec3d(0.1392843, 0.21910892, 0.16649895), + Vec3d(0.07929871, 0.14429388, 0.06124959), + Vec3d(0.42175787, 0.23847603, 0.50200816), + Vec3d(0.38486859, 0.49908647, 0.41903521), + Vec3d(0.39187715, 0.19330825, 0.07678465), + Vec3d(0.07496683, 0.10997862, 0.3253915), + Vec3d(0.31256906, 0.07589457, 0.14682645), + Vec3d(0.12666458, 0.03865245, 0.07035133), + Vec3d(0.61317011, 0.453896, 0.08471713), + Vec3d(0.509618, 0.34295792, 0.07466823), + Vec3d(0.01792609, 0.04375426, 0.11416985), + Vec3d(0.07444757, 0.33517131, 0.06308572), + Vec3d(0.29675398, 0.04267084, 0.1279182), + Vec3d(0.62473933, 0.46546083, 0.08914635), + Vec3d(0.33211973, 0.08623901, 0.48580852), + Vec3d(0.04223237, 0.25602914, 0.30707565), + Vec3d(0.81340438, 0.57786249, 5.63433098), + Vec3d(0.62807965, 0.47536376, 1.17181577), + Vec3d(0.52493661, 0.36014609, 0.26894465), + Vec3d(0.19575899, 0.18007616, 0.0759408), + Vec3d(0.05430091, 0.08966718, 0.06150038), + Vec3d(0.02983422, 0.03045434, 0.03305337)); + color.getGray(); + ASSERT_MAT_NEAR(LinearColor(deg, s, color, mask, cs).linearize(s), y, 1e-4); +} + +TEST(CV_ccmLinearize, test_gray_polyfit) +{ + Mat y = (Mat_(24, 1) << + Vec3d(0.51666899, 0.05119734, 0.08355961), + Vec3d(0.59846831, 0.22746696, 0.03275719), + Vec3d(0.46851612, 0.18821734, 0.02831637), + Vec3d(0.40274707, 0.11294869, 0.10983447), + Vec3d(0.59401581, 0.20773439, 0.05530918), + Vec3d(0.58382767, 0.48249077, 0.04910519), + Vec3d(0.58583962, 0.16222916, 0.04147151), + Vec3d(0.39606823, 0.07893876, 0.04140637), + Vec3d(0.56052673, 0.0472528, 0.02748943), + Vec3d(0.45754742, 0.02793019, 0.04935323), + Vec3d(0.63517156, 0.43148826, 0.0358448), + Vec3d(0.61493813, 0.31386138, 0.04359845), + Vec3d(0.14207934, 0.02743228, 0.02822652), + Vec3d(0.39523985, 0.30585866, 0.07094004), + Vec3d(0.55468508, 0.02734776, 0.0274375), + Vec3d(0.6372021, 0.44431108, 0.03374266), + Vec3d(0.56733935, 0.05641847, 0.05414246), + Vec3d(0.32546855, 0.22544012, 0.0398225), + Vec3d(0.66553671, 0.57956479, 0.17545548), + Vec3d(0.63778086, 0.45540855, 0.09069633), + Vec3d(0.61819338, 0.33161218, 0.03647687), + Vec3d(0.50753594, 0.14890516, 0.0422774), + Vec3d(0.35705032, 0.05956936, 0.08964481), + Vec3d(0.0893518, 0.04399409, 0.18717526)); + color.getGray(); + ASSERT_MAT_NEAR(LinearGray(deg, s, color, mask, cs).linearize(s), y, 1e-4); +} + +TEST(CV_ccmLinearize, test_gray_logpolyfit) +{ + Mat y = (Mat_(24, 1) << + Vec3d(4.60331981e-01, 5.51120816e-02, 3.97365482e-01), + Vec3d(4.73679407e-01, 2.29393836e-01, 3.84195886e-02), + Vec3d(4.38764462e-01, 1.88051166e-01, 3.33576233e-02), + Vec3d(3.95560026e-01, 1.11621603e-01, 5.06142257e+00), + Vec3d(4.73785486e-01, 2.08586471e-01, 5.87127685e-02), + Vec3d(4.73648490e-01, 4.45971601e-01, 5.32792915e-02), + Vec3d(4.73716999e-01, 1.61001724e-01, 4.02782927e-02), + Vec3d(3.90399630e-01, 7.97334727e-02, 4.64809651e-02), + Vec3d(4.71407192e-01, 5.16538838e-02, 3.18491932e-02), + Vec3d(4.32594201e-01, 3.03426453e-02, 5.36226594e-02), + Vec3d(4.68788432e-01, 4.16218138e-01, 3.42954435e-02), + Vec3d(4.72387015e-01, 3.17700868e-01, 4.32262905e-02), + Vec3d(1.40435644e-01, 3.16799217e-02, 3.02925240e-02), + Vec3d(3.89750609e-01, 3.09885279e-01, 1.63338781e-01), + Vec3d(4.70437333e-01, 3.12909236e-02, 3.07003735e-02), + Vec3d(4.68300410e-01, 4.24570259e-01, 3.26637048e-02), + Vec3d(4.72334300e-01, 5.96850848e-02, 5.76907392e-02), + Vec3d(3.28844114e-01, 2.27258414e-01, 4.50583791e-02), + Vec3d(4.58942833e-01, 4.73436696e-01, 1.74710299e-01), + Vec3d(4.68156974e-01, 4.31339830e-01, 9.05259853e-02), + Vec3d(4.71960375e-01, 3.34642678e-01, 4.19957551e-02), + Vec3d(4.56964629e-01, 1.47352730e-01, 4.13462335e-02), + Vec3d(3.57831381e-01, 6.24515609e-02, 6.54872609e-01), + Vec3d(8.92793201e-02, 4.38221622e-02, 3.22837394e+08)); + color.getGray(); + ASSERT_MAT_NEAR(LinearGray(deg, s, color, mask, cs).linearize(s)(cv::Rect(0, 0, 1, 23)), y(cv::Rect(0, 0, 1, 23)), 1e-4); +} + +} // namespace +} // namespace opencv_test \ No newline at end of file diff --git a/modules/mcc/test/test_precomp.hpp b/modules/mcc/test/test_precomp.hpp index 1f399441353..258c86f217c 100644 --- a/modules/mcc/test/test_precomp.hpp +++ b/modules/mcc/test/test_precomp.hpp @@ -6,11 +6,13 @@ #define __OPENCV_TEST_PRECOMP_HPP__ #include "opencv2/ts.hpp" +#include "opencv2/ts/cuda_test.hpp" #include "opencv2/mcc.hpp" namespace opencv_test { using namespace cv::mcc; +using namespace cv::ccm; } #endif diff --git a/modules/mcc/test/test_utils.cpp b/modules/mcc/test/test_utils.cpp new file mode 100644 index 00000000000..df8d70383a4 --- /dev/null +++ b/modules/mcc/test/test_utils.cpp @@ -0,0 +1,50 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include "test_precomp.hpp" + +namespace opencv_test +{ +namespace +{ + +TEST(CV_ccmUtils, test_gamma_correction) +{ + Mat x = (Mat_(4, 3) << + 0.8, -0.5, 0.6, + 0.2, 0.9, -0.9, + 1. , -0.2 , 0.4, + -0.4, 0.1, 0.3); + Mat y = (Mat_(4, 3) << + 0.6120656, -0.21763764, 0.32503696, + 0.02899119, 0.79311017, -0.79311017, + 1., -0.02899119, 0.13320851, + -0.13320851, 0.00630957, 0.07074028); + ASSERT_MAT_NEAR(gammaCorrection(x, 2.2), y, 1e-4); +} + +TEST(CV_ccmUtils, test_saturate) +{ + Mat x = (Mat_(5, 1) << + Vec3d(0., 0.5, 0.), + Vec3d(0., 0.3, 0.4), + Vec3d(0.3, 0.8, 0.4), + Vec3d(0.7, 0.6, 0.2), + Vec3d(1., 0.8, 0.5)); + Mat y = (Mat_(5, 1) <(1, 1) << Vec3d(0.2, 0.3, 0.4)); + Mat y = (Mat_(1, 1) <<0.28596); + std::cout << x << std::endl; + std::cout << "vs" << std::endl; + std::cout << y << std::endl; + ASSERT_MAT_NEAR(rgb2gray(x), y, 1e-4); +} + +} // namespace +} // namespace opencv_test From 7d133a0ede639d951bc92060127a67bde5c29282 Mon Sep 17 00:00:00 2001 From: ChenqiShan Date: Thu, 17 Sep 2020 17:04:30 +0800 Subject: [PATCH 26/71] Split distance, io and utils into cpp & hpp. Refer ccm.hpp in entrypoint header and update realted refs in sampe & tutorial --- modules/mcc/include/opencv2/mcc.hpp | 1 + modules/mcc/include/opencv2/mcc/distance.hpp | 222 ++--------------- modules/mcc/include/opencv2/mcc/io.hpp | 50 +--- modules/mcc/include/opencv2/mcc/utils.hpp | 204 +++++---------- .../mcc/samples/color_correction_model.cpp | 3 +- modules/mcc/src/distance.cpp | 233 ++++++++++++++++++ modules/mcc/src/io.cpp | 53 ++++ modules/mcc/src/utils.cpp | 120 +++++++++ .../basic_ccm/color_correction_model.markdown | 4 +- 9 files changed, 496 insertions(+), 394 deletions(-) create mode 100644 modules/mcc/src/distance.cpp create mode 100644 modules/mcc/src/io.cpp create mode 100644 modules/mcc/src/utils.cpp diff --git a/modules/mcc/include/opencv2/mcc.hpp b/modules/mcc/include/opencv2/mcc.hpp index 2027485fb2a..827af2abc68 100644 --- a/modules/mcc/include/opencv2/mcc.hpp +++ b/modules/mcc/include/opencv2/mcc.hpp @@ -32,6 +32,7 @@ #include "mcc/checker_detector.hpp" #include "mcc/checker_model.hpp" +#include "mcc/ccm.hpp" /** @defgroup mcc Macbeth Chart module diff --git a/modules/mcc/include/opencv2/mcc/distance.hpp b/modules/mcc/include/opencv2/mcc/distance.hpp index d0c9ac16307..e34980e4e9f 100644 --- a/modules/mcc/include/opencv2/mcc/distance.hpp +++ b/modules/mcc/include/opencv2/mcc/distance.hpp @@ -49,28 +49,12 @@ enum DISTANCE_TYPE RGBL }; -double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2); -double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH = 1.0, - double kC = 1.0, double kL = 1.0, double k1 = 0.045, - double k2 = 0.015); -double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2); -double toRad(double degree); -double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2); -double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1.0, - double kC = 1.0, double kH = 1.0); -double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2); -double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1, double kC = 1); -double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2); -double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2); -cv::Mat distance(cv::Mat src, cv::Mat ref, DISTANCE_TYPE distance_type); - - /* *\ brief distance between two points in formula CIE76 *\ param lab1 a 3D vector *\ param lab2 a 3D vector *\ return distance between lab1 and lab2 */ -double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2) { return norm(lab1 - lab2); }; +double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2); /* *\ brief distance between two points in formula CIE94 *\ param lab1 a 3D vector @@ -82,36 +66,15 @@ double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2) { return norm(lab1 - lab2); }; *\ param k2 second scale parameter *\ return distance between lab1 and lab2 */ -double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH, - double kC, double kL, double k1, double k2) -{ - double dl = lab1[0] - lab2[0]; - double c1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); - double c2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); - double dc = c1 - c2; - double da = lab1[1] - lab2[1]; - double db = lab1[2] - lab2[2]; - double dh = pow(da, 2) + pow(db, 2) - pow(dc, 2); - double sc = 1.0 + k1 * c1; - double sh = 1.0 + k2 * c1; - double sl = 1.0; - double res = - pow(dl / (kL * sl), 2) + pow(dc / (kC * sc), 2) + dh / pow(kH * sh, 2); - - return res > 0 ? sqrt(res) : 0; -} +double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH = 1.0, + double kC = 1.0, double kL = 1.0, double k1 = 0.045, + double k2 = 0.015); -double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2) -{ - return deltaCIE94(lab1, lab2); -} +double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2); -double toRad(double degree) { return degree / 180 * CV_PI; }; +double toRad(double degree); -double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2) -{ - return deltaCIE94(lab1, lab2, 1.0, 1.0, 2.0, 0.048, 0.014); -} +double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2); /* *\ brief distance between two points in formula CIE2000 *\ param lab1 a 3D vector @@ -121,99 +84,9 @@ double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2) *\ param kH Hue scale *\ return distance between lab1 and lab2 */ -double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL, - double kC, double kH) -{ - double delta_L_apo = lab2[0] - lab1[0]; - double l_bar_apo = (lab1[0] + lab2[0]) / 2.0; - double C1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); - double C2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); - double C_bar = (C1 + C2) / 2.0; - double G = sqrt(pow(C_bar, 7) / (pow(C_bar, 7) + pow(25, 7))); - double a1_apo = lab1[1] + lab1[1] / 2.0 * (1.0 - G); - double a2_apo = lab2[1] + lab2[1] / 2.0 * (1.0 - G); - double C1_apo = sqrt(pow(a1_apo, 2) + pow(lab1[2], 2)); - double C2_apo = sqrt(pow(a2_apo, 2) + pow(lab2[2], 2)); - double C_bar_apo = (C1_apo + C2_apo) / 2.0; - double delta_C_apo = C2_apo - C1_apo; - - double h1_apo; - if (C1_apo == 0) - { - h1_apo = 0.0; - } - else - { - h1_apo = atan2(lab1[2], a1_apo); - if (h1_apo < 0.0) h1_apo += 2. * CV_PI; - } - - double h2_apo; - if (C2_apo == 0) - { - h2_apo = 0.0; - } - else - { - h2_apo = atan2(lab2[2], a2_apo); - if (h2_apo < 0.0) h2_apo += 2. * CV_PI; - } - - double delta_h_apo; - if (abs(h2_apo - h1_apo) <= CV_PI) - { - delta_h_apo = h2_apo - h1_apo; - } - else if (h2_apo <= h1_apo) - { - delta_h_apo = h2_apo - h1_apo + 2. * CV_PI; - } - else - { - delta_h_apo = h2_apo - h1_apo - 2. * CV_PI; - } - - double H_bar_apo; - if (C1_apo == 0 || C2_apo == 0) - { - H_bar_apo = h1_apo + h2_apo; - } - else if (abs(h1_apo - h2_apo) <= CV_PI) - { - H_bar_apo = (h1_apo + h2_apo) / 2.0; - } - else if (h1_apo + h2_apo < 2. * CV_PI) - { - H_bar_apo = (h1_apo + h2_apo + 2. * CV_PI) / 2.0; - } - else - { - H_bar_apo = (h1_apo + h2_apo - 2. * CV_PI) / 2.0; - } - - double delta_H_apo = 2.0 * sqrt(C1_apo * C2_apo) * sin(delta_h_apo / 2.0); - double T = 1.0 - 0.17 * cos(H_bar_apo - toRad(30.)) + - 0.24 * cos(2.0 * H_bar_apo) + - 0.32 * cos(3.0 * H_bar_apo + toRad(6.0)) - - 0.2 * cos(4.0 * H_bar_apo - toRad(63.0)); - double sC = 1.0 + 0.045 * C_bar_apo; - double sH = 1.0 + 0.015 * C_bar_apo * T; - double sL = 1.0 + ((0.015 * pow(l_bar_apo - 50.0, 2.0)) / - sqrt(20.0 + pow(l_bar_apo - 50.0, 2.0))); - double RT = -2.0 * G * - sin(toRad(60.0) * - exp(-pow((H_bar_apo - toRad(275.0)) / toRad(25.0), 2.0))); - double res = - (pow(delta_L_apo / (kL * sL), 2.0) + pow(delta_C_apo / (kC * sC), 2.0) + - pow(delta_H_apo / (kH * sH), 2.0) + - RT * (delta_C_apo / (kC * sC)) * (delta_H_apo / (kH * sH))); - return res > 0 ? sqrt(res) : 0; -} - -double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2) -{ - return deltaCIEDE2000_(lab1, lab2); -} +double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1.0, + double kC = 1.0, double kH = 1.0); +double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2); /* *\ brief distance between two points in formula CMC *\ param lab1 a 3D vector @@ -222,77 +95,16 @@ double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2) *\ param kC Chroma scale *\ return distance between lab1 and lab2 */ -double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL, double kC) -{ - double dL = lab2[0] - lab1[0]; - double da = lab2[1] - lab1[1]; - double db = lab2[2] - lab1[2]; - double C1 = sqrt(pow(lab1[1], 2.0) + pow(lab1[2], 2.0)); - double C2 = sqrt(pow(lab2[1], 2.0) + pow(lab2[2], 2.0)); - double dC = C2 - C1; - double dH = sqrt(pow(da, 2) + pow(db, 2) - pow(dC, 2)); - - double H1; - if (C1 == 0.) - { - H1 = 0.0; - } - else - { - H1 = atan2(lab1[2], lab1[1]); - if (H1 < 0.0) H1 += 2. * CV_PI; - } - - double F = pow(C1, 2) / sqrt(pow(C1, 4) + 1900); - double T = (H1 > toRad(164) && H1 <= toRad(345)) - ? 0.56 + abs(0.2 * cos(H1 + toRad(168))) - : 0.36 + abs(0.4 * cos(H1 + toRad(35))); - double sL = - lab1[0] < 16. ? 0.511 : (0.040975 * lab1[0]) / (1.0 + 0.01765 * lab1[0]); - double sC = (0.0638 * C1) / (1.0 + 0.0131 * C1) + 0.638; - double sH = sC * (F * T + 1.0 - F); +double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1, double kC = 1); - return sqrt(pow(dL / (kL * sL), 2.0) + pow(dC / (kC * sC), 2.0) + - pow(dH / sH, 2.0)); -} +double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2); -double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2) -{ - return deltaCMC(lab1, lab2); -} +double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2); -double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2) -{ - return deltaCMC(lab1, lab2, 2, 1); -} +Mat distance(Mat src, Mat ref, DISTANCE_TYPE distance_type); -cv::Mat distance(cv::Mat src, cv::Mat ref, DISTANCE_TYPE distance_type) -{ - switch (distance_type) - { - case cv::ccm::CIE76: - return distanceWise(src, ref, deltaCIE76); - case cv::ccm::CIE94_GRAPHIC_ARTS: - return distanceWise(src, ref, deltaCIE94GraphicArts); - case cv::ccm::CIE94_TEXTILES: - return distanceWise(src, ref, deltaCIE94Textiles); - case cv::ccm::CIE2000: - return distanceWise(src, ref, deltaCIEDE2000); - case cv::ccm::CMC_1TO1: - return distanceWise(src, ref, deltaCMC1To1); - case cv::ccm::CMC_2TO1: - return distanceWise(src, ref, deltaCMC2To1); - case cv::ccm::RGB: - return distanceWise(src, ref, deltaCIE76); - case cv::ccm::RGBL: - return distanceWise(src, ref, deltaCIE76); - default: - throw std::invalid_argument{ "Wrong distance_type!" }; - break; - } -}; +} // namespace ccm +} // namespace cv -} // namespace ccm -} // namespace cv -#endif +#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/io.hpp b/modules/mcc/include/opencv2/mcc/io.hpp index dd62d46e423..e3d7f0bf58d 100644 --- a/modules/mcc/include/opencv2/mcc/io.hpp +++ b/modules/mcc/include/opencv2/mcc/io.hpp @@ -28,10 +28,8 @@ #ifndef __OPENCV_MCC_IO_HPP__ #define __OPENCV_MCC_IO_HPP__ -#include -#include -#include #include +#include namespace cv { @@ -39,29 +37,17 @@ namespace ccm { /* *\ brief Io is the meaning of illuminant and observer. See notes of ccm.hpp - * for supported list for illuminant and observer*/ -class IO + * for supported list for illuminant and observer*/ +class CV_EXPORTS_W IO { public: - std::string illuminant; std::string observer; - - IO() {}; - - IO(std::string illuminant_, std::string observer_) :illuminant(illuminant_), observer(observer_) {}; - - virtual ~IO() {}; - - bool operator<(const IO& other) const - { - return (illuminant < other.illuminant || ((illuminant == other.illuminant) && (observer < other.observer))); - } - - bool operator==(const IO& other) const - { - return illuminant == other.illuminant && observer == other.observer; - }; + IO(){}; + IO(std::string illuminant_, std::string observer_) ; + virtual ~IO(){}; + bool operator<(const IO& other) const; + bool operator==(const IO& other) const; }; const IO A_2("A", "2"), A_10("A", "10"), @@ -83,27 +69,9 @@ const static std::map> illuminants_xy = }; std::vector xyY2XYZ(const std::vector& xyY); -std::vector xyY2XYZ(const std::vector& xyY) -{ - double Y = xyY.size() >= 3 ? xyY[2] : 1; - return { Y * xyY[0] / xyY[1], Y, Y / xyY[1] * (1 - xyY[0] - xyY[1]) }; -} - -/* *\ brief function to get illuminants*/ -static std::map > getIlluminant(); -static std::map > getIlluminant() -{ - std::map > illuminants; - for (auto it = illuminants_xy.begin(); it != illuminants_xy.end(); ++it) - { - illuminants[it->first] = xyY2XYZ(it->second); - } - return illuminants; -} -const std::map > illuminants = getIlluminant(); } // namespace ccm } // namespace cv -#endif \ No newline at end of file +#endif diff --git a/modules/mcc/include/opencv2/mcc/utils.hpp b/modules/mcc/include/opencv2/mcc/utils.hpp index d1f56854c85..37cfb1febcb 100644 --- a/modules/mcc/include/opencv2/mcc/utils.hpp +++ b/modules/mcc/include/opencv2/mcc/utils.hpp @@ -28,38 +28,59 @@ #ifndef __OPENCV_MCC_UTILS_HPP__ #define __OPENCV_MCC_UTILS_HPP__ -#include -#include -#include -#include #include -namespace cv -{ -namespace ccm -{ +namespace cv { +namespace ccm { -double gammaCorrection_(const double& element, const double& gamma); -cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma); -cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask); -cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm); -cv::Mat saturate(cv::Mat& src, const double& low, const double& up); -cv::Mat rgb2gray(cv::Mat rgb); +/* *\ brief gamma correction ,see ColorSpace.pdf for details. + *\ param src the input array,type of Mat. + *\ param gamma a constant for gamma correction. + */ +CV_EXPORTS_W double gammaCorrection_(const double& element, const double& gamma); -/* *\ brief function for elementWise operation - *\ param src the input array, type of cv::Mat - *\ lambda a for operation +CV_EXPORTS_W Mat gammaCorrection(const Mat& src, const double& gamma); + +/* *\ brief maskCopyTo a function to delete unsatisfied elementwise. + *\ param src the input array, type of Mat. + *\ param mask operation mask that used to choose satisfided elementwise. + */ +CV_EXPORTS_W Mat maskCopyTo(const Mat& src, const Mat& mask); + +/* *\ brief multiple the function used to compute an array with n channels + *mulipied by ccm. \ param src the input array, type of Mat. \ param ccm the + *ccm matrix to make color correction. + */ +CV_EXPORTS_W Mat multiple(const Mat& xyz, const Mat& ccm); + +/* *\ brief multiple the function used to get the mask of saturated colors, + colors between low and up will be choosed. + *\ param src the input array, type of Mat. + *\ param low the threshold to choose saturated colors + *\ param up the threshold to choose saturated colors */ +CV_EXPORTS_W Mat saturate(Mat& src, const double& low, const double& up); + +/* *\ brief rgb2gray it is an approximation grayscale function for relative RGB + *color space, see Miscellaneous.pdf for details; \ param rgb the input array, + *type of Mat. + */ +CV_EXPORTS_W Mat rgb2gray(Mat rgb); + +/* *\ brief function for elementWise operation + *\ param src the input array, type of Mat + *\ lambda a for operation + */ template -cv::Mat elementWise(const cv::Mat& src, F&& lambda) +Mat elementWise(const Mat& src, F&& lambda) { - cv::Mat dst = src.clone(); + Mat dst = src.clone(); const int channel = src.channels(); switch (channel) { case 1: { - cv::MatIterator_ it, end; + MatIterator_ it, end; for (it = dst.begin(), end = dst.end(); it != end; ++it) { (*it) = lambda((*it)); @@ -68,7 +89,7 @@ cv::Mat elementWise(const cv::Mat& src, F&& lambda) } case 3: { - cv::MatIterator_ it, end; + MatIterator_ it, end; for (it = dst.begin(), end = dst.end(); it != end; ++it) { for (int j = 0; j < 3; j++) @@ -79,21 +100,21 @@ cv::Mat elementWise(const cv::Mat& src, F&& lambda) break; } default: - throw std::invalid_argument{ "Wrong channel!" }; + throw std::invalid_argument { "Wrong channel!" }; break; } return dst; } /* *\ brief function for channel operation - *\ param src the input array, type of cv::Mat + *\ param src the input array, type of Mat *\ lambda the function for operation */ template -cv::Mat channelWise(const cv::Mat& src, F&& lambda) +Mat channelWise(const Mat& src, F&& lambda) { - cv::Mat dst = src.clone(); - cv::MatIterator_ it, end; + Mat dst = src.clone(); + MatIterator_ it, end; for (it = dst.begin(), end = dst.end(); it != end; ++it) { *it = lambda(*it); @@ -102,17 +123,17 @@ cv::Mat channelWise(const cv::Mat& src, F&& lambda) } /* *\ brief function for distance operation. - *\ param src the input array, type of cv::Mat. - *\ param ref another input array, type of cv::Mat. - *\ param lambda the computing method for distance . -*/ + *\ param src the input array, type of Mat. + *\ param ref another input array, type of Mat. + *\ param lambda the computing method for distance . + */ template -cv::Mat distanceWise(cv::Mat& src, cv::Mat& ref, F&& lambda) +Mat distanceWise(Mat& src, Mat& ref, F&& lambda) { - cv::Mat dst = cv::Mat(src.size(), CV_64FC1); - cv::MatIterator_ it_src = src.begin(), end_src = src.end(), + Mat dst = Mat(src.size(), CV_64FC1); + MatIterator_ it_src = src.begin(), end_src = src.end(), it_ref = ref.begin(); - cv::MatIterator_ it_dst = dst.begin(); + MatIterator_ it_dst = dst.begin(); for (; it_src != end_src; ++it_src, ++it_ref, ++it_dst) { *it_dst = lambda(*it_src, *it_ref); @@ -120,116 +141,11 @@ cv::Mat distanceWise(cv::Mat& src, cv::Mat& ref, F&& lambda) return dst; } +CV_EXPORTS_W Mat multiple(const Mat& xyz, const Mat& ccm); -double gammaCorrection_(const double& element, const double& gamma) -{ - return (element >= 0 ? pow(element, gamma) : -pow((-element), gamma)); -} - -/* *\ brief gamma correction, see ColorSpace.pdf for details. - *\ param src the input array, type of cv::Mat. - *\ param gamma a constant for gamma correction. -*/ -cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma) -{ - return elementWise(src, [gamma](double element)->double {return gammaCorrection_(element, gamma); }); -} - -/* *\ brief maskCopyTo a function to delete unsatisfied elementwise. - *\ param src the input array, type of cv::Mat. - *\ param mask operation mask that used to choose satisfided elementwise. -*/ -cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) -{ - cv::Mat dst(countNonZero(mask), 1, src.type()); - const int channel = src.channels(); - auto it_mask = mask.begin(); - switch (channel) - { - case 1: - { - auto it_src = src.begin(), end_src = src.end(); - auto it_dst = dst.begin(); - for (; it_src != end_src; ++it_src, ++it_mask) - { - if (*it_mask) - { - (*it_dst) = (*it_src); - ++it_dst; - } - } - break; - } - case 3: - { - auto it_src = src.begin(), end_src = src.end(); - auto it_dst = dst.begin(); - for (; it_src != end_src; ++it_src, ++it_mask) - { - if (*it_mask) - { - (*it_dst) = (*it_src); - ++it_dst; - } - } - break; - } - default: - throw std::invalid_argument{ "Wrong channel!" }; - break; - } - return dst; -} - -/* *\ brief multiple the function used to compute an array with n channels mulipied by ccm. - *\ param src the input array, type of cv::Mat. - *\ param ccm the ccm matrix to make color correction. -*/ -cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm) -{ - cv::Mat tmp = xyz.reshape(1, xyz.rows * xyz.cols); - cv::Mat res = tmp * ccm; - res = res.reshape(res.cols, xyz.rows); - return res; -} - -/* *\ brief multiple the function used to get the mask of saturated colors, - colors between low and up will be choosed. - *\ param src the input array, type of cv::Mat. - *\ param low the threshold to choose saturated colors - *\ param up the threshold to choose saturated colors -*/ -cv::Mat saturate(cv::Mat& src, const double& low, const double& up) -{ - cv::Mat dst = cv::Mat::ones(src.size(), CV_8UC1); - cv::MatIterator_ it_src = src.begin(), end_src = src.end(); - cv::MatIterator_ it_dst = dst.begin(); - for (; it_src != end_src; ++it_src, ++it_dst) - { - for (int i = 0; i < 3; ++i) - { - if ((*it_src)[i] > up || (*it_src)[i] < low) - { - *it_dst = 0; - break; - } - } - } - return dst; -} - -const static cv::Mat m_gray = (cv::Mat_(3, 1) << 0.2126, 0.7152, 0.0722); - -/* *\ brief rgb2gray it is an approximation grayscale function for relative RGB color space, - * see Miscellaneous.pdf for details; - *\ param rgb the input array, type of cv::Mat. -*/ -cv::Mat rgb2gray(cv::Mat rgb) -{ - return multiple(rgb, m_gray); -} -} // namespace ccm -} // namespace cv +const static Mat m_gray = (Mat_(3, 1) << 0.2126, 0.7152, 0.0722); +} // namespace ccm +} // namespace cv -#endif \ No newline at end of file +#endif diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp index fd5ffef8f2b..9da005c4d48 100644 --- a/modules/mcc/samples/color_correction_model.cpp +++ b/modules/mcc/samples/color_correction_model.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include using namespace std; @@ -113,7 +112,7 @@ int main(int argc, char *argv[]) // Save the calibrated image to {FILE_NAME}.calibrated.{FILE_EXT} string filename = filepath.substr(filepath.find_last_of('/')+1); - int dotIndex = filename.find_last_of('.'); + size_t dotIndex = filename.find_last_of('.'); string baseName = filename.substr(0, dotIndex); string ext = filename.substr(dotIndex+1, filename.length()-dotIndex); string calibratedFilePath = baseName + ".calibrated." + ext; diff --git a/modules/mcc/src/distance.cpp b/modules/mcc/src/distance.cpp new file mode 100644 index 00000000000..dd39f0c614a --- /dev/null +++ b/modules/mcc/src/distance.cpp @@ -0,0 +1,233 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#include "precomp.hpp" + +namespace cv +{ +namespace ccm +{ + +double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2) { return norm(lab1 - lab2); }; + +double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH, + double kC, double kL, double k1, double k2) +{ + double dl = lab1[0] - lab2[0]; + double c1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); + double c2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); + double dc = c1 - c2; + double da = lab1[1] - lab2[1]; + double db = lab1[2] - lab2[2]; + double dh = pow(da, 2) + pow(db, 2) - pow(dc, 2); + double sc = 1.0 + k1 * c1; + double sh = 1.0 + k2 * c1; + double sl = 1.0; + double res = + pow(dl / (kL * sl), 2) + pow(dc / (kC * sc), 2) + dh / pow(kH * sh, 2); + + return res > 0 ? sqrt(res) : 0; +} + +double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2) +{ + return deltaCIE94(lab1, lab2); +} + +double toRad(double degree) { return degree / 180 * CV_PI; }; + +double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2) +{ + return deltaCIE94(lab1, lab2, 1.0, 1.0, 2.0, 0.048, 0.014); +} + +double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL, + double kC, double kH) +{ + double delta_L_apo = lab2[0] - lab1[0]; + double l_bar_apo = (lab1[0] + lab2[0]) / 2.0; + double C1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); + double C2 = sqrt(pow(lab2[1], 2) + pow(lab2[2], 2)); + double C_bar = (C1 + C2) / 2.0; + double G = sqrt(pow(C_bar, 7) / (pow(C_bar, 7) + pow(25, 7))); + double a1_apo = lab1[1] + lab1[1] / 2.0 * (1.0 - G); + double a2_apo = lab2[1] + lab2[1] / 2.0 * (1.0 - G); + double C1_apo = sqrt(pow(a1_apo, 2) + pow(lab1[2], 2)); + double C2_apo = sqrt(pow(a2_apo, 2) + pow(lab2[2], 2)); + double C_bar_apo = (C1_apo + C2_apo) / 2.0; + double delta_C_apo = C2_apo - C1_apo; + + double h1_apo; + if (C1_apo == 0) + { + h1_apo = 0.0; + } + else + { + h1_apo = atan2(lab1[2], a1_apo); + if (h1_apo < 0.0) h1_apo += 2. * CV_PI; + } + + double h2_apo; + if (C2_apo == 0) + { + h2_apo = 0.0; + } + else + { + h2_apo = atan2(lab2[2], a2_apo); + if (h2_apo < 0.0) h2_apo += 2. * CV_PI; + } + + double delta_h_apo; + if (abs(h2_apo - h1_apo) <= CV_PI) + { + delta_h_apo = h2_apo - h1_apo; + } + else if (h2_apo <= h1_apo) + { + delta_h_apo = h2_apo - h1_apo + 2. * CV_PI; + } + else + { + delta_h_apo = h2_apo - h1_apo - 2. * CV_PI; + } + + double H_bar_apo; + if (C1_apo == 0 || C2_apo == 0) + { + H_bar_apo = h1_apo + h2_apo; + } + else if (abs(h1_apo - h2_apo) <= CV_PI) + { + H_bar_apo = (h1_apo + h2_apo) / 2.0; + } + else if (h1_apo + h2_apo < 2. * CV_PI) + { + H_bar_apo = (h1_apo + h2_apo + 2. * CV_PI) / 2.0; + } + else + { + H_bar_apo = (h1_apo + h2_apo - 2. * CV_PI) / 2.0; + } + + double delta_H_apo = 2.0 * sqrt(C1_apo * C2_apo) * sin(delta_h_apo / 2.0); + double T = 1.0 - 0.17 * cos(H_bar_apo - toRad(30.)) + + 0.24 * cos(2.0 * H_bar_apo) + + 0.32 * cos(3.0 * H_bar_apo + toRad(6.0)) - + 0.2 * cos(4.0 * H_bar_apo - toRad(63.0)); + double sC = 1.0 + 0.045 * C_bar_apo; + double sH = 1.0 + 0.015 * C_bar_apo * T; + double sL = 1.0 + ((0.015 * pow(l_bar_apo - 50.0, 2.0)) / + sqrt(20.0 + pow(l_bar_apo - 50.0, 2.0))); + double RT = -2.0 * G * + sin(toRad(60.0) * + exp(-pow((H_bar_apo - toRad(275.0)) / toRad(25.0), 2.0))); + double res = + (pow(delta_L_apo / (kL * sL), 2.0) + pow(delta_C_apo / (kC * sC), 2.0) + + pow(delta_H_apo / (kH * sH), 2.0) + + RT * (delta_C_apo / (kC * sC)) * (delta_H_apo / (kH * sH))); + return res > 0 ? sqrt(res) : 0; +} + +double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2) +{ + return deltaCIEDE2000_(lab1, lab2); +} + +double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL, double kC) +{ + double dL = lab2[0] - lab1[0]; + double da = lab2[1] - lab1[1]; + double db = lab2[2] - lab1[2]; + double C1 = sqrt(pow(lab1[1], 2.0) + pow(lab1[2], 2.0)); + double C2 = sqrt(pow(lab2[1], 2.0) + pow(lab2[2], 2.0)); + double dC = C2 - C1; + double dH = sqrt(pow(da, 2) + pow(db, 2) - pow(dC, 2)); + + double H1; + if (C1 == 0.) + { + H1 = 0.0; + } + else + { + H1 = atan2(lab1[2], lab1[1]); + if (H1 < 0.0) H1 += 2. * CV_PI; + } + + double F = pow(C1, 2) / sqrt(pow(C1, 4) + 1900); + double T = (H1 > toRad(164) && H1 <= toRad(345)) + ? 0.56 + abs(0.2 * cos(H1 + toRad(168))) + : 0.36 + abs(0.4 * cos(H1 + toRad(35))); + double sL = + lab1[0] < 16. ? 0.511 : (0.040975 * lab1[0]) / (1.0 + 0.01765 * lab1[0]); + double sC = (0.0638 * C1) / (1.0 + 0.0131 * C1) + 0.638; + double sH = sC * (F * T + 1.0 - F); + + return sqrt(pow(dL / (kL * sL), 2.0) + pow(dC / (kC * sC), 2.0) + + pow(dH / sH, 2.0)); +} + +double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2) +{ + return deltaCMC(lab1, lab2); +} + +double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2) +{ + return deltaCMC(lab1, lab2, 2, 1); +} + +Mat distance(Mat src, Mat ref, DISTANCE_TYPE distance_type) +{ + switch (distance_type) + { + case cv::ccm::CIE76: + return distanceWise(src, ref, deltaCIE76); + case cv::ccm::CIE94_GRAPHIC_ARTS: + return distanceWise(src, ref, deltaCIE94GraphicArts); + case cv::ccm::CIE94_TEXTILES: + return distanceWise(src, ref, deltaCIE94Textiles); + case cv::ccm::CIE2000: + return distanceWise(src, ref, deltaCIEDE2000); + case cv::ccm::CMC_1TO1: + return distanceWise(src, ref, deltaCMC1To1); + case cv::ccm::CMC_2TO1: + return distanceWise(src, ref, deltaCMC2To1); + case cv::ccm::RGB: + return distanceWise(src, ref, deltaCIE76); + case cv::ccm::RGBL: + return distanceWise(src, ref, deltaCIE76); + default: + throw std::invalid_argument{ "Wrong distance_type!" }; + break; + } +}; + +} // namespace ccm +} // namespace cv \ No newline at end of file diff --git a/modules/mcc/src/io.cpp b/modules/mcc/src/io.cpp new file mode 100644 index 00000000000..6d061326b48 --- /dev/null +++ b/modules/mcc/src/io.cpp @@ -0,0 +1,53 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#include "opencv2/mcc/io.hpp" +namespace cv +{ +namespace ccm +{ +IO::IO(std::string illuminant_, std::string observer_) :illuminant(illuminant_), observer(observer_) {}; + +bool IO::operator<(const IO& other) const +{ + return (illuminant < other.illuminant || ((illuminant == other.illuminant) && (observer < other.observer))); +} + +bool IO::operator==(const IO& other) const +{ + return illuminant == other.illuminant && observer == other.observer; +}; + +// data from https://en.wikipedia.org/wiki/Standard_illuminant. +std::vector xyY2XYZ(const std::vector& xyY) +{ + double Y = xyY.size() >= 3 ? xyY[2] : 1; + return { Y * xyY[0] / xyY[1], Y, Y / xyY[1] * (1 - xyY[0] - xyY[1]) }; +} + +} // namespace ccm +} // namespace cv diff --git a/modules/mcc/src/utils.cpp b/modules/mcc/src/utils.cpp new file mode 100644 index 00000000000..56f3be7aaba --- /dev/null +++ b/modules/mcc/src/utils.cpp @@ -0,0 +1,120 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#include "precomp.hpp" + +namespace cv +{ +namespace ccm +{ + +double gammaCorrection_(const double& element, const double& gamma) +{ + return (element >= 0 ? pow(element, gamma) : -pow((-element), gamma)); +} + +cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma) +{ + return elementWise(src, [gamma](double element)->double {return gammaCorrection_(element, gamma); }); +} + +cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) +{ + cv::Mat dst(countNonZero(mask), 1, src.type()); + const int channel = src.channels(); + auto it_mask = mask.begin(); + switch (channel) + { + case 1: + { + auto it_src = src.begin(), end_src = src.end(); + auto it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_mask) + { + if (*it_mask) + { + (*it_dst) = (*it_src); + ++it_dst; + } + } + break; + } + case 3: + { + auto it_src = src.begin(), end_src = src.end(); + auto it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_mask) + { + if (*it_mask) + { + (*it_dst) = (*it_src); + ++it_dst; + } + } + break; + } + default: + throw std::invalid_argument { "Wrong channel!" }; + break; + } + return dst; +} + +cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm) +{ + cv::Mat tmp = xyz.reshape(1, xyz.rows * xyz.cols); + cv::Mat res = tmp * ccm; + res = res.reshape(res.cols, xyz.rows); + return res; +} + +cv::Mat saturate(cv::Mat& src, const double& low, const double& up) +{ + cv::Mat dst = cv::Mat::ones(src.size(), CV_8UC1); + cv::MatIterator_ it_src = src.begin(), end_src = src.end(); + cv::MatIterator_ it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_dst) + { + for (int i = 0; i < 3; ++i) + { + if ((*it_src)[i] > up || (*it_src)[i] < low) + { + *it_dst = 0; + break; + } + } + } + return dst; +} + +cv::Mat rgb2gray(cv::Mat rgb) +{ + return multiple(rgb, m_gray); +} + +} // namespace ccm +} // namespace cv diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index 0999c92cd72..6a761f66dbb 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -181,7 +181,7 @@ Supported Color Space: The first part is to detect the ColorChecker position. -@code{.cpp}#include #include #include #include #include #include using namespace std;using namespace cv;using namespace mcc;using namespace ccm;using namespace std;@endcode +@code{.cpp}#include #include #include #include #include using namespace std;using namespace cv;using namespace mcc;using namespace ccm;using namespace std;@endcode ``` Here is sets of header and namespaces. You can set other namespace like the code above. @@ -235,4 +235,4 @@ The member function infer_image is to make correction correction using ccm matri ``` Save the calibrated image. -``` \ No newline at end of file +``` From 0ee295e17dca08e67a58022653f6155afd99f219 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Tue, 22 Sep 2020 15:53:04 +0800 Subject: [PATCH 27/71] add static method --- modules/mcc/include/opencv2/mcc/ccm.hpp | 17 +- modules/mcc/include/opencv2/mcc/color.hpp | 29 +- .../mcc/include/opencv2/mcc/colorspace.hpp | 98 +++-- modules/mcc/src/ccm.cpp | 26 +- modules/mcc/src/color.cpp | 71 +++- modules/mcc/src/colorspace.cpp | 351 ++++++++++++++++-- modules/mcc/test/test_ccm.cpp | 8 +- modules/mcc/test/test_color.cpp | 2 +- modules/mcc/test/test_colorspace.cpp | 16 +- modules/mcc/test/test_linearize.cpp | 4 +- 10 files changed, 526 insertions(+), 96 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 379b55a6625..ded97f252ed 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -246,12 +246,23 @@ class CV_EXPORTS_W ColorCorrectionModel double loss; int max_count; double epsilon; + ColorCorrectionModel(cv::Mat src_, CONST_COLOR constcolor, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, cv::Mat weights_list = Mat(), double weights_coeff = 0, + INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); - ColorCorrectionModel(Mat src_, Mat colors_, const ColorSpace& ref_cs_, RGBBase_& cs_=sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, - double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, + ColorCorrectionModel(cv::Mat src_, Mat colors_, COLOR_SPACE ref_cs_, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, cv::Mat weights_list = Mat(), double weights_coeff = 0, + INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); + + ColorCorrectionModel(cv::Mat src_, Color dst_, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, cv::Mat weights_list = Mat(), double weights_coeff = 0, INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); - ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_= sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + /* ColorCorrectionModel(Mat src_, Mat colors_, const ColorSpace& ref_cs_, RGBBase_& cs_ , CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, + INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4);*/ + + ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_ , CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); diff --git a/modules/mcc/include/opencv2/mcc/color.hpp b/modules/mcc/include/opencv2/mcc/color.hpp index ac2c246d8dc..85f03a28db6 100644 --- a/modules/mcc/include/opencv2/mcc/color.hpp +++ b/modules/mcc/include/opencv2/mcc/color.hpp @@ -53,7 +53,8 @@ class CV_EXPORTS_W Color Mat grays; Mat colored; std::map> history; - + Color(Mat colors_, enum COLOR_SPACE cs_) ; + Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_) ; Color(Mat colors_, const ColorSpace& cs_, Mat colored_); Color(Mat colors_, const ColorSpace& cs_); @@ -66,6 +67,7 @@ class CV_EXPORTS_W Color *\ param other type of ColorSpace. *\ return Color. */ + Color to(COLOR_SPACE other, CAM method = BRADFORD, bool save = true); Color to(const ColorSpace& other, CAM method = BRADFORD, bool save = true); /* *\ brief Channels split. @@ -195,13 +197,24 @@ const Mat Vinyl_COLORED_MASK = (Mat_(18, 1) << /* *\ brief Macbeth ColorChecker with 2deg D50. */ -CV_EXPORTS_W extern Color Macbeth_D50_2; - -/* *\ brief Macbeth ColorChecker with 2deg D65. -*/ -CV_EXPORTS_W extern Color Macbeth_D65_2; - -CV_EXPORTS_W extern Color Vinyl_D50_2; +//const Color Macbeth_D50_2; +// +///* *\ brief Macbeth ColorChecker with 2deg D65. +//*/ +//const Color Macbeth_D65_2; +// +//const Color Vinyl_D50_2; +enum CONST_COLOR { + Macbeth, + Vinyl +}; +class CV_EXPORTS_W GetColor { +public: + static Color get_color(CONST_COLOR const_color); +}; +//const Color Macbeth_D50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2, ColorChecker2005_COLORED_MASK); +////const Color Macbeth_D65_2(ColorChecker2005_LAB_D65_2, Lab_D65_2, ColorChecker2005_COLORED_MASK); +//const Color Vinyl_D50_2(Vinyl_LAB_D50_2, Lab_D50_2, Vinyl_COLORED_MASK); } // namespace ccm } // namespace cv diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp index 2cb54d07f6d..2af907ceb2c 100644 --- a/modules/mcc/include/opencv2/mcc/colorspace.hpp +++ b/modules/mcc/include/opencv2/mcc/colorspace.hpp @@ -39,6 +39,49 @@ namespace cv { namespace ccm { +enum COLOR_SPACE { + sRGB, + sRGBL, + AdobeRGB, + AdobeRGBL, + WideGamutRGB, + WideGamutRGBL, + ProPhotoRGB, + ProPhotoRGBL, + DCI_P3_RGB, + DCI_P3_RGBL, + AppleRGB, + AppleRGBL, + REC_709_RGB, + REC_709_RGBL, + REC_2020_RGB, + REC_2020_RGBL, + XYZ_D65_2, + XYZ_D65_10, + XYZ_D50_2, + XYZ_D50_10, + XYZ_A_2, + XYZ_A_10, + XYZ_D55_2, + XYZ_D55_10, + XYZ_D75_2, + XYZ_D75_10, + XYZ_E_2, + XYZ_E_10, + Lab_D65_2, + Lab_D65_10, + Lab_D50_2, + Lab_D50_10, + Lab_A_2, + Lab_A_10, + Lab_D55_2, + Lab_D55_10, + Lab_D75_2, + Lab_D75_10, + Lab_E_2, + Lab_E_10 +}; + /* *\ brief Basic class for ColorSpace. */ class CV_EXPORTS_W ColorSpace @@ -277,25 +320,6 @@ class CV_EXPORTS_W REC_2020_RGB_ : public sRGBBase_ }; -CV_EXPORTS_W extern sRGB_ sRGB, sRGBL; -CV_EXPORTS_W extern AdobeRGB_ AdobeRGB, AdobeRGBL; -CV_EXPORTS_W extern WideGamutRGB_ WideGamutRGB, WideGamutRGBL; -CV_EXPORTS_W extern ProPhotoRGB_ ProPhotoRGB, ProPhotoRGBL; -CV_EXPORTS_W extern DCI_P3_RGB_ DCI_P3_RGB, DCI_P3_RGBL; -CV_EXPORTS_W extern AppleRGB_ AppleRGB, AppleRGBL; -CV_EXPORTS_W extern REC_709_RGB_ REC_709_RGB, REC_709_RGBL; -CV_EXPORTS_W extern REC_2020_RGB_ REC_2020_RGB, REC_2020_RGBL; - -/* *\ brief Bind RGB with RGBL. -*/ -class CV_EXPORTS_W ColorSpaceInitial -{ -public: - ColorSpaceInitial(); -}; - -extern ColorSpaceInitial color_space_initial; - /* *\ brief Enum of the possible types of CAMs. */ enum CAM @@ -322,6 +346,15 @@ class CV_EXPORTS_W XYZ :public ColorSpace public: XYZ(IO io_) : ColorSpace(io_, "XYZ", true) {}; Operations cam(IO dio, CAM method = BRADFORD); + static std::map xyz_cs; + + static XYZ* get(IO io);/* { + if (xyz_cs.count(io) == 1) { + return xyz_cs[io]; + } + xyz_cs[io] = new XYZ(io); + return xyz_cs[io]; + }*/ private: /* *\ brief Get cam. *\ param sio the input IO of src. @@ -334,15 +367,23 @@ class CV_EXPORTS_W XYZ :public ColorSpace /* *\ brief Define XYZ_D65_2 and XYZ_D50_2. */ -const XYZ XYZ_D65_2(D65_2); -const XYZ XYZ_D50_2(D50_2); +const XYZ XYZ_D65_2_CS(D65_2); +const XYZ XYZ_D50_2_CS(D50_2); /* *\ brief Lab color space. */ class CV_EXPORTS_W Lab :public ColorSpace { public: + static std::map lab_cs; Lab(IO io_); + static Lab* get(IO io);/*{ + if (lab_cs.count(io) == 1) { + return lab_cs[io]; + } + lab_cs[io] = new Lab(io); + return lab_cs[io]; + }*/ private: static constexpr double delta = (6. / 29.); static constexpr double m = 1. / (3. * delta * delta); @@ -368,8 +409,19 @@ class CV_EXPORTS_W Lab :public ColorSpace /* *\ brief Define Lab_D65_2 and Lab_D50_2. */ -const Lab Lab_D65_2(D65_2); -const Lab Lab_D50_2(D50_2); +const Lab Lab_D65_2_CS(D65_2); +const Lab Lab_D50_2_CS(D50_2); + +//static std::map map_cs ; + +class CV_EXPORTS_W GetCS { +public: + static std::map map_cs; + static RGBBase_* get_rgb(enum COLOR_SPACE cs_name); + static ColorSpace* get_cs(enum COLOR_SPACE cs_name); +}; + + } // namespace ccm } // namespace cv diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 163a79609b9..6075b66000f 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -31,12 +31,28 @@ namespace cv { namespace ccm { + ColorCorrectionModel::ColorCorrectionModel(Mat src_, CONST_COLOR constcolor, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, + double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, + INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : + ColorCorrectionModel(src_, GetColor::get_color(constcolor), *GetCS::get_rgb(cs_), ccm_type_, distance_, linear_type, + gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} + ColorCorrectionModel::ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE ref_cs_, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, + double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, + INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : + ColorCorrectionModel(src_, Color(colors_, *GetCS::get_cs(ref_cs_)), *GetCS::get_rgb(cs_), ccm_type_, distance_, linear_type, + gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} -ColorCorrectionModel::ColorCorrectionModel(Mat src_, Mat colors_, const ColorSpace& ref_cs_, RGBBase_& cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, - double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, - INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : - ColorCorrectionModel(src_, Color(colors_, ref_cs_), cs_, ccm_type_, distance_, linear_type, - gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} + ColorCorrectionModel::ColorCorrectionModel(Mat src_, Color dst_, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, + double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, + INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : + ColorCorrectionModel(src_, dst_, *GetCS::get_rgb(cs_), ccm_type_, distance_, linear_type, + gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} + +//ColorCorrectionModel::ColorCorrectionModel(Mat src_, Mat colors_, const ColorSpace& ref_cs_, RGBBase_& cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, +// double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, +// INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : +// ColorCorrectionModel(src_, Color(colors_, ref_cs_), cs_, ccm_type_, distance_, linear_type, +// gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} ColorCorrectionModel::ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index a94b0f1d600..72a05b4a323 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -31,18 +31,24 @@ namespace cv { namespace ccm { + //Color(Mat colors_, enum COLOR_SPACE cs_); + //Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_); +Color::Color(Mat colors_, enum COLOR_SPACE cs_) :colors(colors_), cs(*GetCS::get_cs(cs_)) {}; Color::Color(Mat colors_, const ColorSpace& cs_, Mat colored_) : colors(colors_), cs(cs_), colored(colored_) { - grays= ~colored; + grays = ~colored; +} +Color::Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_) : colors(colors_), cs(*GetCS::get_cs(cs_)), colored(colored_) { + grays = ~colored; } - Color::Color(Mat colors_, const ColorSpace& cs_) : colors(colors_), cs(cs_) {}; - -Color Color::to(const ColorSpace& other, CAM method, bool save) +//Color Color::to(const ColorSpace& other, CAM method, bool save) +Color Color::to(const ColorSpace& other, CAM method , bool save) { if (history.count(other) == 1) { + return *history[other]; } if (cs.relate(other)) @@ -58,6 +64,27 @@ Color Color::to(const ColorSpace& other, CAM method, bool save) } return *color; } +Color Color::to( COLOR_SPACE other, CAM method, bool save) +{ + return to(*GetCS::get_cs(other), method, save); + // if (history.count(other) == 1) + //if (history.count(*get_cs(other)) == 1) + //{ + // return *history[*get_cs(other)]; + //} + //if (cs.relate(*get_cs(other))) + //{ + // return Color(cs.relation(*get_cs(other)).run(colors), other); + //} + //Operations ops; + //ops.add(cs.to).add(XYZ(cs.io).cam((*get_cs(other)).io, method).add((*get_cs(other)).from)); + //std::shared_ptr color(new Color(ops.run(colors), other)); + //if (save) + //{ + // history[*get_cs(other)] = color; + //} + //return *color; +} Mat Color::channel(Mat m, int i) { @@ -68,13 +95,15 @@ Mat Color::channel(Mat m, int i) Mat Color::toGray(IO io, CAM method, bool save) { - XYZ xyz(io); + //XYZ xyz(io); + XYZ xyz = *XYZ::get(io); return channel(this->to(xyz, method, save).colors, 1); } Mat Color::toLuminant(IO io, CAM method, bool save) { - Lab lab(io); + // Lab lab(io); + Lab lab= *Lab::get(io); return channel(this->to(lab, method, save).colors, 0); } @@ -85,7 +114,8 @@ Mat Color::diff(Color& other, DISTANCE_TYPE method) Mat Color::diff(Color& other, IO io, DISTANCE_TYPE method) { - Lab lab(io); + // Lab lab(io); + Lab lab = *Lab::get(io); switch (method) { case cv::ccm::CIE76: @@ -125,9 +155,30 @@ Color Color::operator[](Mat mask) return Color(maskCopyTo(colors, mask), cs); } -Color Macbeth_D50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2, ColorChecker2005_COLORED_MASK); -Color Macbeth_D65_2(ColorChecker2005_LAB_D65_2, Lab_D65_2, ColorChecker2005_COLORED_MASK); -Color Vinyl_D50_2(Vinyl_LAB_D50_2, Lab_D50_2, Vinyl_COLORED_MASK); +Color GetColor::get_color(CONST_COLOR const_color) { + switch (const_color) + { + case cv::ccm::Macbeth: + { + Color Macbeth_D50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2, ColorChecker2005_COLORED_MASK); + return Macbeth_D50_2; + break; + } + + case cv::ccm::Vinyl: { + Color Vinyl_D50_2(Vinyl_LAB_D50_2, Lab_D50_2, Vinyl_COLORED_MASK); + return Vinyl_D50_2; + break; + } + + default: + throw; + break; + } +} +//Color Macbeth_D50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2, ColorChecker2005_COLORED_MASK); +//Color Macbeth_D65_2(ColorChecker2005_LAB_D65_2, Lab_D65_2, ColorChecker2005_COLORED_MASK); +//Color Vinyl_D50_2(Vinyl_LAB_D50_2, Lab_D50_2, Vinyl_COLORED_MASK); } // namespace ccm } // namespace cv \ No newline at end of file diff --git a/modules/mcc/src/colorspace.cpp b/modules/mcc/src/colorspace.cpp index 55b2bd62416..48897a4100c 100644 --- a/modules/mcc/src/colorspace.cpp +++ b/modules/mcc/src/colorspace.cpp @@ -315,38 +315,6 @@ void REC_2020_RGB_::setParameter() { gamma = 1 / 0.45; } -sRGB_ sRGB = sRGB_(false); -sRGB_ sRGBL = sRGB_(true); -AdobeRGB_ AdobeRGB = AdobeRGB_(false); -AdobeRGB_ AdobeRGBL = AdobeRGB_(true); -WideGamutRGB_ WideGamutRGB = WideGamutRGB_(false); -WideGamutRGB_ WideGamutRGBL = WideGamutRGB_(true); -ProPhotoRGB_ ProPhotoRGB = ProPhotoRGB_(false); -ProPhotoRGB_ ProPhotoRGBL = ProPhotoRGB_(true); -DCI_P3_RGB_ DCI_P3_RGB = DCI_P3_RGB_(false); -DCI_P3_RGB_ DCI_P3_RGBL = DCI_P3_RGB_(true); -AppleRGB_ AppleRGB = AppleRGB_(false); -AppleRGB_ AppleRGBL = AppleRGB_(true); -REC_709_RGB_ REC_709_RGB = REC_709_RGB_(false); -REC_709_RGB_ REC_709_RGBL = REC_709_RGB_(true); -REC_2020_RGB_ REC_2020_RGB = REC_2020_RGB_(false); -REC_2020_RGB_ REC_2020_RGBL = REC_2020_RGB_(true); - -/* *\ brief Bind RGB with RGBL. - */ - -ColorSpaceInitial::ColorSpaceInitial() { - sRGB.bind(sRGBL); - AdobeRGB.bind(AdobeRGBL); - WideGamutRGB.bind(WideGamutRGBL); - ProPhotoRGB.bind(ProPhotoRGBL); - DCI_P3_RGB.bind(DCI_P3_RGBL); - AppleRGB.bind(AppleRGBL); - REC_709_RGB.bind(REC_709_RGBL); - REC_2020_RGB.bind(REC_2020_RGBL); -} - -ColorSpaceInitial color_space_initial; /* *\ brief Enum of the possible types of CAMs. */ @@ -378,6 +346,16 @@ Mat XYZ::cam_(IO sio, IO dio, CAM method) const { return M; } +std::map XYZ::xyz_cs = {}; + +XYZ* XYZ::get(IO io) { + if (xyz_cs.count(io) == 1) { + return xyz_cs[io]; + } + xyz_cs[io] = new XYZ(io); + return xyz_cs[io]; +} + /* *\ brief Lab color space. */ Lab::Lab(IO io_) : ColorSpace(io_, "Lab", true) { @@ -423,6 +401,315 @@ Mat Lab::tosrc(Mat& src) { return channelWise(src, [this](cv::Vec3d a) -> cv::Vec3d { return tolab(a); }); } +std::map Lab::lab_cs = {}; + +Lab* Lab::get(IO io) { + if (lab_cs.count(io) == 1) { + return lab_cs[io]; + } + lab_cs[io] = new Lab(io); + return lab_cs[io]; +} + +//static std::map map_cs = {}; +std::map GetCS::map_cs = {}; + +RGBBase_* GetCS::get_rgb(enum COLOR_SPACE cs_name) { + switch (cs_name) + { + case cv::ccm::sRGB: + { + if (map_cs.count(cs_name) < 1) { + sRGB_* sRGB_CS = new sRGB_(false); + sRGB_* sRGBL_CS =new sRGB_(true); + (*sRGB_CS).bind(*sRGBL_CS); + map_cs[sRGB] = sRGB_CS; + map_cs[sRGBL] = sRGBL_CS; + } + break; + } + case cv::ccm::AdobeRGB: + { + if (map_cs.count(cs_name) < 1) { + // AdobeRGB_ AdobeRGB_CS(false), AdobeRGBL_CS(true); + // AdobeRGB_CS.bind(AdobeRGBL_CS); + AdobeRGB_* AdobeRGB_CS = new AdobeRGB_(false); + AdobeRGB_* AdobeRGBL_CS = new AdobeRGB_(true); + (*AdobeRGB_CS).bind(*AdobeRGBL_CS); + map_cs[AdobeRGB] = AdobeRGB_CS; + map_cs[AdobeRGBL] = AdobeRGBL_CS; + } + break; + } + case cv::ccm::WideGamutRGB: + { + if (map_cs.count(cs_name) < 1) { + /*WideGamutRGB_ WideGamutRGB_CS(false), WideGamutRGBL_CS(true); + WideGamutRGB_CS.bind(WideGamutRGBL_CS); + map_cs[WideGamutRGB] = &WideGamutRGB_CS; + map_cs[WideGamutRGBL] = &WideGamutRGBL_CS;*/ + WideGamutRGB_* WideGamutRGB_CS = new WideGamutRGB_(false); + WideGamutRGB_* WideGamutRGBL_CS = new WideGamutRGB_(false); + (*WideGamutRGB_CS).bind(*WideGamutRGBL_CS); + map_cs[WideGamutRGB] = WideGamutRGB_CS; + map_cs[WideGamutRGBL] = WideGamutRGBL_CS; + } + break; + } + case cv::ccm::ProPhotoRGB: + { + if (map_cs.count(cs_name) < 1) { + ProPhotoRGB_* ProPhotoRGB_CS = new ProPhotoRGB_(false); + ProPhotoRGB_* ProPhotoRGBL_CS= new ProPhotoRGB_(true); + (*ProPhotoRGB_CS).bind(*ProPhotoRGBL_CS); + map_cs[ProPhotoRGB] = ProPhotoRGB_CS; + map_cs[ProPhotoRGBL] = ProPhotoRGBL_CS; + } + break; + } + case cv::ccm::DCI_P3_RGB: + { + if (map_cs.count(cs_name) < 1) { + DCI_P3_RGB_* DCI_P3_RGB_CS = new DCI_P3_RGB_(false); + DCI_P3_RGB_* DCI_P3_RGBL_CS =new DCI_P3_RGB_(true); + (*DCI_P3_RGB_CS).bind(*DCI_P3_RGBL_CS); + map_cs[DCI_P3_RGB] = DCI_P3_RGB_CS; + map_cs[DCI_P3_RGBL] = DCI_P3_RGBL_CS; + } + break; + } + case cv::ccm::AppleRGB: + { + if (map_cs.count(cs_name) < 1) { + AppleRGB_* AppleRGB_CS = new AppleRGB_(false); + AppleRGB_* AppleRGBL_CS = new AppleRGB_(true); + (*AppleRGB_CS).bind(*AppleRGBL_CS); + map_cs[AppleRGB] = AppleRGB_CS; + map_cs[AppleRGBL] = AppleRGBL_CS; + } + break; + } + case cv::ccm::REC_709_RGB: + { + if (map_cs.count(cs_name) < 1) { + REC_709_RGB_* REC_709_RGB_CS = new REC_709_RGB_(false); + REC_709_RGB_* REC_709_RGBL_CS= new REC_709_RGB_(true); + (*REC_709_RGB_CS).bind(*REC_709_RGBL_CS); + map_cs[REC_709_RGB] = REC_709_RGB_CS; + map_cs[REC_709_RGBL] = REC_709_RGBL_CS; + } + break; + } + case cv::ccm::REC_2020_RGB: + { + if (map_cs.count(cs_name) < 1) { + REC_2020_RGB_* REC_2020_RGB_CS = new REC_2020_RGB_(false); + REC_2020_RGB_* REC_2020_RGBL_CS = new REC_2020_RGB_(true); + (*REC_2020_RGB_CS).bind(*REC_2020_RGBL_CS); + map_cs[REC_2020_RGB] = REC_2020_RGB_CS; + map_cs[REC_2020_RGBL] = REC_2020_RGBL_CS; + } + break; + } + case cv::ccm::sRGBL: + case cv::ccm::AdobeRGBL: + case cv::ccm::WideGamutRGBL: + case cv::ccm::ProPhotoRGBL: + case cv::ccm::DCI_P3_RGBL: + case cv::ccm::AppleRGBL: + case cv::ccm::REC_709_RGBL: + case cv::ccm::REC_2020_RGBL: + throw "linear RGB colorspaces are not supported, you should assigned as normal rgb color space"; + break; + + default: + throw "Only RGB color spaces are supported"; + } + return (RGBBase_*)(map_cs[cs_name]); +} + +ColorSpace* GetCS::get_cs(enum COLOR_SPACE cs_name) { + switch (cs_name) + { + case cv::ccm::sRGB: + case cv::ccm::sRGBL: + { + if (map_cs.count(cs_name) < 1) { + sRGB_* sRGB_CS = new sRGB_(false); + sRGB_* sRGBL_CS = new sRGB_(true); + (*sRGB_CS).bind(*sRGBL_CS); + map_cs[sRGB] = sRGB_CS; + map_cs[sRGBL] = sRGBL_CS; + } + break; + } + case cv::ccm::AdobeRGB: + case cv::ccm::AdobeRGBL: + { + if (map_cs.count(cs_name) < 1) { + AdobeRGB_* AdobeRGB_CS = new AdobeRGB_(false); + AdobeRGB_* AdobeRGBL_CS = new AdobeRGB_(true); + (*AdobeRGB_CS).bind(*AdobeRGBL_CS); + map_cs[AdobeRGB] = AdobeRGB_CS; + map_cs[AdobeRGBL] = AdobeRGBL_CS; + } + break; + } + case cv::ccm::WideGamutRGB: + case cv::ccm::WideGamutRGBL: + { + if (map_cs.count(cs_name) < 1) { + /* WideGamutRGB_ WideGamutRGB_CS(false), WideGamutRGBL_CS(true); + WideGamutRGB_CS.bind(WideGamutRGBL_CS); + map_cs[WideGamutRGB] = &WideGamutRGB_CS; + map_cs[WideGamutRGBL] = &WideGamutRGBL_CS;*/ + WideGamutRGB_* WideGamutRGB_CS = new WideGamutRGB_(false); + WideGamutRGB_* WideGamutRGBL_CS = new WideGamutRGB_(false); + (*WideGamutRGB_CS).bind(*WideGamutRGBL_CS); + map_cs[WideGamutRGB] = WideGamutRGB_CS; + map_cs[WideGamutRGBL] = WideGamutRGBL_CS; + + } + break; + } + case cv::ccm::ProPhotoRGB: + case cv::ccm::ProPhotoRGBL: + { + if (map_cs.count(cs_name) < 1) { + ProPhotoRGB_* ProPhotoRGB_CS = new ProPhotoRGB_(false); + ProPhotoRGB_* ProPhotoRGBL_CS = new ProPhotoRGB_(true); + (*ProPhotoRGB_CS).bind(*ProPhotoRGBL_CS); + map_cs[ProPhotoRGB] = ProPhotoRGB_CS; + map_cs[ProPhotoRGBL] = ProPhotoRGBL_CS; + } + break; + } + case cv::ccm::DCI_P3_RGB: + case cv::ccm::DCI_P3_RGBL: + { + if (map_cs.count(cs_name) < 1) { + DCI_P3_RGB_* DCI_P3_RGB_CS = new DCI_P3_RGB_(false); + DCI_P3_RGB_* DCI_P3_RGBL_CS = new DCI_P3_RGB_(true); + (*DCI_P3_RGB_CS).bind(*DCI_P3_RGBL_CS); + map_cs[DCI_P3_RGB] = DCI_P3_RGB_CS; + map_cs[DCI_P3_RGBL] = DCI_P3_RGBL_CS; + } + break; + } + case cv::ccm::AppleRGB: + case cv::ccm::AppleRGBL: + { + if (map_cs.count(cs_name) < 1) { + AppleRGB_* AppleRGB_CS = new AppleRGB_(false); + AppleRGB_* AppleRGBL_CS = new AppleRGB_(true); + (*AppleRGB_CS).bind(*AppleRGBL_CS); + map_cs[AppleRGB] = AppleRGB_CS; + map_cs[AppleRGBL] = AppleRGBL_CS; + } + break; + } + case cv::ccm::REC_709_RGB: + case cv::ccm::REC_709_RGBL: + { + if (map_cs.count(cs_name) < 1) { + REC_709_RGB_* REC_709_RGB_CS = new REC_709_RGB_(false); + REC_709_RGB_* REC_709_RGBL_CS = new REC_709_RGB_(true); + (*REC_709_RGB_CS).bind(*REC_709_RGBL_CS); + map_cs[REC_709_RGB] = REC_709_RGB_CS; + map_cs[REC_709_RGBL] = REC_709_RGBL_CS; + } + break; + } + case cv::ccm::REC_2020_RGB: + case cv::ccm::REC_2020_RGBL: + { + if (map_cs.count(cs_name) < 1) { + REC_2020_RGB_* REC_2020_RGB_CS = new REC_2020_RGB_(false); + REC_2020_RGB_* REC_2020_RGBL_CS = new REC_2020_RGB_(true); + (*REC_2020_RGB_CS).bind(*REC_2020_RGBL_CS); + map_cs[REC_2020_RGB] = REC_2020_RGB_CS; + map_cs[REC_2020_RGBL] = REC_2020_RGBL_CS; + } + break; + } + case cv::ccm::XYZ_D65_2: + return XYZ::get(D65_2); + break; + case cv::ccm::XYZ_D50_2: + return XYZ::get(D50_2); + break; + case cv::ccm::XYZ_D65_10: + return XYZ::get(D65_10); + break; + case cv::ccm::XYZ_D50_10: + return XYZ::get(D50_10); + break; + case cv::ccm::XYZ_A_2: + return XYZ::get(A_2); + break; + case cv::ccm::XYZ_A_10: + return XYZ::get(A_10); + break; + case cv::ccm::XYZ_D55_2: + return XYZ::get(D55_2); + break; + case cv::ccm::XYZ_D55_10: + return XYZ::get(D55_10); + break; + case cv::ccm::XYZ_D75_2: + return XYZ::get(D75_2); + break; + case cv::ccm::XYZ_D75_10: + return XYZ::get(D75_10); + break; + case cv::ccm::XYZ_E_2: + return XYZ::get(E_2); + break; + case cv::ccm::XYZ_E_10: + return XYZ::get(E_10); + break; + case cv::ccm::Lab_D65_2: + return Lab::get(D65_2); + break; + case cv::ccm::Lab_D50_2: + return Lab::get(D50_2); + break; + case cv::ccm::Lab_D65_10: + return Lab::get(D65_10); + break; + case cv::ccm::Lab_D50_10: + return Lab::get(D50_10); + break; + case cv::ccm::Lab_A_2: + return Lab::get(A_2); + break; + case cv::ccm::Lab_A_10: + return Lab::get(A_10); + break; + case cv::ccm::Lab_D55_2: + return Lab::get(D55_2); + break; + case cv::ccm::Lab_D55_10: + return Lab::get(D55_10); + break; + case cv::ccm::Lab_D75_2: + return Lab::get(D75_2); + break; + case cv::ccm::Lab_D75_10: + return Lab::get(D75_10); + break; + case cv::ccm::Lab_E_2: + return Lab::get(E_2); + break; + case cv::ccm::Lab_E_10: + return Lab::get(E_10); + break; + default: + break; + } + + return map_cs.find(cs_name)->second; +} } // namespace ccm } // namespace cv diff --git a/modules/mcc/test/test_ccm.cpp b/modules/mcc/test/test_ccm.cpp index 08763ebc4ad..d10afa65780 100644 --- a/modules/mcc/test/test_ccm.cpp +++ b/modules/mcc/test/test_ccm.cpp @@ -111,14 +111,14 @@ TEST(CV_ccmRunColorCorrection, test_masks_weights_1) 1.3, 0, 0, 1.4, 0, 0, 0.5, 0, 0, 0.6, 0, 0, 0.7, 0, 0, 0.8, 0, 0); - ColorCorrectionModel model1(s / 255, Macbeth_D50_2, sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, { 0, 0.98 }, weights_list_, 1.5); + ColorCorrectionModel model1(s / 255, GetColor::get_color(Macbeth), sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, { 0, 0.98 }, weights_list_, 1.5); Mat weights = (Mat_(8, 1) << 1.15789474, 1.26315789, 1.36842105, 1.47368421, 0.52631579, 0.63157895, 0.73684211, 0.84210526); ASSERT_MAT_NEAR(model1.weights, weights, 1e-4); - Mat mask = (Mat_(24, 1) << + Mat mask = (Mat_(24, 1) << true, false, false, true, false, false, true, false, false, true, false, false, true, false, false, true, false, false, @@ -128,7 +128,7 @@ TEST(CV_ccmRunColorCorrection, test_masks_weights_1) TEST(CV_ccmRunColorCorrection, test_masks_weights_2) { - ColorCorrectionModel model2(s / 255, Macbeth_D50_2, sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, {0.05, 0.93}, Mat(), 1.5); + ColorCorrectionModel model2(s / 255, GetColor::get_color(Macbeth), sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, {0.05, 0.93}, Mat(), 1.5); Mat weights = (Mat_(20, 1) << 0.65554256, 1.49454705, 1.00499244, 0.79735434, 1.16327759, @@ -137,7 +137,7 @@ TEST(CV_ccmRunColorCorrection, test_masks_weights_2) 1.04551645, 1.54082353, 1.02453421, 0.6015915, 0.26154558); ASSERT_MAT_NEAR(model2.weights, weights, 1e-4); - Mat mask = (Mat_(24, 1) << + Mat mask = (Mat_(24, 1) << true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, false, true, true, diff --git a/modules/mcc/test/test_color.cpp b/modules/mcc/test/test_color.cpp index 2b285579de4..2d0f027c077 100644 --- a/modules/mcc/test/test_color.cpp +++ b/modules/mcc/test/test_color.cpp @@ -114,7 +114,7 @@ TEST(CV_ccmColor, test_grays) Color color_d50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2); Color color_d65_2(ColorChecker2005_LAB_D65_2, Lab_D65_2); - Mat grays = (Mat_(24, 1) << + Mat grays = (Mat_(24, 1) << false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, diff --git a/modules/mcc/test/test_colorspace.cpp b/modules/mcc/test/test_colorspace.cpp index fc6fbea7543..716df9c3495 100644 --- a/modules/mcc/test/test_colorspace.cpp +++ b/modules/mcc/test/test_colorspace.cpp @@ -19,8 +19,8 @@ TEST(CV_ccmColorspace, test_sRGB_M) 3.2404542, -1.5371385, -0.4985314, -0.9692660, 1.8760108, 0.0415560, 0.0556434, -0.2040259, 1.0572252); - ASSERT_MAT_NEAR(sRGB.M_to, to, 1e-4); - ASSERT_MAT_NEAR(sRGB.M_from, from, 1e-4); + ASSERT_MAT_NEAR((*GetCS::get_rgb(sRGB)).M_to, to, 1e-4); + ASSERT_MAT_NEAR((*GetCS::get_rgb(sRGB)).M_from, from, 1e-4); } TEST(CV_ccmColorspace, test_AdobeRGB_M) @@ -33,8 +33,8 @@ TEST(CV_ccmColorspace, test_AdobeRGB_M) 2.0413690, -0.5649464, -0.3446944, -0.9692660, 1.8760108, 0.0415560, 0.0134474, -0.1183897, 1.0154096); - ASSERT_MAT_NEAR(AdobeRGB.M_to, to, 1e-4); - ASSERT_MAT_NEAR(AdobeRGB.M_from, from, 1e-4); + ASSERT_MAT_NEAR((*GetCS::get_rgb(AdobeRGB)).M_to, to, 1e-4); + ASSERT_MAT_NEAR((*GetCS::get_rgb(AdobeRGB)).M_from, from, 1e-4); } TEST(CV_ccmColorspace, test_WideGamutRGB_M) @@ -47,8 +47,8 @@ TEST(CV_ccmColorspace, test_WideGamutRGB_M) 1.4628067, -0.1840623, -0.2743606, -0.5217933, 1.4472381, 0.0677227, 0.0349342, -0.0968930, 1.2884099); - ASSERT_MAT_NEAR(WideGamutRGB.M_to, to, 1e-2); - ASSERT_MAT_NEAR(WideGamutRGB.M_from, from, 1e-2); + ASSERT_MAT_NEAR((*GetCS::get_rgb(WideGamutRGB)).M_to, to, 1e-2); + ASSERT_MAT_NEAR((*GetCS::get_rgb(WideGamutRGB)).M_from, from, 1e-2); } // wont' work @@ -76,8 +76,8 @@ TEST(CV_ccmColorspace, test_ProPhotoRGB_M) 1.3459433, -0.2556075, -0.0511118, -0.5445989, 1.5081673, 0.0205351, 0.0000000, 0.0000000, 1.2118128); - ASSERT_MAT_NEAR(ProPhotoRGB.M_to, to, 1e-2); - ASSERT_MAT_NEAR(ProPhotoRGB.M_from, from, 1e-2); + ASSERT_MAT_NEAR((*GetCS::get_rgb(ProPhotoRGB)).M_to, to, 1e-2); + ASSERT_MAT_NEAR((*GetCS::get_rgb(ProPhotoRGB)).M_from, from, 1e-2); } } // namespace diff --git a/modules/mcc/test/test_linearize.cpp b/modules/mcc/test/test_linearize.cpp index ca62b44d790..d90399fe475 100644 --- a/modules/mcc/test/test_linearize.cpp +++ b/modules/mcc/test/test_linearize.cpp @@ -38,8 +38,8 @@ Mat s = s_origin / 255; double gamma = 2.2; int deg = 3; -Color color = Macbeth_D50_2; -RGBBase_ cs = sRGB; +Color color = GetColor::get_color(Macbeth); +RGBBase_ cs = *GetCS::get_rgb(sRGB); Mat mask = saturate(s, 0.05, 0.93); TEST(CV_ccmLinearize, test_identity) From cb8a7b4ad10a4bb70aafe74778b7731e08ff5a07 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Wed, 23 Sep 2020 10:01:31 +0800 Subject: [PATCH 28/71] fix shared_ptr --- .../mcc/include/opencv2/mcc/colorspace.hpp | 17 +-- modules/mcc/src/color.cpp | 8 +- modules/mcc/src/colorspace.cpp | 100 ++++++++---------- modules/mcc/test/test_ccm.cpp | 10 +- 4 files changed, 65 insertions(+), 70 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp index 963932c4259..f81454e7b12 100644 --- a/modules/mcc/include/opencv2/mcc/colorspace.hpp +++ b/modules/mcc/include/opencv2/mcc/colorspace.hpp @@ -357,9 +357,9 @@ class CV_EXPORTS_W XYZ :public ColorSpace public: XYZ(IO io_) : ColorSpace(io_, "XYZ", true) {}; Operations cam(IO dio, CAM method = BRADFORD); - static std::map xyz_cs; - - static XYZ* get(IO io);/* { + // static std::map xyz_cs; + static std::map > xyz_cs; + static std::shared_ptr get(IO io);/* { if (xyz_cs.count(io) == 1) { return xyz_cs[io]; } @@ -387,9 +387,9 @@ const XYZ XYZ_D50_2_CS(D50_2); class CV_EXPORTS_W Lab :public ColorSpace { public: - static std::map lab_cs; + static std::map > lab_cs; Lab(IO io_); - static Lab* get(IO io);/*{ + static std::shared_ptr get(IO io);/*{ if (lab_cs.count(io) == 1) { return lab_cs[io]; } @@ -430,9 +430,10 @@ const Lab Lab_D50_2_CS(D50_2); class CV_EXPORTS_W GetCS { public: - static std::map map_cs; - static RGBBase_* get_rgb(enum COLOR_SPACE cs_name); - static ColorSpace* get_cs(enum COLOR_SPACE cs_name); + static std::map > map_cs; + //static RGBBase_* get_rgb(enum COLOR_SPACE cs_name); + static std::shared_ptr get_rgb(enum COLOR_SPACE cs_name); + static std::shared_ptr get_cs(enum COLOR_SPACE cs_name); }; diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index 72a05b4a323..8f3b1c94efa 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -160,14 +160,14 @@ Color GetColor::get_color(CONST_COLOR const_color) { { case cv::ccm::Macbeth: { - Color Macbeth_D50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2, ColorChecker2005_COLORED_MASK); - return Macbeth_D50_2; + std::shared_ptr Macbeth_D50_2(new Color(ColorChecker2005_LAB_D50_2, Lab_D50_2, ColorChecker2005_COLORED_MASK)); + return *Macbeth_D50_2; break; } case cv::ccm::Vinyl: { - Color Vinyl_D50_2(Vinyl_LAB_D50_2, Lab_D50_2, Vinyl_COLORED_MASK); - return Vinyl_D50_2; + std::shared_ptr Vinyl_D50_2(new Color(Vinyl_LAB_D50_2, Lab_D50_2, Vinyl_COLORED_MASK)); + return *Vinyl_D50_2; break; } diff --git a/modules/mcc/src/colorspace.cpp b/modules/mcc/src/colorspace.cpp index 48897a4100c..707b6821b96 100644 --- a/modules/mcc/src/colorspace.cpp +++ b/modules/mcc/src/colorspace.cpp @@ -346,13 +346,14 @@ Mat XYZ::cam_(IO sio, IO dio, CAM method) const { return M; } -std::map XYZ::xyz_cs = {}; +std::map > XYZ::xyz_cs = {}; -XYZ* XYZ::get(IO io) { +std::shared_ptr XYZ::get(IO io) { if (xyz_cs.count(io) == 1) { return xyz_cs[io]; } - xyz_cs[io] = new XYZ(io); + std::shared_ptr XYZ_CS(new XYZ(io)); + xyz_cs[io] = XYZ_CS; return xyz_cs[io]; } @@ -401,27 +402,27 @@ Mat Lab::tosrc(Mat& src) { return channelWise(src, [this](cv::Vec3d a) -> cv::Vec3d { return tolab(a); }); } -std::map Lab::lab_cs = {}; - -Lab* Lab::get(IO io) { +std::map > Lab::lab_cs = {}; +std::shared_ptr Lab::get(IO io) { if (lab_cs.count(io) == 1) { return lab_cs[io]; } - lab_cs[io] = new Lab(io); + std::shared_ptr Lab_CS(new Lab(io)); + lab_cs[io] = Lab_CS; return lab_cs[io]; } //static std::map map_cs = {}; -std::map GetCS::map_cs = {}; +std::map > GetCS::map_cs = {}; -RGBBase_* GetCS::get_rgb(enum COLOR_SPACE cs_name) { +std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) { switch (cs_name) { case cv::ccm::sRGB: { if (map_cs.count(cs_name) < 1) { - sRGB_* sRGB_CS = new sRGB_(false); - sRGB_* sRGBL_CS =new sRGB_(true); + std::shared_ptr sRGB_CS(new sRGB_(false)); + std::shared_ptr sRGBL_CS(new sRGB_(true)); (*sRGB_CS).bind(*sRGBL_CS); map_cs[sRGB] = sRGB_CS; map_cs[sRGBL] = sRGBL_CS; @@ -431,10 +432,8 @@ RGBBase_* GetCS::get_rgb(enum COLOR_SPACE cs_name) { case cv::ccm::AdobeRGB: { if (map_cs.count(cs_name) < 1) { - // AdobeRGB_ AdobeRGB_CS(false), AdobeRGBL_CS(true); - // AdobeRGB_CS.bind(AdobeRGBL_CS); - AdobeRGB_* AdobeRGB_CS = new AdobeRGB_(false); - AdobeRGB_* AdobeRGBL_CS = new AdobeRGB_(true); + std::shared_ptr AdobeRGB_CS(new AdobeRGB_(false)); + std::shared_ptr AdobeRGBL_CS(new AdobeRGB_(true)); (*AdobeRGB_CS).bind(*AdobeRGBL_CS); map_cs[AdobeRGB] = AdobeRGB_CS; map_cs[AdobeRGBL] = AdobeRGBL_CS; @@ -444,12 +443,8 @@ RGBBase_* GetCS::get_rgb(enum COLOR_SPACE cs_name) { case cv::ccm::WideGamutRGB: { if (map_cs.count(cs_name) < 1) { - /*WideGamutRGB_ WideGamutRGB_CS(false), WideGamutRGBL_CS(true); - WideGamutRGB_CS.bind(WideGamutRGBL_CS); - map_cs[WideGamutRGB] = &WideGamutRGB_CS; - map_cs[WideGamutRGBL] = &WideGamutRGBL_CS;*/ - WideGamutRGB_* WideGamutRGB_CS = new WideGamutRGB_(false); - WideGamutRGB_* WideGamutRGBL_CS = new WideGamutRGB_(false); + std::shared_ptr WideGamutRGB_CS(new WideGamutRGB_(false)); + std::shared_ptr WideGamutRGBL_CS(new WideGamutRGB_(true)); (*WideGamutRGB_CS).bind(*WideGamutRGBL_CS); map_cs[WideGamutRGB] = WideGamutRGB_CS; map_cs[WideGamutRGBL] = WideGamutRGBL_CS; @@ -459,8 +454,8 @@ RGBBase_* GetCS::get_rgb(enum COLOR_SPACE cs_name) { case cv::ccm::ProPhotoRGB: { if (map_cs.count(cs_name) < 1) { - ProPhotoRGB_* ProPhotoRGB_CS = new ProPhotoRGB_(false); - ProPhotoRGB_* ProPhotoRGBL_CS= new ProPhotoRGB_(true); + std::shared_ptr ProPhotoRGB_CS(new ProPhotoRGB_(false)); + std::shared_ptr ProPhotoRGBL_CS(new ProPhotoRGB_(true)); (*ProPhotoRGB_CS).bind(*ProPhotoRGBL_CS); map_cs[ProPhotoRGB] = ProPhotoRGB_CS; map_cs[ProPhotoRGBL] = ProPhotoRGBL_CS; @@ -470,8 +465,8 @@ RGBBase_* GetCS::get_rgb(enum COLOR_SPACE cs_name) { case cv::ccm::DCI_P3_RGB: { if (map_cs.count(cs_name) < 1) { - DCI_P3_RGB_* DCI_P3_RGB_CS = new DCI_P3_RGB_(false); - DCI_P3_RGB_* DCI_P3_RGBL_CS =new DCI_P3_RGB_(true); + std::shared_ptr DCI_P3_RGB_CS(new DCI_P3_RGB_(false)); + std::shared_ptr DCI_P3_RGBL_CS(new DCI_P3_RGB_(true)); (*DCI_P3_RGB_CS).bind(*DCI_P3_RGBL_CS); map_cs[DCI_P3_RGB] = DCI_P3_RGB_CS; map_cs[DCI_P3_RGBL] = DCI_P3_RGBL_CS; @@ -481,8 +476,8 @@ RGBBase_* GetCS::get_rgb(enum COLOR_SPACE cs_name) { case cv::ccm::AppleRGB: { if (map_cs.count(cs_name) < 1) { - AppleRGB_* AppleRGB_CS = new AppleRGB_(false); - AppleRGB_* AppleRGBL_CS = new AppleRGB_(true); + std::shared_ptr AppleRGB_CS(new AppleRGB_(false)); + std::shared_ptr AppleRGBL_CS(new AppleRGB_(true)); (*AppleRGB_CS).bind(*AppleRGBL_CS); map_cs[AppleRGB] = AppleRGB_CS; map_cs[AppleRGBL] = AppleRGBL_CS; @@ -492,8 +487,8 @@ RGBBase_* GetCS::get_rgb(enum COLOR_SPACE cs_name) { case cv::ccm::REC_709_RGB: { if (map_cs.count(cs_name) < 1) { - REC_709_RGB_* REC_709_RGB_CS = new REC_709_RGB_(false); - REC_709_RGB_* REC_709_RGBL_CS= new REC_709_RGB_(true); + std::shared_ptr REC_709_RGB_CS(new REC_709_RGB_(false)); + std::shared_ptr REC_709_RGBL_CS(new REC_709_RGB_(true)); (*REC_709_RGB_CS).bind(*REC_709_RGBL_CS); map_cs[REC_709_RGB] = REC_709_RGB_CS; map_cs[REC_709_RGBL] = REC_709_RGBL_CS; @@ -503,8 +498,8 @@ RGBBase_* GetCS::get_rgb(enum COLOR_SPACE cs_name) { case cv::ccm::REC_2020_RGB: { if (map_cs.count(cs_name) < 1) { - REC_2020_RGB_* REC_2020_RGB_CS = new REC_2020_RGB_(false); - REC_2020_RGB_* REC_2020_RGBL_CS = new REC_2020_RGB_(true); + std::shared_ptr REC_2020_RGB_CS(new REC_2020_RGB_(false)); + std::shared_ptr REC_2020_RGBL_CS(new REC_2020_RGB_(true)); (*REC_2020_RGB_CS).bind(*REC_2020_RGBL_CS); map_cs[REC_2020_RGB] = REC_2020_RGB_CS; map_cs[REC_2020_RGBL] = REC_2020_RGBL_CS; @@ -525,18 +520,19 @@ RGBBase_* GetCS::get_rgb(enum COLOR_SPACE cs_name) { default: throw "Only RGB color spaces are supported"; } - return (RGBBase_*)(map_cs[cs_name]); + // return (std::shared_ptr < RGBBase_>)(*map_cs[cs_name]); + return (std::dynamic_pointer_cast)(map_cs[cs_name]); } -ColorSpace* GetCS::get_cs(enum COLOR_SPACE cs_name) { +std::shared_ptr GetCS::get_cs(enum COLOR_SPACE cs_name) { switch (cs_name) { case cv::ccm::sRGB: case cv::ccm::sRGBL: { if (map_cs.count(cs_name) < 1) { - sRGB_* sRGB_CS = new sRGB_(false); - sRGB_* sRGBL_CS = new sRGB_(true); + std::shared_ptr sRGB_CS(new sRGB_(false)); + std::shared_ptr sRGBL_CS(new sRGB_(true)); (*sRGB_CS).bind(*sRGBL_CS); map_cs[sRGB] = sRGB_CS; map_cs[sRGBL] = sRGBL_CS; @@ -547,8 +543,8 @@ ColorSpace* GetCS::get_cs(enum COLOR_SPACE cs_name) { case cv::ccm::AdobeRGBL: { if (map_cs.count(cs_name) < 1) { - AdobeRGB_* AdobeRGB_CS = new AdobeRGB_(false); - AdobeRGB_* AdobeRGBL_CS = new AdobeRGB_(true); + std::shared_ptr AdobeRGB_CS(new AdobeRGB_(false)); + std::shared_ptr AdobeRGBL_CS(new AdobeRGB_(true)); (*AdobeRGB_CS).bind(*AdobeRGBL_CS); map_cs[AdobeRGB] = AdobeRGB_CS; map_cs[AdobeRGBL] = AdobeRGBL_CS; @@ -559,12 +555,8 @@ ColorSpace* GetCS::get_cs(enum COLOR_SPACE cs_name) { case cv::ccm::WideGamutRGBL: { if (map_cs.count(cs_name) < 1) { - /* WideGamutRGB_ WideGamutRGB_CS(false), WideGamutRGBL_CS(true); - WideGamutRGB_CS.bind(WideGamutRGBL_CS); - map_cs[WideGamutRGB] = &WideGamutRGB_CS; - map_cs[WideGamutRGBL] = &WideGamutRGBL_CS;*/ - WideGamutRGB_* WideGamutRGB_CS = new WideGamutRGB_(false); - WideGamutRGB_* WideGamutRGBL_CS = new WideGamutRGB_(false); + std::shared_ptr WideGamutRGB_CS(new WideGamutRGB_(false)); + std::shared_ptr WideGamutRGBL_CS(new WideGamutRGB_(true)); (*WideGamutRGB_CS).bind(*WideGamutRGBL_CS); map_cs[WideGamutRGB] = WideGamutRGB_CS; map_cs[WideGamutRGBL] = WideGamutRGBL_CS; @@ -576,8 +568,8 @@ ColorSpace* GetCS::get_cs(enum COLOR_SPACE cs_name) { case cv::ccm::ProPhotoRGBL: { if (map_cs.count(cs_name) < 1) { - ProPhotoRGB_* ProPhotoRGB_CS = new ProPhotoRGB_(false); - ProPhotoRGB_* ProPhotoRGBL_CS = new ProPhotoRGB_(true); + std::shared_ptr ProPhotoRGB_CS(new ProPhotoRGB_(false)); + std::shared_ptr ProPhotoRGBL_CS(new ProPhotoRGB_(true)); (*ProPhotoRGB_CS).bind(*ProPhotoRGBL_CS); map_cs[ProPhotoRGB] = ProPhotoRGB_CS; map_cs[ProPhotoRGBL] = ProPhotoRGBL_CS; @@ -588,8 +580,8 @@ ColorSpace* GetCS::get_cs(enum COLOR_SPACE cs_name) { case cv::ccm::DCI_P3_RGBL: { if (map_cs.count(cs_name) < 1) { - DCI_P3_RGB_* DCI_P3_RGB_CS = new DCI_P3_RGB_(false); - DCI_P3_RGB_* DCI_P3_RGBL_CS = new DCI_P3_RGB_(true); + std::shared_ptr DCI_P3_RGB_CS(new DCI_P3_RGB_(false)); + std::shared_ptr DCI_P3_RGBL_CS(new DCI_P3_RGB_(true)); (*DCI_P3_RGB_CS).bind(*DCI_P3_RGBL_CS); map_cs[DCI_P3_RGB] = DCI_P3_RGB_CS; map_cs[DCI_P3_RGBL] = DCI_P3_RGBL_CS; @@ -600,8 +592,8 @@ ColorSpace* GetCS::get_cs(enum COLOR_SPACE cs_name) { case cv::ccm::AppleRGBL: { if (map_cs.count(cs_name) < 1) { - AppleRGB_* AppleRGB_CS = new AppleRGB_(false); - AppleRGB_* AppleRGBL_CS = new AppleRGB_(true); + std::shared_ptr AppleRGB_CS(new AppleRGB_(false)); + std::shared_ptr AppleRGBL_CS(new AppleRGB_(true)); (*AppleRGB_CS).bind(*AppleRGBL_CS); map_cs[AppleRGB] = AppleRGB_CS; map_cs[AppleRGBL] = AppleRGBL_CS; @@ -612,8 +604,8 @@ ColorSpace* GetCS::get_cs(enum COLOR_SPACE cs_name) { case cv::ccm::REC_709_RGBL: { if (map_cs.count(cs_name) < 1) { - REC_709_RGB_* REC_709_RGB_CS = new REC_709_RGB_(false); - REC_709_RGB_* REC_709_RGBL_CS = new REC_709_RGB_(true); + std::shared_ptr REC_709_RGB_CS(new REC_709_RGB_(false)); + std::shared_ptr REC_709_RGBL_CS(new REC_709_RGB_(true)); (*REC_709_RGB_CS).bind(*REC_709_RGBL_CS); map_cs[REC_709_RGB] = REC_709_RGB_CS; map_cs[REC_709_RGBL] = REC_709_RGBL_CS; @@ -624,8 +616,8 @@ ColorSpace* GetCS::get_cs(enum COLOR_SPACE cs_name) { case cv::ccm::REC_2020_RGBL: { if (map_cs.count(cs_name) < 1) { - REC_2020_RGB_* REC_2020_RGB_CS = new REC_2020_RGB_(false); - REC_2020_RGB_* REC_2020_RGBL_CS = new REC_2020_RGB_(true); + std::shared_ptr REC_2020_RGB_CS(new REC_2020_RGB_(false)); + std::shared_ptr REC_2020_RGBL_CS(new REC_2020_RGB_(true)); (*REC_2020_RGB_CS).bind(*REC_2020_RGBL_CS); map_cs[REC_2020_RGB] = REC_2020_RGB_CS; map_cs[REC_2020_RGBL] = REC_2020_RGBL_CS; @@ -708,7 +700,7 @@ ColorSpace* GetCS::get_cs(enum COLOR_SPACE cs_name) { break; } - return map_cs.find(cs_name)->second; + return map_cs[cs_name]; } } // namespace ccm diff --git a/modules/mcc/test/test_ccm.cpp b/modules/mcc/test/test_ccm.cpp index d10afa65780..a66c7e492c3 100644 --- a/modules/mcc/test/test_ccm.cpp +++ b/modules/mcc/test/test_ccm.cpp @@ -39,7 +39,8 @@ Mat s = (Mat_(24, 1) << TEST(CV_ccmRunColorCorrection, test_model) { - ColorCorrectionModel model(s / 255, Color(ColorChecker2005_LAB_D50_2, Lab_D50_2)); + // ColorCorrectionModel model(s / 255, Color(ColorChecker2005_LAB_D50_2, Lab_D50_2)); + ColorCorrectionModel model(s / 255, Macbeth); Mat src_rgbl = (Mat_(24, 1) << Vec3d(0.68078957, 0.12382801, 0.01514889), Vec3d(0.81177942, 0.32550452, 0.089818), @@ -111,8 +112,8 @@ TEST(CV_ccmRunColorCorrection, test_masks_weights_1) 1.3, 0, 0, 1.4, 0, 0, 0.5, 0, 0, 0.6, 0, 0, 0.7, 0, 0, 0.8, 0, 0); - ColorCorrectionModel model1(s / 255, GetColor::get_color(Macbeth), sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, { 0, 0.98 }, weights_list_, 1.5); - + //ColorCorrectionModel model1(s / 255, GetColor::get_color(Macbeth), sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, { 0, 0.98 }, weights_list_, 1.5); + ColorCorrectionModel model1(s / 255,Macbeth, sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, { 0, 0.98 }, weights_list_, 1.5); Mat weights = (Mat_(8, 1) << 1.15789474, 1.26315789, 1.36842105, 1.47368421, 0.52631579, 0.63157895, 0.73684211, 0.84210526); @@ -128,7 +129,8 @@ TEST(CV_ccmRunColorCorrection, test_masks_weights_1) TEST(CV_ccmRunColorCorrection, test_masks_weights_2) { - ColorCorrectionModel model2(s / 255, GetColor::get_color(Macbeth), sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, {0.05, 0.93}, Mat(), 1.5); + // ColorCorrectionModel model2(s / 255, GetColor::get_color(Macbeth), sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, {0.05, 0.93}, Mat(), 1.5); + ColorCorrectionModel model2(s / 255, Macbeth, sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, { 0.05, 0.93 }, Mat(), 1.5); Mat weights = (Mat_(20, 1) << 0.65554256, 1.49454705, 1.00499244, 0.79735434, 1.16327759, From 5c548dff74e848ca44ab1ba479717af1234599a9 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Wed, 23 Sep 2020 11:14:47 +0800 Subject: [PATCH 29/71] fix markdown for new version --- modules/mcc/include/opencv2/mcc/ccm.hpp | 61 +++++++------------ modules/mcc/include/opencv2/mcc/color.hpp | 13 +--- .../mcc/include/opencv2/mcc/colorspace.hpp | 19 +----- .../mcc/samples/color_correction_model.cpp | 16 ++--- modules/mcc/src/ccm.cpp | 10 --- modules/mcc/src/color.cpp | 27 -------- .../basic_ccm/color_correction_model.markdown | 4 +- 7 files changed, 36 insertions(+), 114 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index a4e4d461dc2..0ead609980c 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -259,10 +259,6 @@ class CV_EXPORTS_W ColorCorrectionModel double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, cv::Mat weights_list = Mat(), double weights_coeff = 0, INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); - /* ColorCorrectionModel(Mat src_, Mat colors_, const ColorSpace& ref_cs_, RGBBase_& cs_ , CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, - double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, - INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4);*/ - ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_ , CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); @@ -288,13 +284,35 @@ class CV_EXPORTS_W ColorCorrectionModel */ Mat initialWhiteBalance(void); - /* *\ brief Fitting nonlinear-optimization initial value by least square. * see CCM.pdf for details *\ param fit if fit is True, return optimalization for rgbl distance function. */ void initialLeastSquare(bool fit = false); + double calc_loss_(Color color); + double calc_loss(const Mat ccm_); + + /* *\ brief Fitting ccm if distance function is associated with CIE Lab color space. + * see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp + * Set terminal criteria for solver is possible. + */ + void fitting(void); + + /* *\ brief Infer using fitting ccm. + *\ param img the input image, type of cv::Mat. + *\ return the output array, type of cv::Mat. + */ + Mat infer(const Mat& img, bool islinear = false); + + /* *\ brief Infer image and output as an BGR image with uint8 type. + * mainly for test or debug. + * input size and output size should be 255. + *\ param imgfile path name of image to infer. + *\ param islinear if linearize or not. + *\ return the output array, type of cv::Mat. + */ + Mat inferImage(std::string imgfile, bool islinear = false); /* *\ brief Loss function base on cv::MinProblemSolver::Function. * see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp @@ -317,7 +335,6 @@ class CV_EXPORTS_W ColorCorrectionModel double calc(const double* x) const CV_OVERRIDE { Mat ccm_(ccm_loss->shape, 1, CV_64F); - for (int i = 0; i < ccm_loss->shape; i++) { ccm_.at(i, 0) = x[i]; @@ -326,41 +343,9 @@ class CV_EXPORTS_W ColorCorrectionModel return ccm_loss->calc_loss(ccm_); } }; - - double calc_loss_(Color color); - - double calc_loss(const Mat ccm_); - - - /* *\ brief Fitting ccm if distance function is associated with CIE Lab color space. - * see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp - * Set terminal criteria for solver is possible. - */ - - void fitting(void); - - - /* *\ brief Infer using fitting ccm. - *\ param img the input image, type of cv::Mat. - *\ return the output array, type of cv::Mat. - */ - Mat infer(const Mat& img, bool islinear = false); - - - /* *\ brief Infer image and output as an BGR image with uint8 type. - * mainly for test or debug. - * input size and output size should be 255. - *\ param imgfile path name of image to infer. - *\ param islinear if linearize or not. - *\ return the output array, type of cv::Mat. - */ - Mat inferImage(std::string imgfile, bool islinear = false); - - }; } // namespace ccm } // namespace cv - #endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/color.hpp b/modules/mcc/include/opencv2/mcc/color.hpp index f9cdedb2da3..6998af4eb5d 100644 --- a/modules/mcc/include/opencv2/mcc/color.hpp +++ b/modules/mcc/include/opencv2/mcc/color.hpp @@ -194,15 +194,8 @@ const Mat Vinyl_COLORED_MASK = (Mat_(18, 1) << 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); -/* *\ brief Macbeth ColorChecker with 2deg D50. +/* *\ brief Macbeth and Vinyl ColorChecker with 2deg D50 . */ -//const Color Macbeth_D50_2; -// -///* *\ brief Macbeth ColorChecker with 2deg D65. -//*/ -//const Color Macbeth_D65_2; -// -//const Color Vinyl_D50_2; enum CONST_COLOR { Macbeth, Vinyl @@ -213,10 +206,6 @@ class CV_EXPORTS_W GetColor { }; -//const Color Macbeth_D50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2, ColorChecker2005_COLORED_MASK); -////const Color Macbeth_D65_2(ColorChecker2005_LAB_D65_2, Lab_D65_2, ColorChecker2005_COLORED_MASK); -//const Color Vinyl_D50_2(Vinyl_LAB_D50_2, Lab_D50_2, Vinyl_COLORED_MASK); - } // namespace ccm } // namespace cv diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp index f81454e7b12..3fc4c55ee1a 100644 --- a/modules/mcc/include/opencv2/mcc/colorspace.hpp +++ b/modules/mcc/include/opencv2/mcc/colorspace.hpp @@ -211,7 +211,6 @@ class CV_EXPORTS_W sRGBBase_ : public RGBBase_ */ double toLFuncEW(double& x); - /* *\ brief Linearization. * see ColorSpace.pdf for details. *\ param rgb the input array, type of cv::Mat. @@ -357,15 +356,8 @@ class CV_EXPORTS_W XYZ :public ColorSpace public: XYZ(IO io_) : ColorSpace(io_, "XYZ", true) {}; Operations cam(IO dio, CAM method = BRADFORD); - // static std::map xyz_cs; static std::map > xyz_cs; - static std::shared_ptr get(IO io);/* { - if (xyz_cs.count(io) == 1) { - return xyz_cs[io]; - } - xyz_cs[io] = new XYZ(io); - return xyz_cs[io]; - }*/ + static std::shared_ptr get(IO io); private: /* *\ brief Get cam. @@ -389,13 +381,7 @@ class CV_EXPORTS_W Lab :public ColorSpace public: static std::map > lab_cs; Lab(IO io_); - static std::shared_ptr get(IO io);/*{ - if (lab_cs.count(io) == 1) { - return lab_cs[io]; - } - lab_cs[io] = new Lab(io); - return lab_cs[io]; - }*/ + static std::shared_ptr get(IO io); private: static constexpr double delta = (6. / 29.); @@ -431,7 +417,6 @@ const Lab Lab_D50_2_CS(D50_2); class CV_EXPORTS_W GetCS { public: static std::map > map_cs; - //static RGBBase_* get_rgb(enum COLOR_SPACE cs_name); static std::shared_ptr get_rgb(enum COLOR_SPACE cs_name); static std::shared_ptr get_cs(enum COLOR_SPACE cs_name); }; diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp index 9da005c4d48..602bdf9f66b 100644 --- a/modules/mcc/samples/color_correction_model.cpp +++ b/modules/mcc/samples/color_correction_model.cpp @@ -72,20 +72,20 @@ int main(int argc, char *argv[]) src /= 255.0; //compte color correction matrix - ColorCorrectionModel model1(src, Vinyl_D50_2); + ColorCorrectionModel model1(src, Vinyl); /* brief More models with different parameters, try it & check the document for details. */ - // ColorCorrectionModel model2(src, Vinyl_D50_2, AdobeRGB, CCM_4x3, CIE2000, GAMMA, 2.2, 3); - // ColorCorrectionModel model3(src, Vinyl_D50_2, WideGamutRGB, CCM_4x3, CIE2000, GRAYPOLYFIT, 2.2, 3); - // ColorCorrectionModel model4(src, Vinyl_D50_2, ProPhotoRGB, CCM_4x3, RGBL, GRAYLOGPOLYFIT, 2.2, 3); - // ColorCorrectionModel model5(src, Vinyl_D50_2, DCI_P3_RGB, CCM_3x3, RGB, IDENTITY_, 2.2, 3); - // ColorCorrectionModel model6(src, Vinyl_D50_2, AppleRGB, CCM_3x3, CIE2000, COLORPOLYFIT, 2.2, 2,{ 0, 0.98 },Mat(),2); - // ColorCorrectionModel model7(src, Vinyl_D50_2, REC_2020_RGB, CCM_3x3, CIE94_GRAPHIC_ARTS, COLORLOGPOLYFIT, 2.2, 3); + // ColorCorrectionModel model2(src, Vinyl, AdobeRGB, CCM_4x3, CIE2000, GAMMA, 2.2, 3); + // ColorCorrectionModel model3(src, Vinyl, WideGamutRGB, CCM_4x3, CIE2000, GRAYPOLYFIT, 2.2, 3); + // ColorCorrectionModel model4(src, Vinyl, ProPhotoRGB, CCM_4x3, RGBL, GRAYLOGPOLYFIT, 2.2, 3); + // ColorCorrectionModel model5(src, Vinyl, DCI_P3_RGB, CCM_3x3, RGB, IDENTITY_, 2.2, 3); + // ColorCorrectionModel model6(src, Vinyl, AppleRGB, CCM_3x3, CIE2000, COLORPOLYFIT, 2.2, 2,{ 0, 0.98 },Mat(),2); + // ColorCorrectionModel model7(src, Vinyl, REC_2020_RGB, CCM_3x3, CIE94_GRAPHIC_ARTS, COLORLOGPOLYFIT, 2.2, 3); /* If you use a customized ColorChecker, you can use your own reference color values and corresponding color space in a way like: */ - // cv::Mat ref = = (Mat_(18, 1) << + // cv::Mat ref = (Mat_(18, 1) << // Vec3d(1.00000000e+02, 5.20000001e-03, -1.04000000e-02), // Vec3d(7.30833969e+01, -8.19999993e-01, -2.02099991e+00), // Vec3d(6.24930000e+01, 4.25999999e-01, -2.23099995e+00), diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 6075b66000f..dd93bdebf37 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -48,12 +48,6 @@ namespace ccm ColorCorrectionModel(src_, dst_, *GetCS::get_rgb(cs_), ccm_type_, distance_, linear_type, gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} -//ColorCorrectionModel::ColorCorrectionModel(Mat src_, Mat colors_, const ColorSpace& ref_cs_, RGBBase_& cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, -// double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, -// INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : -// ColorCorrectionModel(src_, Color(colors_, ref_cs_), cs_, ccm_type_, distance_, linear_type, -// gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} - ColorCorrectionModel::ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : @@ -62,7 +56,6 @@ ColorCorrectionModel::ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_, Mat saturate_mask = saturate(src, saturated_threshold[0], saturated_threshold[1]); this->linear = getLinear(gamma, deg, this->src, this->dst, saturate_mask, this->cs, linear_type); calWeightsMasks(weights_list, weights_coeff, saturate_mask); - src_rgbl = this->linear->linearize(maskCopyTo(this->src, mask)); dst.colors = maskCopyTo(dst.colors, mask); dst_rgbl = this->dst.to(*(this->cs.l)).colors; @@ -91,7 +84,6 @@ ColorCorrectionModel::ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_, } break; } - fitting(); } @@ -158,7 +150,6 @@ Mat ColorCorrectionModel::initialWhiteBalance(void) sum(dchannels[2])[0] / sum(schannels[2])[0], 0, 0, 0 }; std::vector initial_vec_(initial_vec.begin(), initial_vec.begin() + shape); Mat initial_white_balance = Mat(initial_vec_, true).reshape(0, shape / 3); - return initial_white_balance; } @@ -264,6 +255,5 @@ Mat ColorCorrectionModel::inferImage(std::string imgfile, bool islinear) return out_img; } - } // namespace ccm } // namespace cv diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index 8f3b1c94efa..2134fc36d00 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -31,8 +31,6 @@ namespace cv { namespace ccm { - //Color(Mat colors_, enum COLOR_SPACE cs_); - //Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_); Color::Color(Mat colors_, enum COLOR_SPACE cs_) :colors(colors_), cs(*GetCS::get_cs(cs_)) {}; Color::Color(Mat colors_, const ColorSpace& cs_, Mat colored_) : colors(colors_), cs(cs_), colored(colored_) @@ -43,7 +41,6 @@ Color::Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_) : colors(colors_), grays = ~colored; } Color::Color(Mat colors_, const ColorSpace& cs_) : colors(colors_), cs(cs_) {}; -//Color Color::to(const ColorSpace& other, CAM method, bool save) Color Color::to(const ColorSpace& other, CAM method , bool save) { if (history.count(other) == 1) @@ -67,23 +64,6 @@ Color Color::to(const ColorSpace& other, CAM method , bool save) Color Color::to( COLOR_SPACE other, CAM method, bool save) { return to(*GetCS::get_cs(other), method, save); - // if (history.count(other) == 1) - //if (history.count(*get_cs(other)) == 1) - //{ - // return *history[*get_cs(other)]; - //} - //if (cs.relate(*get_cs(other))) - //{ - // return Color(cs.relation(*get_cs(other)).run(colors), other); - //} - //Operations ops; - //ops.add(cs.to).add(XYZ(cs.io).cam((*get_cs(other)).io, method).add((*get_cs(other)).from)); - //std::shared_ptr color(new Color(ops.run(colors), other)); - //if (save) - //{ - // history[*get_cs(other)] = color; - //} - //return *color; } Mat Color::channel(Mat m, int i) @@ -95,14 +75,12 @@ Mat Color::channel(Mat m, int i) Mat Color::toGray(IO io, CAM method, bool save) { - //XYZ xyz(io); XYZ xyz = *XYZ::get(io); return channel(this->to(xyz, method, save).colors, 1); } Mat Color::toLuminant(IO io, CAM method, bool save) { - // Lab lab(io); Lab lab= *Lab::get(io); return channel(this->to(lab, method, save).colors, 0); } @@ -114,7 +92,6 @@ Mat Color::diff(Color& other, DISTANCE_TYPE method) Mat Color::diff(Color& other, IO io, DISTANCE_TYPE method) { - // Lab lab(io); Lab lab = *Lab::get(io); switch (method) { @@ -176,9 +153,5 @@ Color GetColor::get_color(CONST_COLOR const_color) { break; } } -//Color Macbeth_D50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2, ColorChecker2005_COLORED_MASK); -//Color Macbeth_D65_2(ColorChecker2005_LAB_D65_2, Lab_D65_2, ColorChecker2005_COLORED_MASK); -//Color Vinyl_D50_2(Vinyl_LAB_D50_2, Lab_D50_2, Vinyl_COLORED_MASK); - } // namespace ccm } // namespace cv \ No newline at end of file diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index 39d946e1ab7..37ef7315817 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -211,13 +211,13 @@ Preparation for ColorChecker detection to get messages for the image. The CCheckerDetectorobject is created and uses getListColorChecker function to get ColorChecker message. ``` -@code{.cpp} for (Ptr checker : checkers) { Ptr cdraw = CCheckerDraw::create(checker); cdraw->draw(image); Mat chartsRGB = checker->getChartsRGB();Mat src = chartsRGB.col(1).clone().reshape(3, 18); src /= 255.0; //compte color correction matrix ColorCorrectionModel model1(src, Vinyl_D50_2);}@endcode +@code{.cpp} for (Ptr checker : checkers) { Ptr cdraw = CCheckerDraw::create(checker); cdraw->draw(image); Mat chartsRGB = checker->getChartsRGB();Mat src = chartsRGB.col(1).clone().reshape(3, 18); src /= 255.0; //compte color correction matrix ColorCorrectionModel model1(src, Vinyl);}@endcode ``` For every ColorChecker, we can compute a ccm matrix for color correction. Model1 is an object of ColorCorrectionModel class. The parameters should be changed to get the best effect of color correction. See other parameters' detail at the Parameters. ``` -@code{.cpp}cv::Mat ref = = (Mat_(18, 1) <(18, 1) < Date: Wed, 23 Sep 2020 14:19:05 +0800 Subject: [PATCH 30/71] delete useless include message --- modules/mcc/include/opencv2/mcc/colorspace.hpp | 1 - modules/mcc/src/colorspace.cpp | 6 ------ 2 files changed, 7 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp index 3fc4c55ee1a..37310d957ad 100644 --- a/modules/mcc/include/opencv2/mcc/colorspace.hpp +++ b/modules/mcc/include/opencv2/mcc/colorspace.hpp @@ -34,7 +34,6 @@ #include #include "opencv2/mcc/io.hpp" #include "opencv2/mcc/operations.hpp" -#include "opencv2/mcc/utils.hpp" namespace cv { diff --git a/modules/mcc/src/colorspace.cpp b/modules/mcc/src/colorspace.cpp index 707b6821b96..2200034dbe4 100644 --- a/modules/mcc/src/colorspace.cpp +++ b/modules/mcc/src/colorspace.cpp @@ -203,7 +203,6 @@ Mat sRGBBase_::fromLFunc(Mat& rgbl) { /* *\ brief sRGB color space. * data from https://en.wikipedia.org/wiki/SRGB. */ - void sRGB_::setParameter() { xr = 0.64; yr = 0.33; @@ -217,7 +216,6 @@ void sRGB_::setParameter() { /* *\ brief Adobe RGB color space. */ - void AdobeRGB_::setParameter() { xr = 0.64; yr = 0.33; @@ -231,7 +229,6 @@ void AdobeRGB_::setParameter() { /* *\ brief Wide-gamut RGB color space. * data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. */ - void WideGamutRGB_::setParameter() { xr = 0.7347; yr = 0.2653; @@ -245,7 +242,6 @@ void WideGamutRGB_::setParameter() { /* *\ brief ProPhoto RGB color space. * data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. */ - void ProPhotoRGB_::setParameter() { xr = 0.734699; yr = 0.265301; @@ -274,7 +270,6 @@ void DCI_P3_RGB_::setParameter() { * data from * http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. */ - void AppleRGB_::setParameter() { xr = 0.625; yr = 0.34; @@ -288,7 +283,6 @@ void AppleRGB_::setParameter() { /* *\ brief REC_709 RGB color space. * data from https://en.wikipedia.org/wiki/Rec._709. */ - void REC_709_RGB_::setParameter() { xr = 0.64; yr = 0.33; From 2a679087f952c5392ae17ed8db6209549de94e93 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Wed, 23 Sep 2020 16:59:58 +0800 Subject: [PATCH 31/71] update unittests --- modules/mcc/test/test_ccm.cpp | 3 -- modules/mcc/test/test_colorspace.cpp | 15 ---------- modules/mcc/test/test_io.cpp | 44 ---------------------------- 3 files changed, 62 deletions(-) delete mode 100644 modules/mcc/test/test_io.cpp diff --git a/modules/mcc/test/test_ccm.cpp b/modules/mcc/test/test_ccm.cpp index a66c7e492c3..68ef741d108 100644 --- a/modules/mcc/test/test_ccm.cpp +++ b/modules/mcc/test/test_ccm.cpp @@ -39,7 +39,6 @@ Mat s = (Mat_(24, 1) << TEST(CV_ccmRunColorCorrection, test_model) { - // ColorCorrectionModel model(s / 255, Color(ColorChecker2005_LAB_D50_2, Lab_D50_2)); ColorCorrectionModel model(s / 255, Macbeth); Mat src_rgbl = (Mat_(24, 1) << Vec3d(0.68078957, 0.12382801, 0.01514889), @@ -112,7 +111,6 @@ TEST(CV_ccmRunColorCorrection, test_masks_weights_1) 1.3, 0, 0, 1.4, 0, 0, 0.5, 0, 0, 0.6, 0, 0, 0.7, 0, 0, 0.8, 0, 0); - //ColorCorrectionModel model1(s / 255, GetColor::get_color(Macbeth), sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, { 0, 0.98 }, weights_list_, 1.5); ColorCorrectionModel model1(s / 255,Macbeth, sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, { 0, 0.98 }, weights_list_, 1.5); Mat weights = (Mat_(8, 1) << 1.15789474, 1.26315789, 1.36842105, 1.47368421, @@ -129,7 +127,6 @@ TEST(CV_ccmRunColorCorrection, test_masks_weights_1) TEST(CV_ccmRunColorCorrection, test_masks_weights_2) { - // ColorCorrectionModel model2(s / 255, GetColor::get_color(Macbeth), sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, {0.05, 0.93}, Mat(), 1.5); ColorCorrectionModel model2(s / 255, Macbeth, sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, { 0.05, 0.93 }, Mat(), 1.5); Mat weights = (Mat_(20, 1) << diff --git a/modules/mcc/test/test_colorspace.cpp b/modules/mcc/test/test_colorspace.cpp index 716df9c3495..88e8284b9ed 100644 --- a/modules/mcc/test/test_colorspace.cpp +++ b/modules/mcc/test/test_colorspace.cpp @@ -51,21 +51,6 @@ TEST(CV_ccmColorspace, test_WideGamutRGB_M) ASSERT_MAT_NEAR((*GetCS::get_rgb(WideGamutRGB)).M_from, from, 1e-2); } -// wont' work -//TEST(CV_ccmColorspace, test_WideGamutRGB_M) -//{ -// Mat to = (Mat_(3, 3) << -// 0.7161046, 0.1009296, 0.1471858, -// 0.2581874, 0.7249378, 0.0168748, -// 0.0000000, 0.0517813, 0.7734287); -// Mat from = (Mat_(3, 3) << -// 1.4628067, -0.1840623, -0.2743606, -// -0.5217933, 1.4472381, 0.0677227, -// 0.0349342, -0.0968930, 1.2884099) -// ASSERT_MAT_NEAR(WideGamutRGB.M_to, to, 1e-2); -// ASSERT_MAT_NEAR(WideGamutRGB.M_from, from, 1e-2); -//} -// TEST(CV_ccmColorspace, test_ProPhotoRGB_M) { Mat to = (Mat_(3, 3) << diff --git a/modules/mcc/test/test_io.cpp b/modules/mcc/test/test_io.cpp deleted file mode 100644 index daf33080d54..00000000000 --- a/modules/mcc/test/test_io.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. - -#include "test_precomp.hpp" - -#include -#include - -namespace opencv_test -{ -namespace -{ - -using namespace std; - -/* -std::map> illuminants_test = -{ - {A_2, { 1.098466069456375, 1, 0.3558228003436005 }}, - {A_10, { 1.111420406956693, 1, 0.3519978321919493 }}, - {D50_2, { 0.9642119944211994, 1, 0.8251882845188288 }}, - {D50_10, { 0.9672062750333777, 1, 0.8142801513128616 }}, - {D55_2, { 0.956797052643698, 1, 0.9214805860173273 }}, - {D55_10, { 0.9579665682254781, 1, 0.9092525159847462 }}, - {D65_2, { 0.95047, 1., 1.08883 }}, - {D65_10, { 0.94811, 1., 1.07304 }}, - {D75_2, { 0.9497220898840717, 1, 1.226393520724154 }}, - {D75_10, { 0.9441713925645873, 1, 1.2064272211720228 }}, - {E_2, { 1., 1., 1. }}, - {E_10, { 1., 1., 1. }}, -}; - -TEST(CV_ccmIO, test_illuminants) -{ - for (auto i = illuminants.begin(); i != illuminants.end(); ++i) - { - ASSERT_EQ(illuminants[i->first], illuminants_test[i->first]); - } -} -*/ - -} // namespace -} // namespace opencv_test From c775243151bf37550770f55f0073c97e67d6e838 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Sun, 27 Sep 2020 22:43:32 +0800 Subject: [PATCH 32/71] update docs & fix bugs for InitialwhiteBalance() --- modules/mcc/include/opencv2/mcc/ccm.hpp | 62 ++-- .../mcc/include/opencv2/mcc/colorspace.hpp | 3 + modules/mcc/src/ccm.cpp | 6 +- .../basic_ccm/color_correction_model.markdown | 289 +++++++++--------- 4 files changed, 194 insertions(+), 166 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 0ead609980c..53ecd272d72 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -47,22 +47,27 @@ namespace ccm detected colors of ColorChecker patches; NOTICE: the color type is RGB not BGR, and the color values are in [0, 1]; type: cv::Mat; - dst : - the reference colors; - NOTICE: Built-in color card or custom color card are supported; - Built-in: - Macbeth_D50_2: Macbeth ColorChecker with 2deg D50; - Macbeth_D65_2: Macbeth ColorChecker with 2deg D65; - Custom: - You should use Color - For the list of color spaces supported, see the notes below; - If the color type is some RGB, the format is RGB not BGR, and the color values are in [0, 1]; - type: Color; + constcolor : + the Built-in color card; + Supported list: + Macbeth: Macbeth ColorChecker with 2deg D50; + Vinyl: DKK ColorChecker with 2deg D50; + type: enum CONST_COLOR; + Mat colors_ : + the reference color values + and corresponding color space + NOTICE: the color values are in [0, 1] + type: cv::Mat + ref_cs_ : + the corresponding color space + NOTICE: For the list of color spaces supported, see the notes below; + If the color type is some RGB, the format is RGB not BGR; + type:enum COLOR_SPACE; colorspace : the absolute color space that detected colors convert to; NOTICE: it should be some RGB color space; For the list of RGB color spaces supported, see the notes below; - type: ColorSpace; + type: enum COLOR_SPACE; ccm_type : the shape of color correction matrix(CCM); Supported list: @@ -169,19 +174,26 @@ namespace ccm Lab_D65_2; XYZ_D50_2; XYZ_D65_2; - Supported IO (You can use Lab(io) or XYZ(io) to create color space): - A_2; - A_10; - D50_2; - D50_10; - D55_2; - D55_10; - D65_2; - D65_10; - D75_2; - D75_10; - E_2; - E_10; + XYZ_D65_10; + XYZ_D50_10; + XYZ_A_2; + XYZ_A_10; + XYZ_D55_2; + XYZ_D55_10; + XYZ_D75_2; + XYZ_D75_10; + XYZ_E_2; + XYZ_E_10; + Lab_D65_10; + Lab_D50_10; + Lab_A_2; + Lab_A_10; + Lab_D55_2; + Lab_D55_10; + Lab_D75_2; + Lab_D75_10; + Lab_E_2; + Lab_E_10; --------------------------------------------------- Abbr. src, s: source; diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp index 37310d957ad..f5078a91b23 100644 --- a/modules/mcc/include/opencv2/mcc/colorspace.hpp +++ b/modules/mcc/include/opencv2/mcc/colorspace.hpp @@ -39,6 +39,9 @@ namespace cv { namespace ccm { + +/** Supported Color Space. +*/ enum COLOR_SPACE { sRGB, sRGBL, diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index dd93bdebf37..c6b11d64971 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -73,7 +73,7 @@ ColorCorrectionModel::ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_, switch (initial_method_type) { case cv::ccm::WHITE_BALANCE: - initialWhiteBalance(); + ccm0 = initialWhiteBalance(); break; case cv::ccm::LEAST_SQUARE: initialLeastSquare(); @@ -141,9 +141,9 @@ void ColorCorrectionModel::calWeightsMasks(Mat weights_list, double weights_coef Mat ColorCorrectionModel::initialWhiteBalance(void) { - Mat schannels[3]; + Mat schannels[4]; split(src_rgbl, schannels); - Mat dchannels[3]; + Mat dchannels[4]; split(dst_rgbl, dchannels); std::vector initial_vec = { sum(dchannels[0])[0] / sum(schannels[0])[0], 0, 0, 0, sum(dchannels[1])[0] / sum(schannels[1])[0], 0, 0, 0, diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index 37ef7315817..31a3436d443 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -32,144 +32,157 @@ The sample has two parts of code, the first is the color checker detector model, ``` Here are the parameters for ColorCorrectionModel -src : - detected colors of ColorChecker patches; - NOTICE: the color type is RGB not BGR, and the color values are in [0, 1]; - type: cv::Mat; -dst : - the reference colors; - NOTICE: Built-in color card or custom color card are supported; - Built-in: - Macbeth_D50_2: Macbeth ColorChecker with 2deg D50; - Macbeth_D65_2: Macbeth ColorChecker with 2deg D65; - Custom: - You should use Color - For the list of color spaces supported, see the notes below; - If the color type is some RGB, the format is RGB not BGR, and the color values are in [0, 1]; - type: Color; -colorspace : - the absolute color space that detected colors convert to; - NOTICE: it should be some RGB color space; - For the list of RGB color spaces supported, see the notes below; - type: ColorSpace; -ccm_type : - the shape of color correction matrix(CCM); - Supported list: - "CCM_3x3": 3x3 matrix; - "CCM_4x3": 4x3 matrix; - type: enum CCM_TYPE; -distance : - the type of color distance; - Supported list: - "CIE2000"; - "CIE94_GRAPHIC_ARTS"; - "CIE94_TEXTILES"; - "CIE76"; - "CMC_1TO1"; - "CMC_2TO1"; - "RGB" : Euclidean distance of rgb color space; - "RGBL" : Euclidean distance of rgbl color space; - type: enum DISTANCE_TYPE; -linear_type : - the method of linearization; - NOTICE: see Linearization.pdf for details; - Supported list: - "IDENTITY_" : no change is made; - "GAMMA": gamma correction; - Need assign a value to gamma simultaneously; - "COLORPOLYFIT": polynomial fitting channels respectively; - Need assign a value to deg simultaneously; - "GRAYPOLYFIT": grayscale polynomial fitting; - Need assign a value to deg and dst_whites simultaneously; - "COLORLOGPOLYFIT": logarithmic polynomial fitting channels respectively; - Need assign a value to deg simultaneously; - "GRAYLOGPOLYFIT": grayscale Logarithmic polynomial fitting; - Need assign a value to deg and dst_whites simultaneously; - type: enum LINEAR_TYPE; -gamma : - the gamma value of gamma correction; - NOTICE: only valid when linear is set to "gamma"; - type: double; - -deg : - the degree of linearization polynomial; - NOTICE: only valid when linear is set to "COLORPOLYFIT", "GRAYPOLYFIT", - "COLORLOGPOLYFIT" and "GRAYLOGPOLYFIT"; - type: int; -saturated_threshold : - the threshold to determine saturation; - NOTICE: it is a tuple of [low, up]; - The colors in the closed interval [low, up] are reserved to participate - in the calculation of the loss function and initialization parameters. - type: std::vector; ---------------------------------------------------- -There are some ways to set weights: - 1. set weights_list only; - 2. set weights_coeff only; -see CCM.pdf for details; - -weights_list : - the list of weight of each color; - type: cv::Mat; - -weights_coeff : - the exponent number of L* component of the reference color in CIE Lab color space; - type: double; ---------------------------------------------------- -initial_method_type : - the method of calculating CCM initial value; - see CCM.pdf for details; - Supported list: - 'LEAST_SQUARE': least-squre method; - 'WHITE_BALANCE': white balance method; - -max_count, epsilon : - used in MinProblemSolver-DownhillSolver; - Terminal criteria to the algorithm; - type: int, double; - - ---------------------------------------------------- -Supported Color Space: - Supported list of RGB color spaces: - sRGB; - AdobeRGB; - WideGamutRGB; - ProPhotoRGB; - DCI_P3_RGB; - AppleRGB; - REC_709_RGB; - REC_2020_RGB; - - Supported list of linear RGB color spaces: - sRGBL; - AdobeRGBL; - WideGamutRGBL; - ProPhotoRGBL; - DCI_P3_RGBL; - AppleRGBL; - REC_709_RGBL; - REC_2020_RGBL; - - Supported list of non-RGB color spaces: - Lab_D50_2; - Lab_D65_2; - XYZ_D50_2; - XYZ_D65_2; - - Supported IO (You can use Lab(io) or XYZ(io) to create color space): - A_2; - A_10; - D50_2; - D50_10; - D55_2; - D55_10; - D65_2; - D65_10; - D75_2; - D75_10; - E_2; - E_10; + src : + detected colors of ColorChecker patches; + NOTICE: the color type is RGB not BGR, and the color values are in [0, 1]; + type: cv::Mat; + constcolor : + the Built-in color card; + Supported list: + Macbeth: Macbeth ColorChecker with 2deg D50; + Vinyl: DKK ColorChecker with 2deg D50; + type: enum CONST_COLOR; + Mat colors_ : + the reference color values + and corresponding color space + NOTICE: the color values are in [0, 1] + type: cv::Mat + ref_cs_ : + the corresponding color space + NOTICE: For the list of color spaces supported, see the notes below; + If the color type is some RGB, the format is RGB not BGR; + type:enum COLOR_SPACE; + colorspace : + the absolute color space that detected colors convert to; + NOTICE: it should be some RGB color space; + For the list of RGB color spaces supported, see the notes below; + type: enum COLOR_SPACE; + ccm_type : + the shape of color correction matrix(CCM); + Supported list: + "CCM_3x3": 3x3 matrix; + "CCM_4x3": 4x3 matrix; + type: enum CCM_TYPE; + default: CCM_3x3; + distance : + the type of color distance; + Supported list: + "CIE2000"; + "CIE94_GRAPHIC_ARTS"; + "CIE94_TEXTILES"; + "CIE76"; + "CMC_1TO1"; + "CMC_2TO1"; + "RGB" : Euclidean distance of rgb color space; + "RGBL" : Euclidean distance of rgbl color space; + type: enum DISTANCE_TYPE; + default: CIE2000; + linear_type : + the method of linearization; + NOTICE: see Linearization.pdf for details; + Supported list: + "IDENTITY_" : no change is made; + "GAMMA": gamma correction; + Need assign a value to gamma simultaneously; + "COLORPOLYFIT": polynomial fitting channels respectively; + Need assign a value to deg simultaneously; + "GRAYPOLYFIT": grayscale polynomial fitting; + Need assign a value to deg and dst_whites simultaneously; + "COLORLOGPOLYFIT": logarithmic polynomial fitting channels respectively; + Need assign a value to deg simultaneously; + "GRAYLOGPOLYFIT": grayscale Logarithmic polynomial fitting; + Need assign a value to deg and dst_whites simultaneously; + type: enum LINEAR_TYPE; + default: IDENTITY_; + gamma : + the gamma value of gamma correction; + NOTICE: only valid when linear is set to "gamma"; + type: double; + default: 2.2; + deg : + the degree of linearization polynomial; + NOTICE: only valid when linear is set to "COLORPOLYFIT", "GRAYPOLYFIT", + "COLORLOGPOLYFIT" and "GRAYLOGPOLYFIT"; + type: int; + default: 3; + saturated_threshold : + the threshold to determine saturation; + NOTICE: it is a tuple of [low, up]; + The colors in the closed interval [low, up] are reserved to participate + in the calculation of the loss function and initialization parameters. + type: std::vector; + default: { 0, 0.98 }; + --------------------------------------------------- + There are some ways to set weights: + 1. set weights_list only; + 2. set weights_coeff only; + see CCM.pdf for details; + weights_list : + the list of weight of each color; + type: cv::Mat; + default: empty array; + weights_coeff : + the exponent number of L* component of the reference color in CIE Lab color space; + type: double; + default: 0; + --------------------------------------------------- + initial_method_type : + the method of calculating CCM initial value; + see CCM.pdf for details; + Supported list: + 'LEAST_SQUARE': least-squre method; + 'WHITE_BALANCE': white balance method; + type: enum INITIAL_METHOD_TYPE; + max_count, epsilon : + used in MinProblemSolver-DownhillSolver; + Terminal criteria to the algorithm; + type: int, double; + default: 5000, 1e-4; + --------------------------------------------------- + Supported Color Space: + Supported list of RGB color spaces: + sRGB; + AdobeRGB; + WideGamutRGB; + ProPhotoRGB; + DCI_P3_RGB; + AppleRGB; + REC_709_RGB; + REC_2020_RGB; + Supported list of linear RGB color spaces: + sRGBL; + AdobeRGBL; + WideGamutRGBL; + ProPhotoRGBL; + DCI_P3_RGBL; + AppleRGBL; + REC_709_RGBL; + REC_2020_RGBL; + Supported list of non-RGB color spaces: + Lab_D50_2; + Lab_D65_2; + XYZ_D50_2; + XYZ_D65_2; + XYZ_D65_10; + XYZ_D50_10; + XYZ_A_2; + XYZ_A_10; + XYZ_D55_2; + XYZ_D55_10; + XYZ_D75_2; + XYZ_D75_10; + XYZ_E_2; + XYZ_E_10; + Lab_D65_10; + Lab_D50_10; + Lab_A_2; + Lab_A_10; + Lab_D55_2; + Lab_D55_10; + Lab_D75_2; + Lab_D75_10; + Lab_E_2; + Lab_E_10; ``` From 13b56f6a1b92d4708b32c539541f1f0589e7f909 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Mon, 28 Sep 2020 16:34:05 +0800 Subject: [PATCH 33/71] update doc for doxygen --- modules/mcc/include/opencv2/mcc/ccm.hpp | 69 +++++----- modules/mcc/include/opencv2/mcc/color.hpp | 56 ++++---- .../mcc/include/opencv2/mcc/colorspace.hpp | 126 +++++++++--------- modules/mcc/include/opencv2/mcc/distance.hpp | 56 ++++---- modules/mcc/include/opencv2/mcc/io.hpp | 5 +- modules/mcc/include/opencv2/mcc/linearize.hpp | 54 ++++---- .../mcc/include/opencv2/mcc/operations.hpp | 14 +- modules/mcc/include/opencv2/mcc/utils.hpp | 55 ++++---- modules/mcc/src/ccm.cpp | 6 +- 9 files changed, 221 insertions(+), 220 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 53ecd272d72..108455689ad 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -209,7 +209,7 @@ namespace ccm */ -/* *\ brief Enum of the possible types of ccm. +/** @brief Enum of the possible types of ccm. */ enum CCM_TYPE { @@ -217,7 +217,7 @@ enum CCM_TYPE CCM_4x3 }; -/* *\ brief Enum of the possible types of initial method. +/** @brief Enum of the possible types of initial method. */ enum INITIAL_METHOD_TYPE { @@ -226,8 +226,8 @@ enum INITIAL_METHOD_TYPE }; -/* *\ brief Core class of ccm model. - * produce a ColorCorrectionModel instance for inference. +/** @brief Core class of ccm model. + produce a ColorCorrectionModel instance for inference. */ class CV_EXPORTS_W ColorCorrectionModel @@ -276,58 +276,59 @@ class CV_EXPORTS_W ColorCorrectionModel INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); - /* *\ brief Make no change for CCM_3x3. - * convert cv::Mat A to [A, 1] in CCM_4x3. - *\ param inp the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat + /** @brief Make no change for CCM_3x3. + convert cv::Mat A to [A, 1] in CCM_4x3. + @param inp the input array, type of cv::Mat. + @return the output array, type of cv::Mat */ Mat prepare(const Mat& inp); - /* *\ brief Calculate weights and mask. - *\ param weights_list the input array, type of cv::Mat. - *\ param weights_coeff type of double. - *\ param saturate_list the input array, type of cv::Mat. + /** @brief Calculate weights and mask. + @param weights_list the input array, type of cv::Mat. + @param weights_coeff type of double. + @param saturate_mask the input array, type of cv::Mat. */ void calWeightsMasks(Mat weights_list, double weights_coeff, Mat saturate_mask); - /* *\ brief Fitting nonlinear - optimization initial value by white balance. - * see CCM.pdf for details. - *\ return the output array, type of Mat + /** @brief Fitting nonlinear - optimization initial value by white balance. + see CCM.pdf for details. + @return the output array, type of Mat */ Mat initialWhiteBalance(void); - /* *\ brief Fitting nonlinear-optimization initial value by least square. - * see CCM.pdf for details - *\ param fit if fit is True, return optimalization for rgbl distance function. + /** @brief Fitting nonlinear-optimization initial value by least square. + see CCM.pdf for details + @param fit if fit is True, return optimalization for rgbl distance function. */ void initialLeastSquare(bool fit = false); double calc_loss_(Color color); double calc_loss(const Mat ccm_); - /* *\ brief Fitting ccm if distance function is associated with CIE Lab color space. - * see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp - * Set terminal criteria for solver is possible. + /** @brief Fitting ccm if distance function is associated with CIE Lab color space. + see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp + Set terminal criteria for solver is possible. */ void fitting(void); - /* *\ brief Infer using fitting ccm. - *\ param img the input image, type of cv::Mat. - *\ return the output array, type of cv::Mat. + /** @brief Infer using fitting ccm. + @param img the input image, type of cv::Mat. + @param islinear default false. + @return the output array, type of cv::Mat. */ Mat infer(const Mat& img, bool islinear = false); - /* *\ brief Infer image and output as an BGR image with uint8 type. - * mainly for test or debug. - * input size and output size should be 255. - *\ param imgfile path name of image to infer. - *\ param islinear if linearize or not. - *\ return the output array, type of cv::Mat. + /** @brief Infer image and output as an BGR image with uint8 type. + mainly for test or debug. + input size and output size should be 255. + @param imgfile path name of image to infer. + @param islinear if linearize or not. + @return the output array, type of cv::Mat. */ Mat inferImage(std::string imgfile, bool islinear = false); - /* *\ brief Loss function base on cv::MinProblemSolver::Function. - * see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp + /** @brief Loss function base on cv::MinProblemSolver::Function. + see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp */ class LossFunction : public cv::MinProblemSolver::Function { @@ -335,14 +336,14 @@ class CV_EXPORTS_W ColorCorrectionModel ColorCorrectionModel* ccm_loss; LossFunction(ColorCorrectionModel* ccm) : ccm_loss(ccm) {}; - /* *\ brief Reset dims to ccm->shape. + /** @brief Reset dims to ccm->shape. */ int getDims() const CV_OVERRIDE { return ccm_loss->shape; } - /* *\ brief Reset calculation. + /** @brief Reset calculation. */ double calc(const double* x) const CV_OVERRIDE { diff --git a/modules/mcc/include/opencv2/mcc/color.hpp b/modules/mcc/include/opencv2/mcc/color.hpp index 6998af4eb5d..f9687294157 100644 --- a/modules/mcc/include/opencv2/mcc/color.hpp +++ b/modules/mcc/include/opencv2/mcc/color.hpp @@ -37,16 +37,16 @@ namespace cv namespace ccm { -/* *\ brief Color defined by color_values and color space +/** @brief Color defined by color_values and color space */ class CV_EXPORTS_W Color { public: - /* *\ param grays mask of grayscale color - *\ param colored mask of colored color - *\ param history storage of historical conversion + /** @param grays mask of grayscale color + @param colored mask of colored color + @param history storage of historical conversion */ Mat colors; const ColorSpace& cs; @@ -60,56 +60,56 @@ class CV_EXPORTS_W Color virtual ~Color() {}; - /* *\ brief Change to other color space. - * The conversion process incorporates linear transformations to speed up. - * method is chromatic adapation method. - * when save if True, get data from history first. - *\ param other type of ColorSpace. - *\ return Color. + /** @brief Change to other color space. + The conversion process incorporates linear transformations to speed up. + @param other type of ColorSpace. + @param method the chromatic adapation method. + @param save when save if True, get data from history first. + @return Color. */ Color to(COLOR_SPACE other, CAM method = BRADFORD, bool save = true); Color to(const ColorSpace& other, CAM method = BRADFORD, bool save = true); - /* *\ brief Channels split. - *\ return each channel. + /** @brief Channels split. + @return each channel. */ Mat channel(Mat m, int i); - /* *\ brief To Gray. + /** @brief To Gray. */ Mat toGray(IO io, CAM method = BRADFORD, bool save = true); - /* *\ brief To Luminant. + /** @brief To Luminant. */ Mat toLuminant(IO io, CAM method = BRADFORD, bool save = true); - /* *\ brief Diff without IO. - *\ param other type of Color. - *\ param method type of distance. - *\ return distance between self and other + /** @brief Diff without IO. + @param other type of Color. + @param method type of distance. + @return distance between self and other */ Mat diff(Color& other, DISTANCE_TYPE method = CIE2000); - /* *\ brief Diff with IO. - *\ param other type of Color. - *\ param io type of IO. - *\ param method type of distance. - *\ return distance between self and other + /** @brief Diff with IO. + @param other type of Color. + @param io type of IO. + @param method type of distance. + @return distance between self and other */ Mat diff(Color& other, IO io, DISTANCE_TYPE method = CIE2000); - /* *\ brief Calculate gray mask. + /** @brief Calculate gray mask. */ void getGray(double JDN = 2.0); - /* *\ brief Operator for mask copy. + /** @brief Operator for mask copy. */ Color operator[](Mat mask); }; -/* *\ brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls - * see Miscellaneous.md for details. +/** @brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls + see Miscellaneous.md for details. */ const Mat ColorChecker2005_LAB_D50_2 = (Mat_(24, 1) << cv::Vec3d(37.986, 13.555, 14.059), @@ -194,7 +194,7 @@ const Mat Vinyl_COLORED_MASK = (Mat_(18, 1) << 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); -/* *\ brief Macbeth and Vinyl ColorChecker with 2deg D50 . +/** @brief Macbeth and Vinyl ColorChecker with 2deg D50 . */ enum CONST_COLOR { Macbeth, diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp index f5078a91b23..6602d43995d 100644 --- a/modules/mcc/include/opencv2/mcc/colorspace.hpp +++ b/modules/mcc/include/opencv2/mcc/colorspace.hpp @@ -85,7 +85,7 @@ enum COLOR_SPACE { Lab_E_10 }; -/* *\ brief Basic class for ColorSpace. +/** @brief Basic class for ColorSpace. */ class CV_EXPORTS_W ColorSpace { @@ -115,9 +115,9 @@ class CV_EXPORTS_W ColorSpace }; -/* *\ brief Base of RGB color space; - * the argument values are from AdobeRGB; - * Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space +/** @brief Base of RGB color space; + the argument values are from AdobeRGB; + Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space */ class CV_EXPORTS_W RGBBase_ : public ColorSpace @@ -137,33 +137,33 @@ class CV_EXPORTS_W RGBBase_ : public ColorSpace using ColorSpace::ColorSpace; - /* *\ brief There are 3 kinds of relationships for RGB: - * 1. Different types; - no operation - * 1. Same type, same linear; - copy - * 2. Same type, different linear, self is nonlinear; - 2 toL - * 3. Same type, different linear, self is linear - 3 fromL - *\ param other type of ColorSpace. - *\ return Operations. + /** @brief There are 3 kinds of relationships for RGB: + 1. Different types; - no operation + 1. Same type, same linear; - copy + 2. Same type, different linear, self is nonlinear; - 2 toL + 3. Same type, different linear, self is linear - 3 fromL + @param other type of ColorSpace. + @return Operations. */ Operations relation(const ColorSpace& other) const CV_OVERRIDE; - /* *\ brief Initial operations. + /** @brief Initial operations. */ void init(); - /* *\ brief Produce color space instance with linear and non-linear versions. - *\ param rgbl type of RGBBase_. + /** @brief Produce color space instance with linear and non-linear versions. + @param rgbl type of RGBBase_. */ void bind(RGBBase_& rgbl); private: virtual void setParameter() {}; - /* *\ brief Calculation of M_RGBL2XYZ_base. - * see ColorSpace.pdf for details. + /** @brief Calculation of M_RGBL2XYZ_base. + see ColorSpace.pdf for details. */ virtual void calM(); - /* *\ brief operations to or from XYZ. + /** @brief operations to or from XYZ. */ virtual void calOperations(); @@ -176,7 +176,7 @@ class CV_EXPORTS_W RGBBase_ : public ColorSpace }; -/* *\ brief Base of Adobe RGB color space; +/** @brief Base of Adobe RGB color space; */ class CV_EXPORTS_W AdobeRGBBase_ : public RGBBase_ @@ -190,7 +190,7 @@ class CV_EXPORTS_W AdobeRGBBase_ : public RGBBase_ Mat fromLFunc(Mat& rgbl) CV_OVERRIDE; }; -/* *\ brief Base of sRGB color space; +/** @brief Base of sRGB color space; */ class CV_EXPORTS_W sRGBBase_ : public RGBBase_ @@ -205,36 +205,36 @@ class CV_EXPORTS_W sRGBBase_ : public RGBBase_ double K0; private: - /* *\ brief linearization parameters - * see ColorSpace.pdf for details; + /** @brief linearization parameters + see ColorSpace.pdf for details; */ virtual void calLinear() CV_OVERRIDE; - /* *\ brief Used by toLFunc. + /** @brief Used by toLFunc. */ double toLFuncEW(double& x); - /* *\ brief Linearization. - * see ColorSpace.pdf for details. - *\ param rgb the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat. + /** @brief Linearization. + see ColorSpace.pdf for details. + @param rgb the input array, type of cv::Mat. + @return the output array, type of cv::Mat. */ Mat toLFunc(Mat& rgb) CV_OVERRIDE; - /* *\ brief Used by fromLFunc. + /** @brief Used by fromLFunc. */ double fromLFuncEW(double& x); - /* *\ brief Delinearization. - * see ColorSpace.pdf for details. - *\ param rgbl the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat. + /** @brief Delinearization. + see ColorSpace.pdf for details. + @param rgbl the input array, type of cv::Mat. + @return the output array, type of cv::Mat. */ Mat fromLFunc(Mat& rgbl) CV_OVERRIDE; }; -/* *\ brief sRGB color space. - * data from https://en.wikipedia.org/wiki/SRGB. +/** @brief sRGB color space. + data from https://en.wikipedia.org/wiki/SRGB. */ class CV_EXPORTS_W sRGB_ :public sRGBBase_ @@ -246,7 +246,7 @@ class CV_EXPORTS_W sRGB_ :public sRGBBase_ void setParameter() CV_OVERRIDE; }; -/* *\ brief Adobe RGB color space. +/** @brief Adobe RGB color space. */ class CV_EXPORTS_W AdobeRGB_ : public AdobeRGBBase_ { @@ -258,8 +258,8 @@ class CV_EXPORTS_W AdobeRGB_ : public AdobeRGBBase_ }; -/* *\ brief Wide-gamut RGB color space. - * data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. +/** @brief Wide-gamut RGB color space. + data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. */ class CV_EXPORTS_W WideGamutRGB_ : public AdobeRGBBase_ { @@ -270,8 +270,8 @@ class CV_EXPORTS_W WideGamutRGB_ : public AdobeRGBBase_ void setParameter() CV_OVERRIDE; }; -/* *\ brief ProPhoto RGB color space. - * data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. +/** @brief ProPhoto RGB color space. + data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. */ class CV_EXPORTS_W ProPhotoRGB_ : public AdobeRGBBase_ @@ -283,8 +283,8 @@ class CV_EXPORTS_W ProPhotoRGB_ : public AdobeRGBBase_ void setParameter() CV_OVERRIDE; }; -/* *\ brief DCI-P3 RGB color space. - * data from https://en.wikipedia.org/wiki/DCI-P3. +/** @brief DCI-P3 RGB color space. + data from https://en.wikipedia.org/wiki/DCI-P3. */ class CV_EXPORTS_W DCI_P3_RGB_ : public AdobeRGBBase_ { @@ -295,8 +295,8 @@ class CV_EXPORTS_W DCI_P3_RGB_ : public AdobeRGBBase_ void setParameter() CV_OVERRIDE; }; -/* *\ brief Apple RGB color space. - * data from http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. +/** @brief Apple RGB color space. + data from http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. */ class CV_EXPORTS_W AppleRGB_ : public AdobeRGBBase_ { @@ -307,8 +307,8 @@ class CV_EXPORTS_W AppleRGB_ : public AdobeRGBBase_ void setParameter() CV_OVERRIDE; }; -/* *\ brief REC_709 RGB color space. - * data from https://en.wikipedia.org/wiki/Rec._709. +/** @brief REC_709 RGB color space. + data from https://en.wikipedia.org/wiki/Rec._709. */ class CV_EXPORTS_W REC_709_RGB_ : public sRGBBase_ { @@ -319,8 +319,8 @@ class CV_EXPORTS_W REC_709_RGB_ : public sRGBBase_ void setParameter() CV_OVERRIDE; }; -/* *\ brief REC_2020 RGB color space. - * data from https://en.wikipedia.org/wiki/Rec._2020. +/** @brief REC_2020 RGB color space. + data from https://en.wikipedia.org/wiki/Rec._2020. */ class CV_EXPORTS_W REC_2020_RGB_ : public sRGBBase_ { @@ -332,7 +332,7 @@ class CV_EXPORTS_W REC_2020_RGB_ : public sRGBBase_ }; -/* *\ brief Enum of the possible types of CAMs. +/** @brief Enum of the possible types of CAMs. */ enum CAM { @@ -350,8 +350,8 @@ const static std::map > MAs = { {BRADFORD, { Bradford ,Bradford.inv() }} }; -/* *\ brief XYZ color space. - * Chromatic adaption matrices. +/** @brief XYZ color space. + Chromatic adaption matrices. */ class CV_EXPORTS_W XYZ :public ColorSpace { @@ -362,21 +362,21 @@ class CV_EXPORTS_W XYZ :public ColorSpace static std::shared_ptr get(IO io); private: - /* *\ brief Get cam. - *\ param sio the input IO of src. - *\ param dio the input IO of dst. - *\ param method type of CAM. - *\ return the output array, type of cv::Mat. + /** @brief Get cam. + @param sio the input IO of src. + @param dio the input IO of dst. + @param method type of CAM. + @return the output array, type of cv::Mat. */ Mat cam_(IO sio, IO dio, CAM method = BRADFORD) const; }; -/* *\ brief Define XYZ_D65_2 and XYZ_D50_2. +/** @brief Define XYZ_D65_2 and XYZ_D50_2. */ const XYZ XYZ_D65_2_CS(D65_2); const XYZ XYZ_D50_2_CS(D50_2); -/* *\ brief Lab color space. +/** @brief Lab color space. */ class CV_EXPORTS_W Lab :public ColorSpace { @@ -394,22 +394,22 @@ class CV_EXPORTS_W Lab :public ColorSpace cv::Vec3d fromxyz(cv::Vec3d& xyz); - /* *\ brief Calculate From. - *\ param src the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat + /** @brief Calculate From. + @param src the input array, type of cv::Mat. + @return the output array, type of cv::Mat */ Mat fromsrc(Mat& src); cv::Vec3d tolab(cv::Vec3d& lab); - /* *\ brief Calculate To. - *\ param src the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat + /** @brief Calculate To. + @param src the input array, type of cv::Mat. + @return the output array, type of cv::Mat */ Mat tosrc(Mat& src); }; -/* *\ brief Define Lab_D65_2 and Lab_D50_2. +/** @brief Define Lab_D65_2 and Lab_D50_2. */ const Lab Lab_D65_2_CS(D65_2); const Lab Lab_D50_2_CS(D50_2); diff --git a/modules/mcc/include/opencv2/mcc/distance.hpp b/modules/mcc/include/opencv2/mcc/distance.hpp index 278c97dc29c..dc0b37680ec 100644 --- a/modules/mcc/include/opencv2/mcc/distance.hpp +++ b/modules/mcc/include/opencv2/mcc/distance.hpp @@ -35,8 +35,8 @@ namespace cv namespace ccm { -/* *\brief Enum of possibale functions to calculate the distance between - * colors.see https://en.wikipedia.org/wiki/Color_difference for details;*/ +/** @brief Enum of possibale functions to calculate the distance between + colors.see https://en.wikipedia.org/wiki/Color_difference for details;*/ enum DISTANCE_TYPE { CIE76, @@ -50,23 +50,23 @@ enum DISTANCE_TYPE }; -/* *\ brief distance between two points in formula CIE76 - *\ param lab1 a 3D vector - *\ param lab2 a 3D vector - *\ return distance between lab1 and lab2 +/** @brief distance between two points in formula CIE76 + @param lab1 a 3D vector + @param lab2 a 3D vector + @return distance between lab1 and lab2 */ double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2); -/* *\ brief distance between two points in formula CIE94 - *\ param lab1 a 3D vector - *\ param lab2 a 3D vector - *\ param kH Hue scale - *\ param kC Chroma scale - *\ param kL Lightness scale - *\ param k1 first scale parameter - *\ param k2 second scale parameter - *\ return distance between lab1 and lab2 +/** @brief distance between two points in formula CIE94 + @param lab1 a 3D vector + @param lab2 a 3D vector + @param kH Hue scale + @param kC Chroma scale + @param kL Lightness scale + @param k1 first scale parameter + @param k2 second scale parameter + @return distance between lab1 and lab2 */ double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH = 1.0, @@ -80,25 +80,25 @@ double toRad(double degree); double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2); -/* *\ brief distance between two points in formula CIE2000 - *\ param lab1 a 3D vector - *\ param lab2 a 3D vector - *\ param kL Lightness scale - *\ param kC Chroma scale - *\ param kH Hue scale - *\ return distance between lab1 and lab2 +/** @brief distance between two points in formula CIE2000 + @param lab1 a 3D vector + @param lab2 a 3D vector + @param kL Lightness scale + @param kC Chroma scale + @param kH Hue scale + @return distance between lab1 and lab2 */ double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1.0, double kC = 1.0, double kH = 1.0); double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2); -/* *\ brief distance between two points in formula CMC - *\ param lab1 a 3D vector - *\ param lab2 a 3D vector - *\ param kL Lightness scale - *\ param kC Chroma scale - *\ return distance between lab1 and lab2 +/** @brief distance between two points in formula CMC + @param lab1 a 3D vector + @param lab2 a 3D vector + @param kL Lightness scale + @param kC Chroma scale + @return distance between lab1 and lab2 */ double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1, double kC = 1); diff --git a/modules/mcc/include/opencv2/mcc/io.hpp b/modules/mcc/include/opencv2/mcc/io.hpp index 311d0e17235..0b44a8561a2 100644 --- a/modules/mcc/include/opencv2/mcc/io.hpp +++ b/modules/mcc/include/opencv2/mcc/io.hpp @@ -39,9 +39,8 @@ namespace cv namespace ccm { -/* *\ brief Io is the meaning of illuminant and observer. See notes of ccm.hpp - - * for supported list for illuminant and observer*/ +/** @brief Io is the meaning of illuminant and observer. See notes of ccm.hpp + for supported list for illuminant and observer*/ class CV_EXPORTS_W IO { public: diff --git a/modules/mcc/include/opencv2/mcc/linearize.hpp b/modules/mcc/include/opencv2/mcc/linearize.hpp index 1712d9d8897..9604d5701b1 100644 --- a/modules/mcc/include/opencv2/mcc/linearize.hpp +++ b/modules/mcc/include/opencv2/mcc/linearize.hpp @@ -36,7 +36,7 @@ namespace cv namespace ccm { -/* *\ brief Enum of the possible types of linearization. +/** @brief Enum of the possible types of linearization. */ enum LINEAR_TYPE { @@ -48,7 +48,7 @@ enum LINEAR_TYPE GRAYLOGPOLYFIT }; -/* *\ brief Polyfit model. +/** @brief Polyfit model. */ class CV_EXPORTS_W Polyfit { @@ -57,7 +57,7 @@ class CV_EXPORTS_W Polyfit Mat p; Polyfit() {}; - /* *\ brief Polyfit method. + /** @brief Polyfit method. https://en.wikipedia.org/wiki/Polynomial_regression polynomial: yi = a0 + a1*xi + a2*xi^2 + ... + an*xi^deg (i = 1,2,...,n) and deduct: Ax = y @@ -75,7 +75,7 @@ class CV_EXPORTS_W Polyfit }; -/* *\ brief Logpolyfit model. +/** @brief Logpolyfit model. */ class CV_EXPORTS_W LogPolyfit @@ -87,7 +87,7 @@ class CV_EXPORTS_W LogPolyfit LogPolyfit() {}; - /* *\ brief Logpolyfit method. + /** @brief Logpolyfit method. */ LogPolyfit(Mat x, Mat y, int deg_); @@ -98,7 +98,7 @@ class CV_EXPORTS_W LogPolyfit }; -/* *\ brief Linearization base. +/** @brief Linearization base. */ class CV_EXPORTS_W Linear @@ -108,8 +108,8 @@ class CV_EXPORTS_W Linear virtual ~Linear() {}; - /* *\ brief Inference. - *\ param inp the input array, type of cv::Mat. + /** @brief Inference. + @param inp the input array, type of cv::Mat. */ virtual Mat linearize(Mat inp); @@ -121,12 +121,12 @@ class CV_EXPORTS_W Linear }; -/* *\ brief Linearization identity. - * make no change. +/** @brief Linearization identity. + make no change. */ class CV_EXPORTS_W LinearIdentity : public Linear {}; -/* *\ brief Linearization gamma correction. +/** @brief Linearization gamma correction. */ class CV_EXPORTS_W LinearGamma : public Linear { @@ -138,8 +138,8 @@ class CV_EXPORTS_W LinearGamma : public Linear Mat linearize(Mat inp) CV_OVERRIDE; }; -/* *\ brief Linearization. - * Grayscale polynomial fitting. +/** @brief Linearization. + Grayscale polynomial fitting. */ template class LinearGray :public Linear @@ -158,9 +158,9 @@ class LinearGray :public Linear calc(src, dst_); } - /* *\ brief monotonically increase is not guaranteed. - *\ param src the input array, type of cv::Mat. - *\ param dst the input array, type of cv::Mat. + /** @brief monotonically increase is not guaranteed. + @param src the input array, type of cv::Mat. + @param dst the input array, type of cv::Mat. */ void calc(const Mat& src, const Mat& dst) { @@ -173,8 +173,8 @@ class LinearGray :public Linear }; }; -/* *\ brief Linearization. - * Fitting channels respectively. +/** @brief Linearization. + Fitting channels respectively. */ template class LinearColor :public Linear @@ -214,15 +214,15 @@ class LinearColor :public Linear }; }; -/* *\ brief Get linearization method. - * used in ccm model. - *\ param gamma used in LinearGamma. - *\ param deg degrees. - *\ param src the input array, type of cv::Mat. - *\ param dst the input array, type of cv::Mat. - *\ param mask the input array, type of cv::Mat. - *\ param cs type of RGBBase_. - *\ param linear_type type of linear. +/** @brief Get linearization method. + used in ccm model. + @param gamma used in LinearGamma. + @param deg degrees. + @param src the input array, type of cv::Mat. + @param dst the input array, type of cv::Mat. + @param mask the input array, type of cv::Mat. + @param cs type of RGBBase_. + @param linear_type type of linear. */ std::shared_ptr getLinear(double gamma, int deg, Mat src, Color dst, Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type); diff --git a/modules/mcc/include/opencv2/mcc/operations.hpp b/modules/mcc/include/opencv2/mcc/operations.hpp index 2412e567f7a..05749c56242 100644 --- a/modules/mcc/include/opencv2/mcc/operations.hpp +++ b/modules/mcc/include/opencv2/mcc/operations.hpp @@ -40,8 +40,8 @@ namespace ccm typedef std::function MatFunc; -/* *\ brief Operation class contains some operarions used for color space - * conversion containing linear transformation and non-linear transformation +/** @brief Operation class contains some operarions used for color space + conversion containing linear transformation and non-linear transformation */ class CV_EXPORTS_W Operation { @@ -57,12 +57,12 @@ class CV_EXPORTS_W Operation Operation(MatFunc f_) : linear(false), f(f_) {}; virtual ~Operation() {}; - /* *\ brief operator function will run operation + /** @brief operator function will run operation */ Mat operator()(Mat& abc); - /* *\ brief add function will conbine this operation - * with other linear transformation operation + /** @brief add function will conbine this operation + with other linear transformation operation */ void add(const Operation& other); @@ -82,11 +82,11 @@ class CV_EXPORTS_W Operations virtual ~Operations() {}; - /* *\ brief add function will conbine this operation with other transformation operations + /** @brief add function will conbine this operation with other transformation operations */ Operations& add(const Operations& other); - /* *\ brief run operations to make color conversion + /** @brief run operations to make color conversion */ Mat run(Mat abc); }; diff --git a/modules/mcc/include/opencv2/mcc/utils.hpp b/modules/mcc/include/opencv2/mcc/utils.hpp index 4579ee40e76..55e13a2723f 100644 --- a/modules/mcc/include/opencv2/mcc/utils.hpp +++ b/modules/mcc/include/opencv2/mcc/utils.hpp @@ -33,43 +33,44 @@ namespace cv { namespace ccm { -/* *\ brief gamma correction ,see ColorSpace.pdf for details. - *\ param src the input array,type of Mat. - *\ param gamma a constant for gamma correction. - */ CV_EXPORTS_W double gammaCorrection_(const double& element, const double& gamma); +/** @brief gamma correction ,see ColorSpace.pdf for details. + @param src the input array,type of Mat. + @param gamma a constant for gamma correction. + */ CV_EXPORTS_W Mat gammaCorrection(const Mat& src, const double& gamma); -/* *\ brief maskCopyTo a function to delete unsatisfied elementwise. - *\ param src the input array, type of Mat. - *\ param mask operation mask that used to choose satisfided elementwise. +/** @brief maskCopyTo a function to delete unsatisfied elementwise. + @param src the input array, type of Mat. + @param mask operation mask that used to choose satisfided elementwise. */ CV_EXPORTS_W Mat maskCopyTo(const Mat& src, const Mat& mask); -/* *\ brief multiple the function used to compute an array with n channels - *mulipied by ccm. \ param src the input array, type of Mat. \ param ccm the - *ccm matrix to make color correction. +/** @brief multiple the function used to compute an array with n channels + mulipied by ccm. + @param xyz the input array, type of Mat. + @param ccm the ccm matrix to make color correction. */ CV_EXPORTS_W Mat multiple(const Mat& xyz, const Mat& ccm); -/* *\ brief multiple the function used to get the mask of saturated colors, +/** @brief multiple the function used to get the mask of saturated colors, colors between low and up will be choosed. - *\ param src the input array, type of Mat. - *\ param low the threshold to choose saturated colors - *\ param up the threshold to choose saturated colors + @param src the input array, type of Mat. + @param low the threshold to choose saturated colors + @param up the threshold to choose saturated colors */ CV_EXPORTS_W Mat saturate(Mat& src, const double& low, const double& up); -/* *\ brief rgb2gray it is an approximation grayscale function for relative RGB - *color space, see Miscellaneous.pdf for details; \ param rgb the input array, - *type of Mat. +/** @brief rgb2gray it is an approximation grayscale function for relative RGB + color space, see Miscellaneous.pdf for details; + @param rgb the input array,type of Mat. */ CV_EXPORTS_W Mat rgb2gray(Mat rgb); -/* *\ brief function for elementWise operation - *\ param src the input array, type of Mat - *\ lambda a for operation +/** @brief function for elementWise operation + @param src the input array, type of Mat + @param lambda a for operation */ template Mat elementWise(const Mat& src, F&& lambda) @@ -107,9 +108,9 @@ Mat elementWise(const Mat& src, F&& lambda) return dst; } -/* *\ brief function for channel operation - *\ param src the input array, type of Mat - *\ lambda the function for operation +/** @brief function for channel operation + @param src the input array, type of Mat + @param lambda the function for operation */ template Mat channelWise(const Mat& src, F&& lambda) @@ -123,10 +124,10 @@ Mat channelWise(const Mat& src, F&& lambda) return dst; } -/* *\ brief function for distance operation. - *\ param src the input array, type of Mat. - *\ param ref another input array, type of Mat. - *\ param lambda the computing method for distance . +/** @brief function for distance operation. + @param src the input array, type of Mat. + @param ref another input array, type of Mat. + @param lambda the computing method for distance . */ template Mat distanceWise(Mat& src, Mat& ref, F&& lambda) diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index c6b11d64971..2d5f840273e 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -31,18 +31,18 @@ namespace cv { namespace ccm { - ColorCorrectionModel::ColorCorrectionModel(Mat src_, CONST_COLOR constcolor, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, +ColorCorrectionModel::ColorCorrectionModel(Mat src_, CONST_COLOR constcolor, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : ColorCorrectionModel(src_, GetColor::get_color(constcolor), *GetCS::get_rgb(cs_), ccm_type_, distance_, linear_type, gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} - ColorCorrectionModel::ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE ref_cs_, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, +ColorCorrectionModel::ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE ref_cs_, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : ColorCorrectionModel(src_, Color(colors_, *GetCS::get_cs(ref_cs_)), *GetCS::get_rgb(cs_), ccm_type_, distance_, linear_type, gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} - ColorCorrectionModel::ColorCorrectionModel(Mat src_, Color dst_, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, +ColorCorrectionModel::ColorCorrectionModel(Mat src_, Color dst_, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : ColorCorrectionModel(src_, dst_, *GetCS::get_rgb(cs_), ccm_type_, distance_, linear_type, From 8be1d19456a7618b058b31bae6448b583a982ef5 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Tue, 29 Sep 2020 16:14:54 +0800 Subject: [PATCH 34/71] update doc&DigitalSG --- modules/mcc/include/opencv2/mcc/ccm.hpp | 16 +- modules/mcc/include/opencv2/mcc/color.hpp | 285 +++++++++++++----- .../mcc/samples/color_correction_model.cpp | 36 +-- modules/mcc/src/ccm.cpp | 6 +- modules/mcc/src/color.cpp | 5 + .../basic_ccm/color_correction_model.markdown | 14 +- 6 files changed, 262 insertions(+), 100 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 108455689ad..bb05d7f4eac 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -50,8 +50,9 @@ namespace ccm constcolor : the Built-in color card; Supported list: - Macbeth: Macbeth ColorChecker with 2deg D50; - Vinyl: DKK ColorChecker with 2deg D50; + Macbeth: Macbeth ColorChecker with 24 squares; + Vinyl: DKK ColorChecker with 12 squares and 6 rectangle; + DigitalSG: DigitalSG ColorChecker with 140 squares; type: enum CONST_COLOR; Mat colors_ : the reference color values @@ -63,11 +64,18 @@ namespace ccm NOTICE: For the list of color spaces supported, see the notes below; If the color type is some RGB, the format is RGB not BGR; type:enum COLOR_SPACE; - colorspace : + cs_ : the absolute color space that detected colors convert to; NOTICE: it should be some RGB color space; For the list of RGB color spaces supported, see the notes below; type: enum COLOR_SPACE; + dst_ : + the reference colors; + NOTICE: custom color card are supported; + You should generate Color instance using reference color values and corresponding color space + For the list of color spaces supported, see the notes below; + If the color type is some RGB, the format is RGB not BGR, and the color values are in [0, 1]; + ccm_type : the shape of color correction matrix(CCM); Supported list: @@ -294,7 +302,7 @@ class CV_EXPORTS_W ColorCorrectionModel see CCM.pdf for details. @return the output array, type of Mat */ - Mat initialWhiteBalance(void); + void initialWhiteBalance(void); /** @brief Fitting nonlinear-optimization initial value by least square. see CCM.pdf for details diff --git a/modules/mcc/include/opencv2/mcc/color.hpp b/modules/mcc/include/opencv2/mcc/color.hpp index f9687294157..7e5f4e8a678 100644 --- a/modules/mcc/include/opencv2/mcc/color.hpp +++ b/modules/mcc/include/opencv2/mcc/color.hpp @@ -111,57 +111,57 @@ class CV_EXPORTS_W Color /** @brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls see Miscellaneous.md for details. */ -const Mat ColorChecker2005_LAB_D50_2 = (Mat_(24, 1) << - cv::Vec3d(37.986, 13.555, 14.059), - cv::Vec3d(65.711, 18.13, 17.81), - cv::Vec3d(49.927, -4.88, -21.925), - cv::Vec3d(43.139, -13.095, 21.905), - cv::Vec3d(55.112, 8.844, -25.399), - cv::Vec3d(70.719, -33.397, -0.199), - cv::Vec3d(62.661, 36.067, 57.096), - cv::Vec3d(40.02, 10.41, -45.964), - cv::Vec3d(51.124, 48.239, 16.248), - cv::Vec3d(30.325, 22.976, -21.587), - cv::Vec3d(72.532, -23.709, 57.255), - cv::Vec3d(71.941, 19.363, 67.857), - cv::Vec3d(28.778, 14.179, -50.297), - cv::Vec3d(55.261, -38.342, 31.37), - cv::Vec3d(42.101, 53.378, 28.19), - cv::Vec3d(81.733, 4.039, 79.819), - cv::Vec3d(51.935, 49.986, -14.574), - cv::Vec3d(51.038, -28.631, -28.638), - cv::Vec3d(96.539, -0.425, 1.186), - cv::Vec3d(81.257, -0.638, -0.335), - cv::Vec3d(66.766, -0.734, -0.504), - cv::Vec3d(50.867, -0.153, -0.27), - cv::Vec3d(35.656, -0.421, -1.231), - cv::Vec3d(20.461, -0.079, -0.973)); - -const Mat ColorChecker2005_LAB_D65_2 = (Mat_(24, 1) << - cv::Vec3d(37.542, 12.018, 13.33), - cv::Vec3d(65.2, 14.821, 17.545), - cv::Vec3d(50.366, -1.573, -21.431), - cv::Vec3d(43.125, -14.63, 22.12), - cv::Vec3d(55.343, 11.449, -25.289), - cv::Vec3d(71.36, -32.718, 1.636), - cv::Vec3d(61.365, 32.885, 55.155), - cv::Vec3d(40.712, 16.908, -45.085), - cv::Vec3d(49.86, 45.934, 13.876), - cv::Vec3d(30.15, 24.915, -22.606), - cv::Vec3d(72.438, -27.464, 58.469), - cv::Vec3d(70.916, 15.583, 66.543), - cv::Vec3d(29.624, 21.425, -49.031), - cv::Vec3d(55.643, -40.76, 33.274), - cv::Vec3d(40.554, 49.972, 25.46), - cv::Vec3d(80.982, -1.037, 80.03), - cv::Vec3d(51.006, 49.876, -16.93), - cv::Vec3d(52.121, -24.61, -26.176), - cv::Vec3d(96.536, -0.694, 1.354), - cv::Vec3d(81.274, -0.61, -0.24), - cv::Vec3d(66.787, -0.647, -0.429), - cv::Vec3d(50.872, -0.059, -0.247), - cv::Vec3d(35.68, -0.22, -1.205), - cv::Vec3d(20.475, 0.049, -0.972)); +const Mat ColorChecker2005_LAB_D50_2 = (Mat_(24, 1) << + Vec3d(37.986, 13.555, 14.059), + Vec3d(65.711, 18.13, 17.81), + Vec3d(49.927, -4.88, -21.925), + Vec3d(43.139, -13.095, 21.905), + Vec3d(55.112, 8.844, -25.399), + Vec3d(70.719, -33.397, -0.199), + Vec3d(62.661, 36.067, 57.096), + Vec3d(40.02, 10.41, -45.964), + Vec3d(51.124, 48.239, 16.248), + Vec3d(30.325, 22.976, -21.587), + Vec3d(72.532, -23.709, 57.255), + Vec3d(71.941, 19.363, 67.857), + Vec3d(28.778, 14.179, -50.297), + Vec3d(55.261, -38.342, 31.37), + Vec3d(42.101, 53.378, 28.19), + Vec3d(81.733, 4.039, 79.819), + Vec3d(51.935, 49.986, -14.574), + Vec3d(51.038, -28.631, -28.638), + Vec3d(96.539, -0.425, 1.186), + Vec3d(81.257, -0.638, -0.335), + Vec3d(66.766, -0.734, -0.504), + Vec3d(50.867, -0.153, -0.27), + Vec3d(35.656, -0.421, -1.231), + Vec3d(20.461, -0.079, -0.973)); + +const Mat ColorChecker2005_LAB_D65_2 = (Mat_(24, 1) << + Vec3d(37.542, 12.018, 13.33), + Vec3d(65.2, 14.821, 17.545), + Vec3d(50.366, -1.573, -21.431), + Vec3d(43.125, -14.63, 22.12), + Vec3d(55.343, 11.449, -25.289), + Vec3d(71.36, -32.718, 1.636), + Vec3d(61.365, 32.885, 55.155), + Vec3d(40.712, 16.908, -45.085), + Vec3d(49.86, 45.934, 13.876), + Vec3d(30.15, 24.915, -22.606), + Vec3d(72.438, -27.464, 58.469), + Vec3d(70.916, 15.583, 66.543), + Vec3d(29.624, 21.425, -49.031), + Vec3d(55.643, -40.76, 33.274), + Vec3d(40.554, 49.972, 25.46), + Vec3d(80.982, -1.037, 80.03), + Vec3d(51.006, 49.876, -16.93), + Vec3d(52.121, -24.61, -26.176), + Vec3d(96.536, -0.694, 1.354), + Vec3d(81.274, -0.61, -0.24), + Vec3d(66.787, -0.647, -0.429), + Vec3d(50.872, -0.059, -0.247), + Vec3d(35.68, -0.22, -1.205), + Vec3d(20.475, 0.049, -0.972)); const Mat ColorChecker2005_COLORED_MASK = (Mat_(24, 1) << 1, 1, 1, 1, 1, 1, @@ -169,36 +169,177 @@ const Mat ColorChecker2005_COLORED_MASK = (Mat_(24, 1) << 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0); -const Mat Vinyl_LAB_D50_2 = (Mat_(18, 1) << - Vec3d(1.00000000e+02, 5.20000001e-03, -1.04000000e-02), - Vec3d(7.30833969e+01, -8.19999993e-01, -2.02099991e+00), - Vec3d(6.24930000e+01, 4.25999999e-01, -2.23099995e+00), - Vec3d(5.04640007e+01, 4.46999997e-01, -2.32399988e+00), - Vec3d(3.77970009e+01, 3.59999985e-02, -1.29700005e+00), - Vec3d(0.00000000e+00, 0.00000000e+00, 0.00000000e+00), - Vec3d(5.15880013e+01, 7.35179977e+01, 5.15690002e+01), - Vec3d(9.36989975e+01, -1.57340002e+01, 9.19420013e+01), - Vec3d(6.94079971e+01, -4.65940018e+01, 5.04869995e+01), - Vec3d(6.66100006e+01, -1.36789999e+01, -4.31720009e+01), - Vec3d(1.17110004e+01, 1.69799995e+01, -3.71759987e+01), - Vec3d(5.19739990e+01, 8.19440002e+01, -8.40699959e+00), - Vec3d(4.05489998e+01, 5.04399986e+01, 2.48490009e+01), - Vec3d(6.08160019e+01, 2.60690002e+01, 4.94420013e+01), - Vec3d(5.22529984e+01, -1.99500008e+01, -2.39960003e+01), - Vec3d(5.12859993e+01, 4.84700012e+01, -1.50579996e+01), - Vec3d(6.87070007e+01, 1.22959995e+01, 1.62129993e+01), - Vec3d(6.36839981e+01, 1.02930002e+01, 1.67639999e+01)); +const Mat Vinyl_LAB_D50_2 = (Mat_(18, 1) << + Vec3d(100, 0.00520000001, -0.0104), + Vec3d(73.0833969, -0.819999993, -2.02099991), + Vec3d(62.493, 0.425999999, -2.23099995), + Vec3d(50.4640007, 0.446999997, -2.32399988), + Vec3d(37.7970009, 0.0359999985, -1.29700005), + Vec3d(0, 0, 0), + Vec3d(51.5880013, 73.5179977, 51.5690002), + Vec3d(93.6989975, -15.7340002, 91.9420013), + Vec3d(69.4079971, -46.5940018, 50.4869995), + Vec3d(66.61000060000001, -13.6789999, -43.1720009), + Vec3d(11.7110004, 16.9799995, -37.1759987), + Vec3d(51.973999, 81.9440002, -8.40699959), + Vec3d(40.5489998, 50.4399986, 24.8490009), + Vec3d(60.8160019, 26.0690002, 49.4420013), + Vec3d(52.2529984, -19.9500008, -23.9960003), + Vec3d(51.2859993, 48.4700012, -15.0579996), + Vec3d(68.70700069999999, 12.2959995, 16.2129993), + Vec3d(63.6839981, 10.2930002, 16.7639999)); const Mat Vinyl_COLORED_MASK = (Mat_(18, 1) << 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - +const Mat DigitalSG_LAB_D50_2 = (Mat_(140, 1) << + Vec3d(96.55,-0.91,0.57), + Vec3d(6.43,-0.06,-0.41), + Vec3d(49.7,-0.18,0.03), + Vec3d(96.5,-0.89,0.59), + Vec3d(6.5,-0.06,-0.44), + Vec3d(49.66,-0.2,0.01), + Vec3d(96.52,-0.91,0.58), + Vec3d(6.49,-0.02,-0.28), + Vec3d(49.72,-0.2,0.04), + Vec3d(96.43,-0.91,0.67), + Vec3d(49.72,-0.19,0), + Vec3d(32.6,51.58,-10.85), + Vec3d(60.75,26.22,-18.6), + Vec3d(28.69,48.28,-39), + Vec3d(49.38,-15.43,-48.48), + Vec3d(60.63,-30.77,-26.23), + Vec3d(19.29,-26.37,-6.15), + Vec3d(60.15,-41.77,-12.6), + Vec3d(21.42,1.67,8.79), + Vec3d(49.69,-0.2,0.01), + Vec3d(6.5,-0.03,-0.67), + Vec3d(21.82,17.33,-18.35), + Vec3d(41.53,18.48,-37.26), + Vec3d(19.99,-0.16,-36.29), + Vec3d(60.16,-18.45,-31.42), + Vec3d(19.94,-17.92,-20.96), + Vec3d(60.68,-6.05,-32.81), + Vec3d(50.81,-49.8,-9.63), + Vec3d(60.65,-39.77,20.76), + Vec3d(6.53,-0.03,-0.43), + Vec3d(96.56,-0.91,0.59), + Vec3d(84.19,-1.95,-8.23), + Vec3d(84.75,14.55,0.23), + Vec3d(84.87,-19.07,-0.82), + Vec3d(85.15,13.48,6.82), + Vec3d(84.17,-10.45,26.78), + Vec3d(61.74,31.06,36.42), + Vec3d(64.37,20.82,18.92), + Vec3d(50.4,-53.22,14.62), + Vec3d(96.51,-0.89,0.65), + Vec3d(49.74,-0.19,0.03), + Vec3d(31.91,18.62,21.99), + Vec3d(60.74,38.66,70.97), + Vec3d(19.35,22.23,-58.86), + Vec3d(96.52,-0.91,0.62), + Vec3d(6.66,0,-0.3), + Vec3d(76.51,20.81,22.72), + Vec3d(72.79,29.15,24.18), + Vec3d(22.33,-20.7,5.75), + Vec3d(49.7,-0.19,0.01), + Vec3d(6.53,-0.05,-0.61), + Vec3d(63.42,20.19,19.22), + Vec3d(34.94,11.64,-50.7), + Vec3d(52.03,-44.15,39.04), + Vec3d(79.43,0.29,-0.17), + Vec3d(30.67,-0.14,-0.53), + Vec3d(63.6,14.44,26.07), + Vec3d(64.37,14.5,17.05), + Vec3d(60.01,-44.33,8.49), + Vec3d(6.63,-0.01,-0.47), + Vec3d(96.56,-0.93,0.59), + Vec3d(46.37,-5.09,-24.46), + Vec3d(47.08,52.97,20.49), + Vec3d(36.04,64.92,38.51), + Vec3d(65.05,0,-0.32), + Vec3d(40.14,-0.19,-0.38), + Vec3d(43.77,16.46,27.12), + Vec3d(64.39,17,16.59), + Vec3d(60.79,-29.74,41.5), + Vec3d(96.48,-0.89,0.64), + Vec3d(49.75,-0.21,0.01), + Vec3d(38.18,-16.99,30.87), + Vec3d(21.31,29.14,-27.51), + Vec3d(80.57,3.85,89.61), + Vec3d(49.71,-0.2,0.03), + Vec3d(60.27,0.08,-0.41), + Vec3d(67.34,14.45,16.9), + Vec3d(64.69,16.95,18.57), + Vec3d(51.12,-49.31,44.41), + Vec3d(49.7,-0.2,0.02), + Vec3d(6.67,-0.05,-0.64), + Vec3d(51.56,9.16,-26.88), + Vec3d(70.83,-24.26,64.77), + Vec3d(48.06,55.33,-15.61), + Vec3d(35.26,-0.09,-0.24), + Vec3d(75.16,0.25,-0.2), + Vec3d(44.54,26.27,38.93), + Vec3d(35.91,16.59,26.46), + Vec3d(61.49,-52.73,47.3), + Vec3d(6.59,-0.05,-0.5), + Vec3d(96.58,-0.9,0.61), + Vec3d(68.93,-34.58,-0.34), + Vec3d(69.65,20.09,78.57), + Vec3d(47.79,-33.18,-30.21), + Vec3d(15.94,-0.42,-1.2), + Vec3d(89.02,-0.36,-0.48), + Vec3d(63.43,25.44,26.25), + Vec3d(65.75,22.06,27.82), + Vec3d(61.47,17.1,50.72), + Vec3d(96.53,-0.89,0.66), + Vec3d(49.79,-0.2,0.03), + Vec3d(85.17,10.89,17.26), + Vec3d(89.74,-16.52,6.19), + Vec3d(84.55,5.07,-6.12), + Vec3d(84.02,-13.87,-8.72), + Vec3d(70.76,0.07,-0.35), + Vec3d(45.59,-0.05,0.23), + Vec3d(20.3,0.07,-0.32), + Vec3d(61.79,-13.41,55.42), + Vec3d(49.72,-0.19,0.02), + Vec3d(6.77,-0.05,-0.44), + Vec3d(21.85,34.37,7.83), + Vec3d(42.66,67.43,48.42), + Vec3d(60.33,36.56,3.56), + Vec3d(61.22,36.61,17.32), + Vec3d(62.07,52.8,77.14), + Vec3d(72.42,-9.82,89.66), + Vec3d(62.03,3.53,57.01), + Vec3d(71.95,-27.34,73.69), + Vec3d(6.59,-0.04,-0.45), + Vec3d(49.77,-0.19,0.04), + Vec3d(41.84,62.05,10.01), + Vec3d(19.78,29.16,-7.85), + Vec3d(39.56,65.98,33.71), + Vec3d(52.39,68.33,47.84), + Vec3d(81.23,24.12,87.51), + Vec3d(81.8,6.78,95.75), + Vec3d(71.72,-16.23,76.28), + Vec3d(20.31,14.45,16.74), + Vec3d(49.68,-0.19,0.05), + Vec3d(96.48,-0.88,0.68), + Vec3d(49.69,-0.18,0.03), + Vec3d(6.39,-0.04,-0.33), + Vec3d(96.54,-0.9,0.67), + Vec3d(49.72,-0.18,0.05), + Vec3d(6.49,-0.03,-0.41), + Vec3d(96.51,-0.9,0.69), + Vec3d(49.7,-0.19,0.07), + Vec3d(6.47,0,-0.38), + Vec3d(96.46,-0.89,0.7)); /** @brief Macbeth and Vinyl ColorChecker with 2deg D50 . */ enum CONST_COLOR { Macbeth, - Vinyl + Vinyl, + DigitalSG }; class CV_EXPORTS_W GetColor { public: diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp index 602bdf9f66b..af66e9ea1d6 100644 --- a/modules/mcc/samples/color_correction_model.cpp +++ b/modules/mcc/samples/color_correction_model.cpp @@ -86,24 +86,24 @@ int main(int argc, char *argv[]) /* If you use a customized ColorChecker, you can use your own reference color values and corresponding color space in a way like: */ // cv::Mat ref = (Mat_(18, 1) << - // Vec3d(1.00000000e+02, 5.20000001e-03, -1.04000000e-02), - // Vec3d(7.30833969e+01, -8.19999993e-01, -2.02099991e+00), - // Vec3d(6.24930000e+01, 4.25999999e-01, -2.23099995e+00), - // Vec3d(5.04640007e+01, 4.46999997e-01, -2.32399988e+00), - // Vec3d(3.77970009e+01, 3.59999985e-02, -1.29700005e+00), - // Vec3d(0.00000000e+00, 0.00000000e+00, 0.00000000e+00), - // Vec3d(5.15880013e+01, 7.35179977e+01, 5.15690002e+01), - // Vec3d(9.36989975e+01, -1.57340002e+01, 9.19420013e+01), - // Vec3d(6.94079971e+01, -4.65940018e+01, 5.04869995e+01), - // Vec3d(6.66100006e+01, -1.36789999e+01, -4.31720009e+01), - // Vec3d(1.17110004e+01, 1.69799995e+01, -3.71759987e+01), - // Vec3d(5.19739990e+01, 8.19440002e+01, -8.40699959e+00), - // Vec3d(4.05489998e+01, 5.04399986e+01, 2.48490009e+01), - // Vec3d(6.08160019e+01, 2.60690002e+01, 4.94420013e+01), - // Vec3d(5.22529984e+01, -1.99500008e+01, -2.39960003e+01), - // Vec3d(5.12859993e+01, 4.84700012e+01, -1.50579996e+01), - // Vec3d(6.87070007e+01, 1.22959995e+01, 1.62129993e+01), - // Vec3d(6.36839981e+01, 1.02930002e+01, 1.67639999e+01)); + // Vec3d(100, 0.00520000001, -0.0104), + // Vec3d(73.0833969, -0.819999993, -2.02099991), + // Vec3d(62.493, 0.425999999, -2.23099995), + // Vec3d(50.4640007, 0.446999997, -2.32399988), + // Vec3d(37.7970009, 0.0359999985, -1.29700005), + // Vec3d(0, 0, 0), + // Vec3d(51.5880013, 73.5179977, 51.5690002), + // Vec3d(93.6989975, -15.7340002, 91.9420013), + // Vec3d(69.4079971, -46.5940018, 50.4869995), + // Vec3d(66.61000060000001, -13.6789999, -43.1720009), + // Vec3d(11.7110004, 16.9799995, -37.1759987), + // Vec3d(51.973999, 81.9440002, -8.40699959), + // Vec3d(40.5489998, 50.4399986, 24.8490009), + // Vec3d(60.8160019, 26.0690002, 49.4420013), + // Vec3d(52.2529984, -19.9500008, -23.9960003), + // Vec3d(51.2859993, 48.4700012, -15.0579996), + // Vec3d(68.70700069999999, 12.2959995, 16.2129993), + // Vec3d(63.6839981, 10.2930002, 16.7639999)); // ColorCorrectionModel model8(src,ref,Lab_D50_2); diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 2d5f840273e..3e93f7cbbbb 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -73,7 +73,7 @@ ColorCorrectionModel::ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_, switch (initial_method_type) { case cv::ccm::WHITE_BALANCE: - ccm0 = initialWhiteBalance(); + initialWhiteBalance(); break; case cv::ccm::LEAST_SQUARE: initialLeastSquare(); @@ -139,7 +139,7 @@ void ColorCorrectionModel::calWeightsMasks(Mat weights_list, double weights_coef masked_len = (int)sum(mask)[0]; } -Mat ColorCorrectionModel::initialWhiteBalance(void) +void ColorCorrectionModel::initialWhiteBalance(void) { Mat schannels[4]; split(src_rgbl, schannels); @@ -150,7 +150,7 @@ Mat ColorCorrectionModel::initialWhiteBalance(void) sum(dchannels[2])[0] / sum(schannels[2])[0], 0, 0, 0 }; std::vector initial_vec_(initial_vec.begin(), initial_vec.begin() + shape); Mat initial_white_balance = Mat(initial_vec_, true).reshape(0, shape / 3); - return initial_white_balance; + ccm0 = initial_white_balance; } void ColorCorrectionModel::initialLeastSquare(bool fit) diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index 2134fc36d00..a85097ffcaa 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -147,6 +147,11 @@ Color GetColor::get_color(CONST_COLOR const_color) { return *Vinyl_D50_2; break; } + case cv::ccm::DigitalSG: { + std::shared_ptr DigitalSG_D50_2(new Color(DigitalSG_LAB_D50_2, Lab_D50_2)); + return *DigitalSG_D50_2; + break; + } default: throw; diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index 31a3436d443..62d6480d053 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -39,8 +39,9 @@ Here are the parameters for ColorCorrectionModel constcolor : the Built-in color card; Supported list: - Macbeth: Macbeth ColorChecker with 2deg D50; - Vinyl: DKK ColorChecker with 2deg D50; + Macbeth: Macbeth ColorChecker ; + Vinyl: DKK ColorChecker ; + DigitalSG: DigitalSG ColorChecker with 140 squares; type: enum CONST_COLOR; Mat colors_ : the reference color values @@ -52,11 +53,18 @@ Here are the parameters for ColorCorrectionModel NOTICE: For the list of color spaces supported, see the notes below; If the color type is some RGB, the format is RGB not BGR; type:enum COLOR_SPACE; - colorspace : + cs_ : the absolute color space that detected colors convert to; NOTICE: it should be some RGB color space; For the list of RGB color spaces supported, see the notes below; type: enum COLOR_SPACE; + dst_ : + the reference colors; + NOTICE: custom color card are supported; + You should use Color + For the list of color spaces supported, see the notes below; + If the color type is some RGB, the format is RGB not BGR, and the color values are in [0, 1]; + ccm_type : the shape of color correction matrix(CCM); Supported list: From d9b7b0a227b3da2d85affb13c53f08200711fd21 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Tue, 29 Sep 2020 20:01:29 +0800 Subject: [PATCH 35/71] replace whitespace for utils.hpp&color.hpp --- modules/mcc/include/opencv2/mcc/color.hpp | 2 +- modules/mcc/include/opencv2/mcc/utils.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/color.hpp b/modules/mcc/include/opencv2/mcc/color.hpp index 7e5f4e8a678..c4a802d5146 100644 --- a/modules/mcc/include/opencv2/mcc/color.hpp +++ b/modules/mcc/include/opencv2/mcc/color.hpp @@ -169,7 +169,7 @@ const Mat ColorChecker2005_COLORED_MASK = (Mat_(24, 1) << 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0); -const Mat Vinyl_LAB_D50_2 = (Mat_(18, 1) << +const Mat Vinyl_LAB_D50_2 = (Mat_(18, 1) << Vec3d(100, 0.00520000001, -0.0104), Vec3d(73.0833969, -0.819999993, -2.02099991), Vec3d(62.493, 0.425999999, -2.23099995), diff --git a/modules/mcc/include/opencv2/mcc/utils.hpp b/modules/mcc/include/opencv2/mcc/utils.hpp index 55e13a2723f..9e5ec5c59bc 100644 --- a/modules/mcc/include/opencv2/mcc/utils.hpp +++ b/modules/mcc/include/opencv2/mcc/utils.hpp @@ -48,7 +48,7 @@ CV_EXPORTS_W Mat gammaCorrection(const Mat& src, const double& gamma); CV_EXPORTS_W Mat maskCopyTo(const Mat& src, const Mat& mask); /** @brief multiple the function used to compute an array with n channels - mulipied by ccm. + mulipied by ccm. @param xyz the input array, type of Mat. @param ccm the ccm matrix to make color correction. */ @@ -63,7 +63,7 @@ CV_EXPORTS_W Mat multiple(const Mat& xyz, const Mat& ccm); CV_EXPORTS_W Mat saturate(Mat& src, const double& low, const double& up); /** @brief rgb2gray it is an approximation grayscale function for relative RGB - color space, see Miscellaneous.pdf for details; + color space, see Miscellaneous.pdf for details; @param rgb the input array,type of Mat. */ CV_EXPORTS_W Mat rgb2gray(Mat rgb); From 5312e32673ec3c3c93fa4f6c0dadfddd78ce5ef4 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Fri, 9 Oct 2020 14:56:42 +0800 Subject: [PATCH 36/71] update getilluminants,imgcodes, --- modules/mcc/CMakeLists.txt | 2 +- modules/mcc/include/opencv2/mcc/ccm.hpp | 17 ++++++++--------- modules/mcc/include/opencv2/mcc/colorspace.hpp | 6 +++--- modules/mcc/include/opencv2/mcc/distance.hpp | 18 +++++++++--------- modules/mcc/include/opencv2/mcc/utils.hpp | 12 ++++++------ modules/mcc/samples/color_correction_model.cpp | 14 +++++++++----- modules/mcc/src/ccm.cpp | 11 ++++++----- modules/mcc/src/colorspace.cpp | 9 ++++++--- modules/mcc/test/test_utils.cpp | 3 --- 9 files changed, 48 insertions(+), 44 deletions(-) diff --git a/modules/mcc/CMakeLists.txt b/modules/mcc/CMakeLists.txt index c45daaffab3..208f9d529ad 100644 --- a/modules/mcc/CMakeLists.txt +++ b/modules/mcc/CMakeLists.txt @@ -1,2 +1,2 @@ set(the_description "Macbeth Chart Detection") -ocv_define_module(mcc opencv_core opencv_imgproc opencv_imgcodecs opencv_calib3d opencv_photo opencv_dnn WRAP python) +ocv_define_module(mcc opencv_core opencv_imgproc opencv_calib3d opencv_photo opencv_dnn WRAP python) \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index bb05d7f4eac..16e807e06e3 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -33,7 +33,6 @@ #include #include #include -#include #include #include "opencv2/mcc/linearize.hpp" @@ -267,16 +266,16 @@ class CV_EXPORTS_W ColorCorrectionModel double loss; int max_count; double epsilon; - ColorCorrectionModel(cv::Mat src_, CONST_COLOR constcolor, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, - double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, cv::Mat weights_list = Mat(), double weights_coeff = 0, + ColorCorrectionModel(Mat src_, CONST_COLOR constcolor, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); - ColorCorrectionModel(cv::Mat src_, Mat colors_, COLOR_SPACE ref_cs_, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, - double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, cv::Mat weights_list = Mat(), double weights_coeff = 0, + ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE ref_cs_, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); - ColorCorrectionModel(cv::Mat src_, Color dst_, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, - double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, cv::Mat weights_list = Mat(), double weights_coeff = 0, + ColorCorrectionModel(Mat src_, Color dst_, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_ , CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, @@ -333,12 +332,12 @@ class CV_EXPORTS_W ColorCorrectionModel @param islinear if linearize or not. @return the output array, type of cv::Mat. */ - Mat inferImage(std::string imgfile, bool islinear = false); + Mat inferImage(Mat& img_, bool islinear = false); /** @brief Loss function base on cv::MinProblemSolver::Function. see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp */ - class LossFunction : public cv::MinProblemSolver::Function + class LossFunction : public MinProblemSolver::Function { public: ColorCorrectionModel* ccm_loss; diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp index 6602d43995d..118b88d5163 100644 --- a/modules/mcc/include/opencv2/mcc/colorspace.hpp +++ b/modules/mcc/include/opencv2/mcc/colorspace.hpp @@ -345,7 +345,7 @@ static std::map , Mat > cams; const static Mat Von_Kries = (Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); const static Mat Bradford = (Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); const static std::map > MAs = { - {IDENTITY , { Mat::eye(cv::Size(3,3),CV_64FC1) , Mat::eye(cv::Size(3,3),CV_64FC1)} }, + {IDENTITY , { Mat::eye(Size(3,3),CV_64FC1) , Mat::eye(Size(3,3),CV_64FC1)} }, {VON_KRIES, { Von_Kries ,Von_Kries.inv() }}, {BRADFORD, { Bradford ,Bradford.inv() }} }; @@ -391,7 +391,7 @@ class CV_EXPORTS_W Lab :public ColorSpace static constexpr double t0 = delta * delta * delta; static constexpr double c = 4. / 29.; - cv::Vec3d fromxyz(cv::Vec3d& xyz); + Vec3d fromxyz(Vec3d& xyz); /** @brief Calculate From. @@ -400,7 +400,7 @@ class CV_EXPORTS_W Lab :public ColorSpace */ Mat fromsrc(Mat& src); - cv::Vec3d tolab(cv::Vec3d& lab); + Vec3d tolab(Vec3d& lab); /** @brief Calculate To. @param src the input array, type of cv::Mat. diff --git a/modules/mcc/include/opencv2/mcc/distance.hpp b/modules/mcc/include/opencv2/mcc/distance.hpp index dc0b37680ec..aaf9ff514b3 100644 --- a/modules/mcc/include/opencv2/mcc/distance.hpp +++ b/modules/mcc/include/opencv2/mcc/distance.hpp @@ -56,7 +56,7 @@ enum DISTANCE_TYPE @return distance between lab1 and lab2 */ -double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCIE76(Vec3d lab1, Vec3d lab2); /** @brief distance between two points in formula CIE94 @param lab1 a 3D vector @@ -69,15 +69,15 @@ double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2); @return distance between lab1 and lab2 */ -double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH = 1.0, +double deltaCIE94(Vec3d lab1, Vec3d lab2, double kH = 1.0, double kC = 1.0, double kL = 1.0, double k1 = 0.045, double k2 = 0.015); -double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCIE94GraphicArts(Vec3d lab1, Vec3d lab2); double toRad(double degree); -double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCIE94Textiles(Vec3d lab1, Vec3d lab2); /** @brief distance between two points in formula CIE2000 @@ -88,9 +88,9 @@ double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2); @param kH Hue scale @return distance between lab1 and lab2 */ -double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1.0, +double deltaCIEDE2000_(Vec3d lab1, Vec3d lab2, double kL = 1.0, double kC = 1.0, double kH = 1.0); -double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCIEDE2000(Vec3d lab1, Vec3d lab2); /** @brief distance between two points in formula CMC @@ -101,11 +101,11 @@ double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2); @return distance between lab1 and lab2 */ -double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL = 1, double kC = 1); +double deltaCMC(Vec3d lab1, Vec3d lab2, double kL = 1, double kC = 1); -double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCMC1To1(Vec3d lab1, Vec3d lab2); -double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2); +double deltaCMC2To1(Vec3d lab1, Vec3d lab2); Mat distance(Mat src, Mat ref, DISTANCE_TYPE distance_type); diff --git a/modules/mcc/include/opencv2/mcc/utils.hpp b/modules/mcc/include/opencv2/mcc/utils.hpp index 9e5ec5c59bc..989971cb0fb 100644 --- a/modules/mcc/include/opencv2/mcc/utils.hpp +++ b/modules/mcc/include/opencv2/mcc/utils.hpp @@ -91,8 +91,8 @@ Mat elementWise(const Mat& src, F&& lambda) } case 3: { - MatIterator_ it, end; - for (it = dst.begin(), end = dst.end(); it != end; ++it) + MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) { for (int j = 0; j < 3; j++) { @@ -116,8 +116,8 @@ template Mat channelWise(const Mat& src, F&& lambda) { Mat dst = src.clone(); - MatIterator_ it, end; - for (it = dst.begin(), end = dst.end(); it != end; ++it) + MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) { *it = lambda(*it); } @@ -133,8 +133,8 @@ template Mat distanceWise(Mat& src, Mat& ref, F&& lambda) { Mat dst = Mat(src.size(), CV_64FC1); - MatIterator_ it_src = src.begin(), end_src = src.end(), - it_ref = ref.begin(); + MatIterator_ it_src = src.begin(), end_src = src.end(), + it_ref = ref.begin(); MatIterator_ it_dst = dst.begin(); for (; it_src != end_src; ++it_src, ++it_ref, ++it_dst) { diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp index af66e9ea1d6..d989b837ad5 100644 --- a/modules/mcc/samples/color_correction_model.cpp +++ b/modules/mcc/samples/color_correction_model.cpp @@ -12,13 +12,13 @@ using namespace ccm; using namespace std; const char *about = "Basic chart detection"; -const char *keys = { +const char *keys = "{ help h usage ? | | show this message }" "{t | | chartType: 0-Standard, 1-DigitalSG, 2-Vinyl }" "{v | | Input from video file, if ommited, input comes from camera }" "{ci | 0 | Camera id if input doesnt come from video (-v) }" "{f | 1 | Path of the file to process (-v) }" - "{nc | 1 | Maximum number of charts in the image }"}; + "{nc | 1 | Maximum number of charts in the image }"; int main(int argc, char *argv[]) { @@ -45,7 +45,7 @@ int main(int argc, char *argv[]) return 0; } - Mat image = cv::imread(filepath, IMREAD_COLOR); + Mat image = imread(filepath, IMREAD_COLOR); if (!image.data) { cout << "Invalid Image!" << endl; @@ -108,7 +108,11 @@ int main(int argc, char *argv[]) // ColorCorrectionModel model8(src,ref,Lab_D50_2); //make color correction - Mat calibratedImage = model1.inferImage(filepath); + Mat img = imread(imgfile); + Mat img_; + cvtColor(img, img_, COLOR_BGR2RGB); + img_.convertTo(img_, CV_64F); + Mat calibratedImage = model1.inferImage(img_); // Save the calibrated image to {FILE_NAME}.calibrated.{FILE_EXT} string filename = filepath.substr(filepath.find_last_of('/')+1); @@ -116,7 +120,7 @@ int main(int argc, char *argv[]) string baseName = filename.substr(0, dotIndex); string ext = filename.substr(dotIndex+1, filename.length()-dotIndex); string calibratedFilePath = baseName + ".calibrated." + ext; - cv::imwrite(calibratedFilePath, calibratedImage); + imwrite(calibratedFilePath, calibratedImage); } return 0; diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 3e93f7cbbbb..0d0d7d76d98 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -237,14 +237,15 @@ Mat ColorCorrectionModel::infer(const Mat& img, bool islinear) return cs.fromL(img_ccm); } -Mat ColorCorrectionModel::inferImage(std::string imgfile, bool islinear) +//Mat ColorCorrectionModel::inferImage(std::string imgfile, bool islinear) +Mat ColorCorrectionModel::inferImage(Mat& img_, bool islinear) { const int inp_size = 255; const int out_size = 255; - Mat img = imread(imgfile); - Mat img_; - cvtColor(img, img_, COLOR_BGR2RGB); - img_.convertTo(img_, CV_64F); + // Mat img = imread(imgfile); + // Mat img_; + // cvtColor(img, img_, COLOR_BGR2RGB); + // img_.convertTo(img_, CV_64F); img_ = img_ / inp_size; Mat out = this->infer(img_, islinear); Mat out_ = out * out_size; diff --git a/modules/mcc/src/colorspace.cpp b/modules/mcc/src/colorspace.cpp index 2200034dbe4..46ddd3a9070 100644 --- a/modules/mcc/src/colorspace.cpp +++ b/modules/mcc/src/colorspace.cpp @@ -29,8 +29,9 @@ namespace cv { namespace ccm { - -static std::map> illuminants = { +static std::map> getilluminants() +{ + static std::map> illuminants = { {A_2, { 1.098466069456375, 1, 0.3558228003436005 }}, {A_10, { 1.111420406956693, 1, 0.3519978321919493 }}, {D50_2, { 0.9642119944211994, 1, 0.8251882845188288 }}, @@ -44,7 +45,9 @@ static std::map> illuminants = { {E_2, { 1., 1., 1. }}, {E_10, { 1., 1., 1. }}, }; - + return illuminants; +}; +static std::map> illuminants =getilluminants(); /* *\ brief Basic class for ColorSpace. */ bool ColorSpace::relate(const ColorSpace& other) const { diff --git a/modules/mcc/test/test_utils.cpp b/modules/mcc/test/test_utils.cpp index df8d70383a4..f7fe5ca2160 100644 --- a/modules/mcc/test/test_utils.cpp +++ b/modules/mcc/test/test_utils.cpp @@ -40,9 +40,6 @@ TEST(CV_ccmUtils, test_rgb2gray) { Mat x = (Mat_(1, 1) << Vec3d(0.2, 0.3, 0.4)); Mat y = (Mat_(1, 1) <<0.28596); - std::cout << x << std::endl; - std::cout << "vs" << std::endl; - std::cout << y << std::endl; ASSERT_MAT_NEAR(rgb2gray(x), y, 1e-4); } From 4b77df540aa85b5864484eff085b5feae1a1ba8f Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Sun, 11 Oct 2020 18:42:50 +0800 Subject: [PATCH 37/71] Fix Mat wrapper over data from C arrays, fix doxygen's @snippet instead of direct code. --- modules/mcc/include/opencv2/mcc/ccm.hpp | 2 +- modules/mcc/include/opencv2/mcc/color.hpp | 442 +++++++++--------- .../mcc/samples/color_correction_model.cpp | 25 +- modules/mcc/src/ccm.cpp | 5 - modules/mcc/src/color.cpp | 29 +- modules/mcc/test/test_color.cpp | 7 +- .../basic_ccm/color_correction_model.markdown | 60 +-- 7 files changed, 282 insertions(+), 288 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 16e807e06e3..a4b738ff1f7 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -328,7 +328,7 @@ class CV_EXPORTS_W ColorCorrectionModel /** @brief Infer image and output as an BGR image with uint8 type. mainly for test or debug. input size and output size should be 255. - @param imgfile path name of image to infer. + @param img_ image to infer, type of cv::Mat. @param islinear if linearize or not. @return the output array, type of cv::Mat. */ diff --git a/modules/mcc/include/opencv2/mcc/color.hpp b/modules/mcc/include/opencv2/mcc/color.hpp index c4a802d5146..e4934728fa2 100644 --- a/modules/mcc/include/opencv2/mcc/color.hpp +++ b/modules/mcc/include/opencv2/mcc/color.hpp @@ -53,8 +53,9 @@ class CV_EXPORTS_W Color Mat grays; Mat colored; std::map> history; - Color(Mat colors_, enum COLOR_SPACE cs_) ; - Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_) ; + Color(Mat colors_, enum COLOR_SPACE cs_); + Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_); + // Color(double *colors_,int row,int col, enum COLOR_SPACE cs_); Color(Mat colors_, const ColorSpace& cs_, Mat colored_); Color(Mat colors_, const ColorSpace& cs_); @@ -111,229 +112,227 @@ class CV_EXPORTS_W Color /** @brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls see Miscellaneous.md for details. */ -const Mat ColorChecker2005_LAB_D50_2 = (Mat_(24, 1) << - Vec3d(37.986, 13.555, 14.059), - Vec3d(65.711, 18.13, 17.81), - Vec3d(49.927, -4.88, -21.925), - Vec3d(43.139, -13.095, 21.905), - Vec3d(55.112, 8.844, -25.399), - Vec3d(70.719, -33.397, -0.199), - Vec3d(62.661, 36.067, 57.096), - Vec3d(40.02, 10.41, -45.964), - Vec3d(51.124, 48.239, 16.248), - Vec3d(30.325, 22.976, -21.587), - Vec3d(72.532, -23.709, 57.255), - Vec3d(71.941, 19.363, 67.857), - Vec3d(28.778, 14.179, -50.297), - Vec3d(55.261, -38.342, 31.37), - Vec3d(42.101, 53.378, 28.19), - Vec3d(81.733, 4.039, 79.819), - Vec3d(51.935, 49.986, -14.574), - Vec3d(51.038, -28.631, -28.638), - Vec3d(96.539, -0.425, 1.186), - Vec3d(81.257, -0.638, -0.335), - Vec3d(66.766, -0.734, -0.504), - Vec3d(50.867, -0.153, -0.27), - Vec3d(35.656, -0.421, -1.231), - Vec3d(20.461, -0.079, -0.973)); +const double ColorChecker2005_LAB_D50_2 [24][3] = + { {37.986, 13.555, 14.059}, + {65.711, 18.13, 17.81}, + {49.927, -4.88, -21.925}, + {43.139, -13.095, 21.905}, + {55.112, 8.844, -25.399}, + {70.719, -33.397, -0.199}, + {62.661, 36.067, 57.096}, + {40.02, 10.41, -45.964}, + {51.124, 48.239, 16.248}, + {30.325, 22.976, -21.587}, + {72.532, -23.709, 57.255}, + {71.941, 19.363, 67.857}, + {28.778, 14.179, -50.297}, + {55.261, -38.342, 31.37}, + {42.101, 53.378, 28.19}, + {81.733, 4.039, 79.819}, + {51.935, 49.986, -14.574}, + {51.038, -28.631, -28.638}, + {96.539, -0.425, 1.186}, + {81.257, -0.638, -0.335}, + {66.766, -0.734, -0.504}, + {50.867, -0.153, -0.27}, + {35.656, -0.421, -1.231}, + {20.461, -0.079, -0.973}}; -const Mat ColorChecker2005_LAB_D65_2 = (Mat_(24, 1) << - Vec3d(37.542, 12.018, 13.33), - Vec3d(65.2, 14.821, 17.545), - Vec3d(50.366, -1.573, -21.431), - Vec3d(43.125, -14.63, 22.12), - Vec3d(55.343, 11.449, -25.289), - Vec3d(71.36, -32.718, 1.636), - Vec3d(61.365, 32.885, 55.155), - Vec3d(40.712, 16.908, -45.085), - Vec3d(49.86, 45.934, 13.876), - Vec3d(30.15, 24.915, -22.606), - Vec3d(72.438, -27.464, 58.469), - Vec3d(70.916, 15.583, 66.543), - Vec3d(29.624, 21.425, -49.031), - Vec3d(55.643, -40.76, 33.274), - Vec3d(40.554, 49.972, 25.46), - Vec3d(80.982, -1.037, 80.03), - Vec3d(51.006, 49.876, -16.93), - Vec3d(52.121, -24.61, -26.176), - Vec3d(96.536, -0.694, 1.354), - Vec3d(81.274, -0.61, -0.24), - Vec3d(66.787, -0.647, -0.429), - Vec3d(50.872, -0.059, -0.247), - Vec3d(35.68, -0.22, -1.205), - Vec3d(20.475, 0.049, -0.972)); +const double ColorChecker2005_LAB_D65_2[24][3]= + {{37.542, 12.018, 13.33}, + {65.2, 14.821, 17.545}, + {50.366, -1.573, -21.431}, + {43.125, -14.63, 22.12}, + {55.343, 11.449, -25.289}, + {71.36, -32.718, 1.636}, + {61.365, 32.885, 55.155}, + {40.712, 16.908, -45.085}, + {49.86, 45.934, 13.876}, + {30.15, 24.915, -22.606}, + {72.438, -27.464, 58.469}, + {70.916, 15.583, 66.543}, + {29.624, 21.425, -49.031}, + {55.643, -40.76, 33.274}, + {40.554, 49.972, 25.46}, + {80.982, -1.037, 80.03}, + {51.006, 49.876, -16.93}, + {52.121, -24.61, -26.176}, + {96.536, -0.694, 1.354}, + {81.274, -0.61, -0.24}, + {66.787, -0.647, -0.429}, + {50.872, -0.059, -0.247}, + {35.68, -0.22, -1.205}, + {20.475, 0.049, -0.972}}; -const Mat ColorChecker2005_COLORED_MASK = (Mat_(24, 1) << +const uchar ColorChecker2005_COLORED_MASK[24] = + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0}; +const double Vinyl_LAB_D50_2[18][3] = + { {100, 0.00520000001, -0.0104}, + {73.0833969, -0.819999993, -2.02099991}, + {62.493, 0.425999999, -2.23099995}, + {50.4640007, 0.446999997, -2.32399988}, + {37.7970009, 0.0359999985, -1.29700005}, + {0, 0, 0}, + {51.5880013, 73.5179977, 51.5690002}, + {93.6989975, -15.7340002, 91.9420013}, + {69.4079971, -46.5940018, 50.4869995}, + {66.61000060000001, -13.6789999, -43.1720009}, + {11.7110004, 16.9799995, -37.1759987}, + {51.973999, 81.9440002, -8.40699959}, + {40.5489998, 50.4399986, 24.8490009}, + {60.8160019, 26.0690002, 49.4420013}, + {52.2529984, -19.9500008, -23.9960003}, + {51.2859993, 48.4700012, -15.0579996}, + {68.70700069999999, 12.2959995, 16.2129993}, + {63.6839981, 10.2930002, 16.7639999}}; +const uchar Vinyl_COLORED_MASK[18]= + { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0); - -const Mat Vinyl_LAB_D50_2 = (Mat_(18, 1) << - Vec3d(100, 0.00520000001, -0.0104), - Vec3d(73.0833969, -0.819999993, -2.02099991), - Vec3d(62.493, 0.425999999, -2.23099995), - Vec3d(50.4640007, 0.446999997, -2.32399988), - Vec3d(37.7970009, 0.0359999985, -1.29700005), - Vec3d(0, 0, 0), - Vec3d(51.5880013, 73.5179977, 51.5690002), - Vec3d(93.6989975, -15.7340002, 91.9420013), - Vec3d(69.4079971, -46.5940018, 50.4869995), - Vec3d(66.61000060000001, -13.6789999, -43.1720009), - Vec3d(11.7110004, 16.9799995, -37.1759987), - Vec3d(51.973999, 81.9440002, -8.40699959), - Vec3d(40.5489998, 50.4399986, 24.8490009), - Vec3d(60.8160019, 26.0690002, 49.4420013), - Vec3d(52.2529984, -19.9500008, -23.9960003), - Vec3d(51.2859993, 48.4700012, -15.0579996), - Vec3d(68.70700069999999, 12.2959995, 16.2129993), - Vec3d(63.6839981, 10.2930002, 16.7639999)); - -const Mat Vinyl_COLORED_MASK = (Mat_(18, 1) << - 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1); -const Mat DigitalSG_LAB_D50_2 = (Mat_(140, 1) << - Vec3d(96.55,-0.91,0.57), - Vec3d(6.43,-0.06,-0.41), - Vec3d(49.7,-0.18,0.03), - Vec3d(96.5,-0.89,0.59), - Vec3d(6.5,-0.06,-0.44), - Vec3d(49.66,-0.2,0.01), - Vec3d(96.52,-0.91,0.58), - Vec3d(6.49,-0.02,-0.28), - Vec3d(49.72,-0.2,0.04), - Vec3d(96.43,-0.91,0.67), - Vec3d(49.72,-0.19,0), - Vec3d(32.6,51.58,-10.85), - Vec3d(60.75,26.22,-18.6), - Vec3d(28.69,48.28,-39), - Vec3d(49.38,-15.43,-48.48), - Vec3d(60.63,-30.77,-26.23), - Vec3d(19.29,-26.37,-6.15), - Vec3d(60.15,-41.77,-12.6), - Vec3d(21.42,1.67,8.79), - Vec3d(49.69,-0.2,0.01), - Vec3d(6.5,-0.03,-0.67), - Vec3d(21.82,17.33,-18.35), - Vec3d(41.53,18.48,-37.26), - Vec3d(19.99,-0.16,-36.29), - Vec3d(60.16,-18.45,-31.42), - Vec3d(19.94,-17.92,-20.96), - Vec3d(60.68,-6.05,-32.81), - Vec3d(50.81,-49.8,-9.63), - Vec3d(60.65,-39.77,20.76), - Vec3d(6.53,-0.03,-0.43), - Vec3d(96.56,-0.91,0.59), - Vec3d(84.19,-1.95,-8.23), - Vec3d(84.75,14.55,0.23), - Vec3d(84.87,-19.07,-0.82), - Vec3d(85.15,13.48,6.82), - Vec3d(84.17,-10.45,26.78), - Vec3d(61.74,31.06,36.42), - Vec3d(64.37,20.82,18.92), - Vec3d(50.4,-53.22,14.62), - Vec3d(96.51,-0.89,0.65), - Vec3d(49.74,-0.19,0.03), - Vec3d(31.91,18.62,21.99), - Vec3d(60.74,38.66,70.97), - Vec3d(19.35,22.23,-58.86), - Vec3d(96.52,-0.91,0.62), - Vec3d(6.66,0,-0.3), - Vec3d(76.51,20.81,22.72), - Vec3d(72.79,29.15,24.18), - Vec3d(22.33,-20.7,5.75), - Vec3d(49.7,-0.19,0.01), - Vec3d(6.53,-0.05,-0.61), - Vec3d(63.42,20.19,19.22), - Vec3d(34.94,11.64,-50.7), - Vec3d(52.03,-44.15,39.04), - Vec3d(79.43,0.29,-0.17), - Vec3d(30.67,-0.14,-0.53), - Vec3d(63.6,14.44,26.07), - Vec3d(64.37,14.5,17.05), - Vec3d(60.01,-44.33,8.49), - Vec3d(6.63,-0.01,-0.47), - Vec3d(96.56,-0.93,0.59), - Vec3d(46.37,-5.09,-24.46), - Vec3d(47.08,52.97,20.49), - Vec3d(36.04,64.92,38.51), - Vec3d(65.05,0,-0.32), - Vec3d(40.14,-0.19,-0.38), - Vec3d(43.77,16.46,27.12), - Vec3d(64.39,17,16.59), - Vec3d(60.79,-29.74,41.5), - Vec3d(96.48,-0.89,0.64), - Vec3d(49.75,-0.21,0.01), - Vec3d(38.18,-16.99,30.87), - Vec3d(21.31,29.14,-27.51), - Vec3d(80.57,3.85,89.61), - Vec3d(49.71,-0.2,0.03), - Vec3d(60.27,0.08,-0.41), - Vec3d(67.34,14.45,16.9), - Vec3d(64.69,16.95,18.57), - Vec3d(51.12,-49.31,44.41), - Vec3d(49.7,-0.2,0.02), - Vec3d(6.67,-0.05,-0.64), - Vec3d(51.56,9.16,-26.88), - Vec3d(70.83,-24.26,64.77), - Vec3d(48.06,55.33,-15.61), - Vec3d(35.26,-0.09,-0.24), - Vec3d(75.16,0.25,-0.2), - Vec3d(44.54,26.27,38.93), - Vec3d(35.91,16.59,26.46), - Vec3d(61.49,-52.73,47.3), - Vec3d(6.59,-0.05,-0.5), - Vec3d(96.58,-0.9,0.61), - Vec3d(68.93,-34.58,-0.34), - Vec3d(69.65,20.09,78.57), - Vec3d(47.79,-33.18,-30.21), - Vec3d(15.94,-0.42,-1.2), - Vec3d(89.02,-0.36,-0.48), - Vec3d(63.43,25.44,26.25), - Vec3d(65.75,22.06,27.82), - Vec3d(61.47,17.1,50.72), - Vec3d(96.53,-0.89,0.66), - Vec3d(49.79,-0.2,0.03), - Vec3d(85.17,10.89,17.26), - Vec3d(89.74,-16.52,6.19), - Vec3d(84.55,5.07,-6.12), - Vec3d(84.02,-13.87,-8.72), - Vec3d(70.76,0.07,-0.35), - Vec3d(45.59,-0.05,0.23), - Vec3d(20.3,0.07,-0.32), - Vec3d(61.79,-13.41,55.42), - Vec3d(49.72,-0.19,0.02), - Vec3d(6.77,-0.05,-0.44), - Vec3d(21.85,34.37,7.83), - Vec3d(42.66,67.43,48.42), - Vec3d(60.33,36.56,3.56), - Vec3d(61.22,36.61,17.32), - Vec3d(62.07,52.8,77.14), - Vec3d(72.42,-9.82,89.66), - Vec3d(62.03,3.53,57.01), - Vec3d(71.95,-27.34,73.69), - Vec3d(6.59,-0.04,-0.45), - Vec3d(49.77,-0.19,0.04), - Vec3d(41.84,62.05,10.01), - Vec3d(19.78,29.16,-7.85), - Vec3d(39.56,65.98,33.71), - Vec3d(52.39,68.33,47.84), - Vec3d(81.23,24.12,87.51), - Vec3d(81.8,6.78,95.75), - Vec3d(71.72,-16.23,76.28), - Vec3d(20.31,14.45,16.74), - Vec3d(49.68,-0.19,0.05), - Vec3d(96.48,-0.88,0.68), - Vec3d(49.69,-0.18,0.03), - Vec3d(6.39,-0.04,-0.33), - Vec3d(96.54,-0.9,0.67), - Vec3d(49.72,-0.18,0.05), - Vec3d(6.49,-0.03,-0.41), - Vec3d(96.51,-0.9,0.69), - Vec3d(49.7,-0.19,0.07), - Vec3d(6.47,0,-0.38), - Vec3d(96.46,-0.89,0.7)); + 1, 1, 1, 1, 1, 1}; +const double DigitalSG_LAB_D50_2[140][3] = + { {96.55,-0.91,0.57}, + {6.43,-0.06,-0.41}, + {49.7,-0.18,0.03}, + {96.5,-0.89,0.59}, + {6.5,-0.06,-0.44}, + {49.66,-0.2,0.01}, + {96.52,-0.91,0.58}, + {6.49,-0.02,-0.28}, + {49.72,-0.2,0.04}, + {96.43,-0.91,0.67}, + {49.72,-0.19,0}, + {32.6,51.58,-10.85}, + {60.75,26.22,-18.6}, + {28.69,48.28,-39}, + {49.38,-15.43,-48.48}, + {60.63,-30.77,-26.23}, + {19.29,-26.37,-6.15}, + {60.15,-41.77,-12.6}, + {21.42,1.67,8.79}, + {49.69,-0.2,0.01}, + {6.5,-0.03,-0.67}, + {21.82,17.33,-18.35}, + {41.53,18.48,-37.26}, + {19.99,-0.16,-36.29}, + {60.16,-18.45,-31.42}, + {19.94,-17.92,-20.96}, + {60.68,-6.05,-32.81}, + {50.81,-49.8,-9.63}, + {60.65,-39.77,20.76}, + {6.53,-0.03,-0.43}, + {96.56,-0.91,0.59}, + {84.19,-1.95,-8.23}, + {84.75,14.55,0.23}, + {84.87,-19.07,-0.82}, + {85.15,13.48,6.82}, + {84.17,-10.45,26.78}, + {61.74,31.06,36.42}, + {64.37,20.82,18.92}, + {50.4,-53.22,14.62}, + {96.51,-0.89,0.65}, + {49.74,-0.19,0.03}, + {31.91,18.62,21.99}, + {60.74,38.66,70.97}, + {19.35,22.23,-58.86}, + {96.52,-0.91,0.62}, + {6.66,0,-0.3}, + {76.51,20.81,22.72}, + {72.79,29.15,24.18}, + {22.33,-20.7,5.75}, + {49.7,-0.19,0.01}, + {6.53,-0.05,-0.61}, + {63.42,20.19,19.22}, + {34.94,11.64,-50.7}, + {52.03,-44.15,39.04}, + {79.43,0.29,-0.17}, + {30.67,-0.14,-0.53}, + {63.6,14.44,26.07}, + {64.37,14.5,17.05}, + {60.01,-44.33,8.49}, + {6.63,-0.01,-0.47}, + {96.56,-0.93,0.59}, + {46.37,-5.09,-24.46}, + {47.08,52.97,20.49}, + {36.04,64.92,38.51}, + {65.05,0,-0.32}, + {40.14,-0.19,-0.38}, + {43.77,16.46,27.12}, + {64.39,17,16.59}, + {60.79,-29.74,41.5}, + {96.48,-0.89,0.64}, + {49.75,-0.21,0.01}, + {38.18,-16.99,30.87}, + {21.31,29.14,-27.51}, + {80.57,3.85,89.61}, + {49.71,-0.2,0.03}, + {60.27,0.08,-0.41}, + {67.34,14.45,16.9}, + {64.69,16.95,18.57}, + {51.12,-49.31,44.41}, + {49.7,-0.2,0.02}, + {6.67,-0.05,-0.64}, + {51.56,9.16,-26.88}, + {70.83,-24.26,64.77}, + {48.06,55.33,-15.61}, + {35.26,-0.09,-0.24}, + {75.16,0.25,-0.2}, + {44.54,26.27,38.93}, + {35.91,16.59,26.46}, + {61.49,-52.73,47.3}, + {6.59,-0.05,-0.5}, + {96.58,-0.9,0.61}, + {68.93,-34.58,-0.34}, + {69.65,20.09,78.57}, + {47.79,-33.18,-30.21}, + {15.94,-0.42,-1.2}, + {89.02,-0.36,-0.48}, + {63.43,25.44,26.25}, + {65.75,22.06,27.82}, + {61.47,17.1,50.72}, + {96.53,-0.89,0.66}, + {49.79,-0.2,0.03}, + {85.17,10.89,17.26}, + {89.74,-16.52,6.19}, + {84.55,5.07,-6.12}, + {84.02,-13.87,-8.72}, + {70.76,0.07,-0.35}, + {45.59,-0.05,0.23}, + {20.3,0.07,-0.32}, + {61.79,-13.41,55.42}, + {49.72,-0.19,0.02}, + {6.77,-0.05,-0.44}, + {21.85,34.37,7.83}, + {42.66,67.43,48.42}, + {60.33,36.56,3.56}, + {61.22,36.61,17.32}, + {62.07,52.8,77.14}, + {72.42,-9.82,89.66}, + {62.03,3.53,57.01}, + {71.95,-27.34,73.69}, + {6.59,-0.04,-0.45}, + {49.77,-0.19,0.04}, + {41.84,62.05,10.01}, + {19.78,29.16,-7.85}, + {39.56,65.98,33.71}, + {52.39,68.33,47.84}, + {81.23,24.12,87.51}, + {81.8,6.78,95.75}, + {71.72,-16.23,76.28}, + {20.31,14.45,16.74}, + {49.68,-0.19,0.05}, + {96.48,-0.88,0.68}, + {49.69,-0.18,0.03}, + {6.39,-0.04,-0.33}, + {96.54,-0.9,0.67}, + {49.72,-0.18,0.05}, + {6.49,-0.03,-0.41}, + {96.51,-0.9,0.69}, + {49.7,-0.19,0.07}, + {6.47,0,-0.38}, + {96.46,-0.89,0.7}}; /** @brief Macbeth and Vinyl ColorChecker with 2deg D50 . */ enum CONST_COLOR { @@ -344,9 +343,10 @@ enum CONST_COLOR { class CV_EXPORTS_W GetColor { public: static Color get_color(CONST_COLOR const_color); + static Mat get_ColorChecker(const double *checker,int row); + static Mat get_ColorChecker_MASK(const uchar *checker,int row); }; - } // namespace ccm } // namespace cv diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp index d989b837ad5..c5327279a72 100644 --- a/modules/mcc/samples/color_correction_model.cpp +++ b/modules/mcc/samples/color_correction_model.cpp @@ -1,3 +1,4 @@ +//! [tutorial] #include #include @@ -12,7 +13,7 @@ using namespace ccm; using namespace std; const char *about = "Basic chart detection"; -const char *keys = +const char *keys = "{ help h usage ? | | show this message }" "{t | | chartType: 0-Standard, 1-DigitalSG, 2-Vinyl }" "{v | | Input from video file, if ommited, input comes from camera }" @@ -26,7 +27,7 @@ int main(int argc, char *argv[]) // ---------------------------------------------------------- // Scroll down a bit (~40 lines) to find actual relevant code // ---------------------------------------------------------- - + //! [get_messages_of_image] CommandLineParser parser(argc, argv, keys); parser.about(about); @@ -51,6 +52,7 @@ int main(int argc, char *argv[]) cout << "Invalid Image!" << endl; return 1; } + //! [get_messages_of_image] Mat imageCopy = image.clone(); Ptr detector = CCheckerDetector::create(); @@ -60,19 +62,23 @@ int main(int argc, char *argv[]) printf("ChartColor not detected \n"); return 2; } - // get checker + //! [get_color_checker] vector> checkers = detector->getListColorChecker(); - + //! [get_color_checker] for (Ptr checker : checkers) { + //! [creat] Ptr cdraw = CCheckerDraw::create(checker); cdraw->draw(image); Mat chartsRGB = checker->getChartsRGB(); Mat src = chartsRGB.col(1).clone().reshape(3, 18); src /= 255.0; + //! [creat] //compte color correction matrix + //! [get_ccm_Matrix] ColorCorrectionModel model1(src, Vinyl); + //! [get_ccm_Matrix] /* brief More models with different parameters, try it & check the document for details. */ @@ -85,6 +91,7 @@ int main(int argc, char *argv[]) /* If you use a customized ColorChecker, you can use your own reference color values and corresponding color space in a way like: */ + //! [reference_color_values] // cv::Mat ref = (Mat_(18, 1) << // Vec3d(100, 0.00520000001, -0.0104), // Vec3d(73.0833969, -0.819999993, -2.02099991), @@ -106,14 +113,16 @@ int main(int argc, char *argv[]) // Vec3d(63.6839981, 10.2930002, 16.7639999)); // ColorCorrectionModel model8(src,ref,Lab_D50_2); + //! [reference_color_values] - //make color correction - Mat img = imread(imgfile); + //! [make_color_correction] Mat img_; - cvtColor(img, img_, COLOR_BGR2RGB); + cvtColor(image, img_, COLOR_BGR2RGB); img_.convertTo(img_, CV_64F); Mat calibratedImage = model1.inferImage(img_); + //! [make_color_correction] + //! [Save_calibrated_image] // Save the calibrated image to {FILE_NAME}.calibrated.{FILE_EXT} string filename = filepath.substr(filepath.find_last_of('/')+1); size_t dotIndex = filename.find_last_of('.'); @@ -121,7 +130,9 @@ int main(int argc, char *argv[]) string ext = filename.substr(dotIndex+1, filename.length()-dotIndex); string calibratedFilePath = baseName + ".calibrated." + ext; imwrite(calibratedFilePath, calibratedImage); + //! [Save_calibrated_image] } return 0; } +//! [tutorial] \ No newline at end of file diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 0d0d7d76d98..279404ded70 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -237,15 +237,10 @@ Mat ColorCorrectionModel::infer(const Mat& img, bool islinear) return cs.fromL(img_ccm); } -//Mat ColorCorrectionModel::inferImage(std::string imgfile, bool islinear) Mat ColorCorrectionModel::inferImage(Mat& img_, bool islinear) { const int inp_size = 255; const int out_size = 255; - // Mat img = imread(imgfile); - // Mat img_; - // cvtColor(img, img_, COLOR_BGR2RGB); - // img_.convertTo(img_, CV_64F); img_ = img_ / inp_size; Mat out = this->infer(img_, islinear); Mat out_ = out * out_size; diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index a85097ffcaa..ac1f72cd801 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -132,23 +132,45 @@ Color Color::operator[](Mat mask) return Color(maskCopyTo(colors, mask), cs); } +Mat GetColor::get_ColorChecker(const double *checker,int row){ + Mat res(row,1, CV_64FC3); + for(int i = 0;i< row;++i) + { + res.at(i,0)=Vec3d(checker[3*i],checker[3*i+1],checker[3*i+2]); + } + return res; +} + +Mat GetColor::get_ColorChecker_MASK(const uchar *checker,int row){ + Mat res(row,1, CV_8U); + for(int i = 0;i< row;++i){ + res.at(i,0)=checker[i]; + } + return res; +} + Color GetColor::get_color(CONST_COLOR const_color) { switch (const_color) { case cv::ccm::Macbeth: { - std::shared_ptr Macbeth_D50_2(new Color(ColorChecker2005_LAB_D50_2, Lab_D50_2, ColorChecker2005_COLORED_MASK)); + Mat ColorChecker2005_LAB_D50_2_ = GetColor::get_ColorChecker(*ColorChecker2005_LAB_D50_2,24); + Mat ColorChecker2005_COLORED_MASK_ = GetColor::get_ColorChecker_MASK(ColorChecker2005_COLORED_MASK,24); + std::shared_ptr Macbeth_D50_2(new Color(ColorChecker2005_LAB_D50_2_, Lab_D50_2, ColorChecker2005_COLORED_MASK_)); return *Macbeth_D50_2; break; } case cv::ccm::Vinyl: { - std::shared_ptr Vinyl_D50_2(new Color(Vinyl_LAB_D50_2, Lab_D50_2, Vinyl_COLORED_MASK)); + Mat Vinyl_LAB_D50_2__=GetColor::get_ColorChecker(*Vinyl_LAB_D50_2,18); + Mat Vinyl_COLORED_MASK__= GetColor::get_ColorChecker_MASK(Vinyl_COLORED_MASK,18); + std::shared_ptr Vinyl_D50_2(new Color(Vinyl_LAB_D50_2__, Lab_D50_2, Vinyl_COLORED_MASK__)); return *Vinyl_D50_2; break; } case cv::ccm::DigitalSG: { - std::shared_ptr DigitalSG_D50_2(new Color(DigitalSG_LAB_D50_2, Lab_D50_2)); + Mat DigitalSG_LAB_D50_2__= GetColor::get_ColorChecker(*DigitalSG_LAB_D50_2,140); + std::shared_ptr DigitalSG_D50_2(new Color( DigitalSG_LAB_D50_2__, Lab_D50_2)); return *DigitalSG_D50_2; break; } @@ -158,5 +180,6 @@ Color GetColor::get_color(CONST_COLOR const_color) { break; } } + } // namespace ccm } // namespace cv \ No newline at end of file diff --git a/modules/mcc/test/test_color.cpp b/modules/mcc/test/test_color.cpp index 2d0f027c077..26f65cd8efd 100644 --- a/modules/mcc/test/test_color.cpp +++ b/modules/mcc/test/test_color.cpp @@ -111,8 +111,11 @@ TEST(CV_ccmColor, test_lab) TEST(CV_ccmColor, test_grays) { - Color color_d50_2(ColorChecker2005_LAB_D50_2, Lab_D50_2); - Color color_d65_2(ColorChecker2005_LAB_D65_2, Lab_D65_2); + Mat ColorChecker2005_LAB_D50_2_test = GetColor::get_ColorChecker(*ColorChecker2005_LAB_D50_2,24); + Mat ColorChecker2005_LAB_D65_2_test = GetColor::get_ColorChecker(*ColorChecker2005_LAB_D65_2,24); + Color color_d50_2(ColorChecker2005_LAB_D50_2_test, Lab_D50_2); + + Color color_d65_2(ColorChecker2005_LAB_D65_2_test, Lab_D65_2); Mat grays = (Mat_(24, 1) << false, false, false, false, false, false, diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index 62d6480d053..b8096f81acc 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -196,64 +196,26 @@ Here are the parameters for ColorCorrectionModel ## Code -@include mcc/samples/color_correction_model.cpp +@snippet samples/color_correction_model.cpp tutorial ## Explanation - The first part is to detect the ColorChecker position. - -@code{.cpp}#include #include #include #include #include using namespace std;using namespace cv;using namespace mcc;using namespace ccm;using namespace std;@endcode - -``` -Here is sets of header and namespaces. You can set other namespace like the code above. -``` - -@code{.cpp} - -const char *about = "Basic chart detection";const char *keys = { "{ help h usage ? | | show this message }" "{t | | chartType: 0-Standard, 1-DigitalSG, 2-Vinyl }" "{v | | Input from video file, if ommited, input comes from camera }" "{ci | 0 | Camera id if input doesnt come from video (-v) }" - - "{f | 1 | Path of the file to process (-v) }" "{nc | 1 | Maximum number of charts in the image }"};@ endcode - -``` -Some arguments for ColorChecker detection. -``` - -@code{.cpp} CommandLineParser parser(argc, argv, keys); parser.about(about); int t = parser.get("t"); int nc = parser.get("nc"); string filepath = parser.get("f"); CV_Assert(0 <= t && t <= 2); TYPECHART chartType = TYPECHART(t); cout << "t: " << t << " , nc: " << nc << ", \nf: " << filepath << endl;if (!parser.check()){ parser.printErrors();return 0;} Mat image = cv::imread(filepath, IMREAD_COLOR);if (!image.data) { cout << "Invalid Image!" << endl; return 1; } @endcode - -``` +The first part is to detect the ColorChecker position. +@snippet samples/color_correction_model.cpp get_color_checker +@snippet samples/color_correction_model.cpp get_messages_of_image Preparation for ColorChecker detection to get messages for the image. -``` - -@code{.cpp}Mat imageCopy = image.clone(); - Ptr detector = CCheckerDetector::create(); if (!detector->process(image, chartType, nc)) { printf("ChartColor not detected \n"); return 2; } vector> checkers = detector->getListColorChecker();@endcode - -``` +@snippet samples/color_correction_model.cpp creat The CCheckerDetectorobject is created and uses getListColorChecker function to get ColorChecker message. -``` - -@code{.cpp} for (Ptr checker : checkers) { Ptr cdraw = CCheckerDraw::create(checker); cdraw->draw(image); Mat chartsRGB = checker->getChartsRGB();Mat src = chartsRGB.col(1).clone().reshape(3, 18); src /= 255.0; //compte color correction matrix ColorCorrectionModel model1(src, Vinyl);}@endcode -``` +@snippet samples/color_correction_model.cpp get_ccm_Matrix For every ColorChecker, we can compute a ccm matrix for color correction. Model1 is an object of ColorCorrectionModel class. The parameters should be changed to get the best effect of color correction. See other parameters' detail at the Parameters. -``` -@code{.cpp}cv::Mat ref = (Mat_(18, 1) < Date: Wed, 28 Oct 2020 09:21:25 +0800 Subject: [PATCH 38/71] remove array from color.h --- modules/mcc/include/opencv2/mcc/color.hpp | 227 +--------------------- modules/mcc/src/color.cpp | 203 +++++++++++++++++++ modules/mcc/test/test_color.cpp | 51 +++++ 3 files changed, 257 insertions(+), 224 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/color.hpp b/modules/mcc/include/opencv2/mcc/color.hpp index e4934728fa2..cf174c34afb 100644 --- a/modules/mcc/include/opencv2/mcc/color.hpp +++ b/modules/mcc/include/opencv2/mcc/color.hpp @@ -109,230 +109,6 @@ class CV_EXPORTS_W Color }; -/** @brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls - see Miscellaneous.md for details. -*/ -const double ColorChecker2005_LAB_D50_2 [24][3] = - { {37.986, 13.555, 14.059}, - {65.711, 18.13, 17.81}, - {49.927, -4.88, -21.925}, - {43.139, -13.095, 21.905}, - {55.112, 8.844, -25.399}, - {70.719, -33.397, -0.199}, - {62.661, 36.067, 57.096}, - {40.02, 10.41, -45.964}, - {51.124, 48.239, 16.248}, - {30.325, 22.976, -21.587}, - {72.532, -23.709, 57.255}, - {71.941, 19.363, 67.857}, - {28.778, 14.179, -50.297}, - {55.261, -38.342, 31.37}, - {42.101, 53.378, 28.19}, - {81.733, 4.039, 79.819}, - {51.935, 49.986, -14.574}, - {51.038, -28.631, -28.638}, - {96.539, -0.425, 1.186}, - {81.257, -0.638, -0.335}, - {66.766, -0.734, -0.504}, - {50.867, -0.153, -0.27}, - {35.656, -0.421, -1.231}, - {20.461, -0.079, -0.973}}; - -const double ColorChecker2005_LAB_D65_2[24][3]= - {{37.542, 12.018, 13.33}, - {65.2, 14.821, 17.545}, - {50.366, -1.573, -21.431}, - {43.125, -14.63, 22.12}, - {55.343, 11.449, -25.289}, - {71.36, -32.718, 1.636}, - {61.365, 32.885, 55.155}, - {40.712, 16.908, -45.085}, - {49.86, 45.934, 13.876}, - {30.15, 24.915, -22.606}, - {72.438, -27.464, 58.469}, - {70.916, 15.583, 66.543}, - {29.624, 21.425, -49.031}, - {55.643, -40.76, 33.274}, - {40.554, 49.972, 25.46}, - {80.982, -1.037, 80.03}, - {51.006, 49.876, -16.93}, - {52.121, -24.61, -26.176}, - {96.536, -0.694, 1.354}, - {81.274, -0.61, -0.24}, - {66.787, -0.647, -0.429}, - {50.872, -0.059, -0.247}, - {35.68, -0.22, -1.205}, - {20.475, 0.049, -0.972}}; - -const uchar ColorChecker2005_COLORED_MASK[24] = - {1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0}; -const double Vinyl_LAB_D50_2[18][3] = - { {100, 0.00520000001, -0.0104}, - {73.0833969, -0.819999993, -2.02099991}, - {62.493, 0.425999999, -2.23099995}, - {50.4640007, 0.446999997, -2.32399988}, - {37.7970009, 0.0359999985, -1.29700005}, - {0, 0, 0}, - {51.5880013, 73.5179977, 51.5690002}, - {93.6989975, -15.7340002, 91.9420013}, - {69.4079971, -46.5940018, 50.4869995}, - {66.61000060000001, -13.6789999, -43.1720009}, - {11.7110004, 16.9799995, -37.1759987}, - {51.973999, 81.9440002, -8.40699959}, - {40.5489998, 50.4399986, 24.8490009}, - {60.8160019, 26.0690002, 49.4420013}, - {52.2529984, -19.9500008, -23.9960003}, - {51.2859993, 48.4700012, -15.0579996}, - {68.70700069999999, 12.2959995, 16.2129993}, - {63.6839981, 10.2930002, 16.7639999}}; -const uchar Vinyl_COLORED_MASK[18]= - { 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1}; -const double DigitalSG_LAB_D50_2[140][3] = - { {96.55,-0.91,0.57}, - {6.43,-0.06,-0.41}, - {49.7,-0.18,0.03}, - {96.5,-0.89,0.59}, - {6.5,-0.06,-0.44}, - {49.66,-0.2,0.01}, - {96.52,-0.91,0.58}, - {6.49,-0.02,-0.28}, - {49.72,-0.2,0.04}, - {96.43,-0.91,0.67}, - {49.72,-0.19,0}, - {32.6,51.58,-10.85}, - {60.75,26.22,-18.6}, - {28.69,48.28,-39}, - {49.38,-15.43,-48.48}, - {60.63,-30.77,-26.23}, - {19.29,-26.37,-6.15}, - {60.15,-41.77,-12.6}, - {21.42,1.67,8.79}, - {49.69,-0.2,0.01}, - {6.5,-0.03,-0.67}, - {21.82,17.33,-18.35}, - {41.53,18.48,-37.26}, - {19.99,-0.16,-36.29}, - {60.16,-18.45,-31.42}, - {19.94,-17.92,-20.96}, - {60.68,-6.05,-32.81}, - {50.81,-49.8,-9.63}, - {60.65,-39.77,20.76}, - {6.53,-0.03,-0.43}, - {96.56,-0.91,0.59}, - {84.19,-1.95,-8.23}, - {84.75,14.55,0.23}, - {84.87,-19.07,-0.82}, - {85.15,13.48,6.82}, - {84.17,-10.45,26.78}, - {61.74,31.06,36.42}, - {64.37,20.82,18.92}, - {50.4,-53.22,14.62}, - {96.51,-0.89,0.65}, - {49.74,-0.19,0.03}, - {31.91,18.62,21.99}, - {60.74,38.66,70.97}, - {19.35,22.23,-58.86}, - {96.52,-0.91,0.62}, - {6.66,0,-0.3}, - {76.51,20.81,22.72}, - {72.79,29.15,24.18}, - {22.33,-20.7,5.75}, - {49.7,-0.19,0.01}, - {6.53,-0.05,-0.61}, - {63.42,20.19,19.22}, - {34.94,11.64,-50.7}, - {52.03,-44.15,39.04}, - {79.43,0.29,-0.17}, - {30.67,-0.14,-0.53}, - {63.6,14.44,26.07}, - {64.37,14.5,17.05}, - {60.01,-44.33,8.49}, - {6.63,-0.01,-0.47}, - {96.56,-0.93,0.59}, - {46.37,-5.09,-24.46}, - {47.08,52.97,20.49}, - {36.04,64.92,38.51}, - {65.05,0,-0.32}, - {40.14,-0.19,-0.38}, - {43.77,16.46,27.12}, - {64.39,17,16.59}, - {60.79,-29.74,41.5}, - {96.48,-0.89,0.64}, - {49.75,-0.21,0.01}, - {38.18,-16.99,30.87}, - {21.31,29.14,-27.51}, - {80.57,3.85,89.61}, - {49.71,-0.2,0.03}, - {60.27,0.08,-0.41}, - {67.34,14.45,16.9}, - {64.69,16.95,18.57}, - {51.12,-49.31,44.41}, - {49.7,-0.2,0.02}, - {6.67,-0.05,-0.64}, - {51.56,9.16,-26.88}, - {70.83,-24.26,64.77}, - {48.06,55.33,-15.61}, - {35.26,-0.09,-0.24}, - {75.16,0.25,-0.2}, - {44.54,26.27,38.93}, - {35.91,16.59,26.46}, - {61.49,-52.73,47.3}, - {6.59,-0.05,-0.5}, - {96.58,-0.9,0.61}, - {68.93,-34.58,-0.34}, - {69.65,20.09,78.57}, - {47.79,-33.18,-30.21}, - {15.94,-0.42,-1.2}, - {89.02,-0.36,-0.48}, - {63.43,25.44,26.25}, - {65.75,22.06,27.82}, - {61.47,17.1,50.72}, - {96.53,-0.89,0.66}, - {49.79,-0.2,0.03}, - {85.17,10.89,17.26}, - {89.74,-16.52,6.19}, - {84.55,5.07,-6.12}, - {84.02,-13.87,-8.72}, - {70.76,0.07,-0.35}, - {45.59,-0.05,0.23}, - {20.3,0.07,-0.32}, - {61.79,-13.41,55.42}, - {49.72,-0.19,0.02}, - {6.77,-0.05,-0.44}, - {21.85,34.37,7.83}, - {42.66,67.43,48.42}, - {60.33,36.56,3.56}, - {61.22,36.61,17.32}, - {62.07,52.8,77.14}, - {72.42,-9.82,89.66}, - {62.03,3.53,57.01}, - {71.95,-27.34,73.69}, - {6.59,-0.04,-0.45}, - {49.77,-0.19,0.04}, - {41.84,62.05,10.01}, - {19.78,29.16,-7.85}, - {39.56,65.98,33.71}, - {52.39,68.33,47.84}, - {81.23,24.12,87.51}, - {81.8,6.78,95.75}, - {71.72,-16.23,76.28}, - {20.31,14.45,16.74}, - {49.68,-0.19,0.05}, - {96.48,-0.88,0.68}, - {49.69,-0.18,0.03}, - {6.39,-0.04,-0.33}, - {96.54,-0.9,0.67}, - {49.72,-0.18,0.05}, - {6.49,-0.03,-0.41}, - {96.51,-0.9,0.69}, - {49.7,-0.19,0.07}, - {6.47,0,-0.38}, - {96.46,-0.89,0.7}}; /** @brief Macbeth and Vinyl ColorChecker with 2deg D50 . */ enum CONST_COLOR { @@ -343,10 +119,13 @@ enum CONST_COLOR { class CV_EXPORTS_W GetColor { public: static Color get_color(CONST_COLOR const_color); + static double create(); static Mat get_ColorChecker(const double *checker,int row); static Mat get_ColorChecker_MASK(const uchar *checker,int row); }; + + } // namespace ccm } // namespace cv diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index ac1f72cd801..e8c533cd447 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -132,6 +132,9 @@ Color Color::operator[](Mat mask) return Color(maskCopyTo(colors, mask), cs); } + + + Mat GetColor::get_ColorChecker(const double *checker,int row){ Mat res(row,1, CV_64FC3); for(int i = 0;i< row;++i) @@ -150,6 +153,206 @@ Mat GetColor::get_ColorChecker_MASK(const uchar *checker,int row){ } Color GetColor::get_color(CONST_COLOR const_color) { + + /** @brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls + see Miscellaneous.md for details. +*/ +const double ColorChecker2005_LAB_D50_2 [24][3] = + { {37.986, 13.555, 14.059}, + {65.711, 18.13, 17.81}, + {49.927, -4.88, -21.925}, + {43.139, -13.095, 21.905}, + {55.112, 8.844, -25.399}, + {70.719, -33.397, -0.199}, + {62.661, 36.067, 57.096}, + {40.02, 10.41, -45.964}, + {51.124, 48.239, 16.248}, + {30.325, 22.976, -21.587}, + {72.532, -23.709, 57.255}, + {71.941, 19.363, 67.857}, + {28.778, 14.179, -50.297}, + {55.261, -38.342, 31.37}, + {42.101, 53.378, 28.19}, + {81.733, 4.039, 79.819}, + {51.935, 49.986, -14.574}, + {51.038, -28.631, -28.638}, + {96.539, -0.425, 1.186}, + {81.257, -0.638, -0.335}, + {66.766, -0.734, -0.504}, + {50.867, -0.153, -0.27}, + {35.656, -0.421, -1.231}, + {20.461, -0.079, -0.973}}; + +const uchar ColorChecker2005_COLORED_MASK[24] = + {1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0}; +const double Vinyl_LAB_D50_2[18][3] = + { {100, 0.00520000001, -0.0104}, + {73.0833969, -0.819999993, -2.02099991}, + {62.493, 0.425999999, -2.23099995}, + {50.4640007, 0.446999997, -2.32399988}, + {37.7970009, 0.0359999985, -1.29700005}, + {0, 0, 0}, + {51.5880013, 73.5179977, 51.5690002}, + {93.6989975, -15.7340002, 91.9420013}, + {69.4079971, -46.5940018, 50.4869995}, + {66.61000060000001, -13.6789999, -43.1720009}, + {11.7110004, 16.9799995, -37.1759987}, + {51.973999, 81.9440002, -8.40699959}, + {40.5489998, 50.4399986, 24.8490009}, + {60.8160019, 26.0690002, 49.4420013}, + {52.2529984, -19.9500008, -23.9960003}, + {51.2859993, 48.4700012, -15.0579996}, + {68.70700069999999, 12.2959995, 16.2129993}, + {63.6839981, 10.2930002, 16.7639999}}; +const uchar Vinyl_COLORED_MASK[18]= + { 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1}; +const double DigitalSG_LAB_D50_2[140][3] = + { {96.55,-0.91,0.57}, + {6.43,-0.06,-0.41}, + {49.7,-0.18,0.03}, + {96.5,-0.89,0.59}, + {6.5,-0.06,-0.44}, + {49.66,-0.2,0.01}, + {96.52,-0.91,0.58}, + {6.49,-0.02,-0.28}, + {49.72,-0.2,0.04}, + {96.43,-0.91,0.67}, + {49.72,-0.19,0}, + {32.6,51.58,-10.85}, + {60.75,26.22,-18.6}, + {28.69,48.28,-39}, + {49.38,-15.43,-48.48}, + {60.63,-30.77,-26.23}, + {19.29,-26.37,-6.15}, + {60.15,-41.77,-12.6}, + {21.42,1.67,8.79}, + {49.69,-0.2,0.01}, + {6.5,-0.03,-0.67}, + {21.82,17.33,-18.35}, + {41.53,18.48,-37.26}, + {19.99,-0.16,-36.29}, + {60.16,-18.45,-31.42}, + {19.94,-17.92,-20.96}, + {60.68,-6.05,-32.81}, + {50.81,-49.8,-9.63}, + {60.65,-39.77,20.76}, + {6.53,-0.03,-0.43}, + {96.56,-0.91,0.59}, + {84.19,-1.95,-8.23}, + {84.75,14.55,0.23}, + {84.87,-19.07,-0.82}, + {85.15,13.48,6.82}, + {84.17,-10.45,26.78}, + {61.74,31.06,36.42}, + {64.37,20.82,18.92}, + {50.4,-53.22,14.62}, + {96.51,-0.89,0.65}, + {49.74,-0.19,0.03}, + {31.91,18.62,21.99}, + {60.74,38.66,70.97}, + {19.35,22.23,-58.86}, + {96.52,-0.91,0.62}, + {6.66,0,-0.3}, + {76.51,20.81,22.72}, + {72.79,29.15,24.18}, + {22.33,-20.7,5.75}, + {49.7,-0.19,0.01}, + {6.53,-0.05,-0.61}, + {63.42,20.19,19.22}, + {34.94,11.64,-50.7}, + {52.03,-44.15,39.04}, + {79.43,0.29,-0.17}, + {30.67,-0.14,-0.53}, + {63.6,14.44,26.07}, + {64.37,14.5,17.05}, + {60.01,-44.33,8.49}, + {6.63,-0.01,-0.47}, + {96.56,-0.93,0.59}, + {46.37,-5.09,-24.46}, + {47.08,52.97,20.49}, + {36.04,64.92,38.51}, + {65.05,0,-0.32}, + {40.14,-0.19,-0.38}, + {43.77,16.46,27.12}, + {64.39,17,16.59}, + {60.79,-29.74,41.5}, + {96.48,-0.89,0.64}, + {49.75,-0.21,0.01}, + {38.18,-16.99,30.87}, + {21.31,29.14,-27.51}, + {80.57,3.85,89.61}, + {49.71,-0.2,0.03}, + {60.27,0.08,-0.41}, + {67.34,14.45,16.9}, + {64.69,16.95,18.57}, + {51.12,-49.31,44.41}, + {49.7,-0.2,0.02}, + {6.67,-0.05,-0.64}, + {51.56,9.16,-26.88}, + {70.83,-24.26,64.77}, + {48.06,55.33,-15.61}, + {35.26,-0.09,-0.24}, + {75.16,0.25,-0.2}, + {44.54,26.27,38.93}, + {35.91,16.59,26.46}, + {61.49,-52.73,47.3}, + {6.59,-0.05,-0.5}, + {96.58,-0.9,0.61}, + {68.93,-34.58,-0.34}, + {69.65,20.09,78.57}, + {47.79,-33.18,-30.21}, + {15.94,-0.42,-1.2}, + {89.02,-0.36,-0.48}, + {63.43,25.44,26.25}, + {65.75,22.06,27.82}, + {61.47,17.1,50.72}, + {96.53,-0.89,0.66}, + {49.79,-0.2,0.03}, + {85.17,10.89,17.26}, + {89.74,-16.52,6.19}, + {84.55,5.07,-6.12}, + {84.02,-13.87,-8.72}, + {70.76,0.07,-0.35}, + {45.59,-0.05,0.23}, + {20.3,0.07,-0.32}, + {61.79,-13.41,55.42}, + {49.72,-0.19,0.02}, + {6.77,-0.05,-0.44}, + {21.85,34.37,7.83}, + {42.66,67.43,48.42}, + {60.33,36.56,3.56}, + {61.22,36.61,17.32}, + {62.07,52.8,77.14}, + {72.42,-9.82,89.66}, + {62.03,3.53,57.01}, + {71.95,-27.34,73.69}, + {6.59,-0.04,-0.45}, + {49.77,-0.19,0.04}, + {41.84,62.05,10.01}, + {19.78,29.16,-7.85}, + {39.56,65.98,33.71}, + {52.39,68.33,47.84}, + {81.23,24.12,87.51}, + {81.8,6.78,95.75}, + {71.72,-16.23,76.28}, + {20.31,14.45,16.74}, + {49.68,-0.19,0.05}, + {96.48,-0.88,0.68}, + {49.69,-0.18,0.03}, + {6.39,-0.04,-0.33}, + {96.54,-0.9,0.67}, + {49.72,-0.18,0.05}, + {6.49,-0.03,-0.41}, + {96.51,-0.9,0.69}, + {49.7,-0.19,0.07}, + {6.47,0,-0.38}, + {96.46,-0.89,0.7}}; + switch (const_color) { case cv::ccm::Macbeth: diff --git a/modules/mcc/test/test_color.cpp b/modules/mcc/test/test_color.cpp index 26f65cd8efd..83469f7ea92 100644 --- a/modules/mcc/test/test_color.cpp +++ b/modules/mcc/test/test_color.cpp @@ -111,6 +111,57 @@ TEST(CV_ccmColor, test_lab) TEST(CV_ccmColor, test_grays) { + const double ColorChecker2005_LAB_D50_2 [24][3] = + { {37.986, 13.555, 14.059}, + {65.711, 18.13, 17.81}, + {49.927, -4.88, -21.925}, + {43.139, -13.095, 21.905}, + {55.112, 8.844, -25.399}, + {70.719, -33.397, -0.199}, + {62.661, 36.067, 57.096}, + {40.02, 10.41, -45.964}, + {51.124, 48.239, 16.248}, + {30.325, 22.976, -21.587}, + {72.532, -23.709, 57.255}, + {71.941, 19.363, 67.857}, + {28.778, 14.179, -50.297}, + {55.261, -38.342, 31.37}, + {42.101, 53.378, 28.19}, + {81.733, 4.039, 79.819}, + {51.935, 49.986, -14.574}, + {51.038, -28.631, -28.638}, + {96.539, -0.425, 1.186}, + {81.257, -0.638, -0.335}, + {66.766, -0.734, -0.504}, + {50.867, -0.153, -0.27}, + {35.656, -0.421, -1.231}, + {20.461, -0.079, -0.973}}; + +const double ColorChecker2005_LAB_D65_2[24][3]= + {{37.542, 12.018, 13.33}, + {65.2, 14.821, 17.545}, + {50.366, -1.573, -21.431}, + {43.125, -14.63, 22.12}, + {55.343, 11.449, -25.289}, + {71.36, -32.718, 1.636}, + {61.365, 32.885, 55.155}, + {40.712, 16.908, -45.085}, + {49.86, 45.934, 13.876}, + {30.15, 24.915, -22.606}, + {72.438, -27.464, 58.469}, + {70.916, 15.583, 66.543}, + {29.624, 21.425, -49.031}, + {55.643, -40.76, 33.274}, + {40.554, 49.972, 25.46}, + {80.982, -1.037, 80.03}, + {51.006, 49.876, -16.93}, + {52.121, -24.61, -26.176}, + {96.536, -0.694, 1.354}, + {81.274, -0.61, -0.24}, + {66.787, -0.647, -0.429}, + {50.872, -0.059, -0.247}, + {35.68, -0.22, -1.205}, + {20.475, 0.049, -0.972}}; Mat ColorChecker2005_LAB_D50_2_test = GetColor::get_ColorChecker(*ColorChecker2005_LAB_D50_2,24); Mat ColorChecker2005_LAB_D65_2_test = GetColor::get_ColorChecker(*ColorChecker2005_LAB_D65_2,24); Color color_d50_2(ColorChecker2005_LAB_D50_2_test, Lab_D50_2); From 9877d1aca48e33338662741dcf3cbc2f6711bb91 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Sun, 8 Nov 2020 16:49:14 +0800 Subject: [PATCH 39/71] remove hpp from include/mcc/ --- modules/mcc/include/opencv2/mcc/ccm.hpp | 311 ++++++++----- modules/mcc/include/opencv2/mcc/color.hpp | 133 ------ .../mcc/include/opencv2/mcc/colorspace.hpp | 430 ------------------ modules/mcc/include/opencv2/mcc/distance.hpp | 116 ----- modules/mcc/include/opencv2/mcc/io.hpp | 82 ---- modules/mcc/include/opencv2/mcc/linearize.hpp | 235 ---------- .../mcc/include/opencv2/mcc/operations.hpp | 100 ---- modules/mcc/include/opencv2/mcc/utils.hpp | 153 ------- modules/mcc/src/ccm.cpp | 363 ++++++++++++--- modules/mcc/src/color.cpp | 6 +- modules/mcc/src/colorspace.cpp | 4 +- modules/mcc/src/distance.cpp | 3 +- modules/mcc/src/io.cpp | 2 +- modules/mcc/src/linearize.cpp | 2 +- modules/mcc/src/operations.cpp | 4 +- modules/mcc/src/utils.cpp | 2 +- modules/mcc/test/test_ccm.cpp | 148 ------ modules/mcc/test/test_color.cpp | 219 --------- modules/mcc/test/test_colorspace.cpp | 69 --- modules/mcc/test/test_linearize.cpp | 232 ---------- modules/mcc/test/test_utils.cpp | 47 -- 21 files changed, 508 insertions(+), 2153 deletions(-) delete mode 100644 modules/mcc/include/opencv2/mcc/color.hpp delete mode 100644 modules/mcc/include/opencv2/mcc/colorspace.hpp delete mode 100644 modules/mcc/include/opencv2/mcc/distance.hpp delete mode 100644 modules/mcc/include/opencv2/mcc/io.hpp delete mode 100644 modules/mcc/include/opencv2/mcc/linearize.hpp delete mode 100644 modules/mcc/include/opencv2/mcc/operations.hpp delete mode 100644 modules/mcc/include/opencv2/mcc/utils.hpp delete mode 100644 modules/mcc/test/test_ccm.cpp delete mode 100644 modules/mcc/test/test_color.cpp delete mode 100644 modules/mcc/test/test_colorspace.cpp delete mode 100644 modules/mcc/test/test_linearize.cpp delete mode 100644 modules/mcc/test/test_utils.cpp diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index a4b738ff1f7..a9455559a91 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -34,7 +34,7 @@ #include #include #include -#include "opencv2/mcc/linearize.hpp" +// #include "opencv2/mcc/linearize.hpp" namespace cv { @@ -231,7 +231,78 @@ enum INITIAL_METHOD_TYPE WHITE_BALANCE, LEAST_SQUARE }; + /** @brief Macbeth and Vinyl ColorChecker with 2deg D50 . + */ +enum CONST_COLOR { + Macbeth, + Vinyl, + DigitalSG +}; +enum COLOR_SPACE { + sRGB, + sRGBL, + AdobeRGB, + AdobeRGBL, + WideGamutRGB, + WideGamutRGBL, + ProPhotoRGB, + ProPhotoRGBL, + DCI_P3_RGB, + DCI_P3_RGBL, + AppleRGB, + AppleRGBL, + REC_709_RGB, + REC_709_RGBL, + REC_2020_RGB, + REC_2020_RGBL, + XYZ_D65_2, + XYZ_D65_10, + XYZ_D50_2, + XYZ_D50_10, + XYZ_A_2, + XYZ_A_10, + XYZ_D55_2, + XYZ_D55_10, + XYZ_D75_2, + XYZ_D75_10, + XYZ_E_2, + XYZ_E_10, + Lab_D65_2, + Lab_D65_10, + Lab_D50_2, + Lab_D50_10, + Lab_A_2, + Lab_A_10, + Lab_D55_2, + Lab_D55_10, + Lab_D75_2, + Lab_D75_10, + Lab_E_2, + Lab_E_10 +}; +enum LINEAR_TYPE +{ + IDENTITY_, + GAMMA, + COLORPOLYFIT, + COLORLOGPOLYFIT, + GRAYPOLYFIT, + GRAYLOGPOLYFIT +}; +/** @brief Enum of possibale functions to calculate the distance between + colors.see https://en.wikipedia.org/wiki/Color_difference for details;*/ +enum DISTANCE_TYPE +{ + CIE76, + CIE94_GRAPHIC_ARTS, + CIE94_TEXTILES, + CIE2000, + CMC_1TO1, + CMC_2TO1, + RGB, + RGBL +}; /** @brief Core class of ccm model. produce a ColorCorrectionModel instance for inference. @@ -240,129 +311,133 @@ enum INITIAL_METHOD_TYPE class CV_EXPORTS_W ColorCorrectionModel { public: - // detected colors, the referenceand the RGB colorspace for conversion - Mat src; - Color dst; - Mat dist; - RGBBase_& cs; - Mat mask; - - // RGBl of detected data and the reference - Mat src_rgbl; - Mat dst_rgbl; - - // ccm type and shape - CCM_TYPE ccm_type; - int shape; - - // linear method and distance - std::shared_ptr linear; - DISTANCE_TYPE distance; - - Mat weights; - Mat ccm; - Mat ccm0; - int masked_len; - double loss; - int max_count; - double epsilon; - ColorCorrectionModel(Mat src_, CONST_COLOR constcolor, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, - double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, - INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); - - ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE ref_cs_, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, - double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, - INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); - - ColorCorrectionModel(Mat src_, Color dst_, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, - double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, - INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); - - ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_ , CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, - double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, - INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); - - - /** @brief Make no change for CCM_3x3. - convert cv::Mat A to [A, 1] in CCM_4x3. - @param inp the input array, type of cv::Mat. - @return the output array, type of cv::Mat - */ - Mat prepare(const Mat& inp); - - /** @brief Calculate weights and mask. - @param weights_list the input array, type of cv::Mat. - @param weights_coeff type of double. - @param saturate_mask the input array, type of cv::Mat. - */ - void calWeightsMasks(Mat weights_list, double weights_coeff, Mat saturate_mask); + class Impl; + Ptr p; + ColorCorrectionModel(Mat src_, CONST_COLOR constcolor); + ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE ref_cs_); + ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE cs_, Mat colored_); + void setColorSpace(COLOR_SPACE cs_); + void setCCM(CCM_TYPE ccm_type_); + void setDistance(DISTANCE_TYPE distance_); + void setLinear(LINEAR_TYPE linear_type); + void setLinearGamma(double gamma); + void setLinearDegree(int deg); + void setSaturatedThreshold(double lower, double upper);//std::vector saturated_threshold + void setWeightsList(Mat weights_list); + void setWeightCoeff(double weights_coeff); + void setInitialMethod(INITIAL_METHOD_TYPE initial_method_type); + void setMaxCount(int max_count_); + void setEpsilon(double epsilon_); + bool run(); + // /** @brief Infer using fitting ccm. + // @param img the input image, type of cv::Mat. + // @param islinear default false. + // @return the output array, type of cv::Mat. + // */ + Mat infer(const Mat& img, bool islinear = false); - /** @brief Fitting nonlinear - optimization initial value by white balance. - see CCM.pdf for details. - @return the output array, type of Mat - */ - void initialWhiteBalance(void); - /** @brief Fitting nonlinear-optimization initial value by least square. - see CCM.pdf for details - @param fit if fit is True, return optimalization for rgbl distance function. - */ - void initialLeastSquare(bool fit = false); - double calc_loss_(Color color); - double calc_loss(const Mat ccm_); - /** @brief Fitting ccm if distance function is associated with CIE Lab color space. - see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp - Set terminal criteria for solver is possible. - */ - void fitting(void); - /** @brief Infer using fitting ccm. - @param img the input image, type of cv::Mat. - @param islinear default false. - @return the output array, type of cv::Mat. - */ - Mat infer(const Mat& img, bool islinear = false); - - /** @brief Infer image and output as an BGR image with uint8 type. - mainly for test or debug. - input size and output size should be 255. - @param img_ image to infer, type of cv::Mat. - @param islinear if linearize or not. - @return the output array, type of cv::Mat. - */ - Mat inferImage(Mat& img_, bool islinear = false); + // ColorCorrectionModel(Mat src_, CONST_COLOR constcolor, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + // double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, + // INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); + + // ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE ref_cs_, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + // double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, + // INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); + + // ColorCorrectionModel(Mat src_, Color dst_, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + // double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, + // INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); + + // ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_ , CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, + // double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, + // INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); + + + // /** @brief Make no change for CCM_3x3. + // convert cv::Mat A to [A, 1] in CCM_4x3. + // @param inp the input array, type of cv::Mat. + // @return the output array, type of cv::Mat + // */ + // Mat prepare(const Mat& inp); + + // /** @brief Calculate weights and mask. + // @param weights_list the input array, type of cv::Mat. + // @param weights_coeff type of double. + // @param saturate_mask the input array, type of cv::Mat. + // */ + // void calWeightsMasks(Mat weights_list, double weights_coeff, Mat saturate_mask); + + // /** @brief Fitting nonlinear - optimization initial value by white balance. + // see CCM.pdf for details. + // @return the output array, type of Mat + // */ + // void initialWhiteBalance(void); + + // /** @brief Fitting nonlinear-optimization initial value by least square. + // see CCM.pdf for details + // @param fit if fit is True, return optimalization for rgbl distance function. + // */ + // void initialLeastSquare(bool fit = false); + + // double calc_loss_(Color color); + // double calc_loss(const Mat ccm_); + + // /** @brief Fitting ccm if distance function is associated with CIE Lab color space. + // see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp + // Set terminal criteria for solver is possible. + // */ + // void fitting(void); + + // /** @brief Infer using fitting ccm. + // @param img the input image, type of cv::Mat. + // @param islinear default false. + // @return the output array, type of cv::Mat. + // */ + // Mat infer(const Mat& img, bool islinear = false); + + // /** @brief Infer image and output as an BGR image with uint8 type. + // mainly for test or debug. + // input size and output size should be 255. + // @param img_ image to infer, type of cv::Mat. + // @param islinear if linearize or not. + // @return the output array, type of cv::Mat. + // */ + // Mat inferImage(Mat& img_, bool islinear = false); + + // /** @brief Loss function base on cv::MinProblemSolver::Function. + // see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp + // */ + // class LossFunction : public MinProblemSolver::Function + // { + // public: + // ColorCorrectionModel* ccm_loss; + // LossFunction(ColorCorrectionModel* ccm) : ccm_loss(ccm) {}; + + // /** @brief Reset dims to ccm->shape. + // */ + // int getDims() const CV_OVERRIDE + // { + // return ccm_loss->shape; + // } + + // /** @brief Reset calculation. + // */ + // double calc(const double* x) const CV_OVERRIDE + // { + // Mat ccm_(ccm_loss->shape, 1, CV_64F); + // for (int i = 0; i < ccm_loss->shape; i++) + // { + // ccm_.at(i, 0) = x[i]; + // } + // ccm_ = ccm_.reshape(0, ccm_loss->shape / 3); + // return ccm_loss->calc_loss(ccm_); + // } + // }; - /** @brief Loss function base on cv::MinProblemSolver::Function. - see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp - */ - class LossFunction : public MinProblemSolver::Function - { - public: - ColorCorrectionModel* ccm_loss; - LossFunction(ColorCorrectionModel* ccm) : ccm_loss(ccm) {}; - - /** @brief Reset dims to ccm->shape. - */ - int getDims() const CV_OVERRIDE - { - return ccm_loss->shape; - } - - /** @brief Reset calculation. - */ - double calc(const double* x) const CV_OVERRIDE - { - Mat ccm_(ccm_loss->shape, 1, CV_64F); - for (int i = 0; i < ccm_loss->shape; i++) - { - ccm_.at(i, 0) = x[i]; - } - ccm_ = ccm_.reshape(0, ccm_loss->shape / 3); - return ccm_loss->calc_loss(ccm_); - } - }; }; } // namespace ccm diff --git a/modules/mcc/include/opencv2/mcc/color.hpp b/modules/mcc/include/opencv2/mcc/color.hpp deleted file mode 100644 index cf174c34afb..00000000000 --- a/modules/mcc/include/opencv2/mcc/color.hpp +++ /dev/null @@ -1,133 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. -// Third party copyrights are property of their respective owners. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Author: Longbu Wang -// Jinheng Zhang -// Chenqi Shan - -#ifndef __OPENCV_MCC_COLOR_HPP__ -#define __OPENCV_MCC_COLOR_HPP__ - -#include -#include "opencv2/mcc/colorspace.hpp" -#include "opencv2/mcc/distance.hpp" - -namespace cv -{ -namespace ccm -{ - -/** @brief Color defined by color_values and color space -*/ - -class CV_EXPORTS_W Color -{ -public: - - /** @param grays mask of grayscale color - @param colored mask of colored color - @param history storage of historical conversion - */ - Mat colors; - const ColorSpace& cs; - Mat grays; - Mat colored; - std::map> history; - Color(Mat colors_, enum COLOR_SPACE cs_); - Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_); - // Color(double *colors_,int row,int col, enum COLOR_SPACE cs_); - Color(Mat colors_, const ColorSpace& cs_, Mat colored_); - Color(Mat colors_, const ColorSpace& cs_); - - virtual ~Color() {}; - - /** @brief Change to other color space. - The conversion process incorporates linear transformations to speed up. - @param other type of ColorSpace. - @param method the chromatic adapation method. - @param save when save if True, get data from history first. - @return Color. - */ - Color to(COLOR_SPACE other, CAM method = BRADFORD, bool save = true); - Color to(const ColorSpace& other, CAM method = BRADFORD, bool save = true); - /** @brief Channels split. - @return each channel. - */ - Mat channel(Mat m, int i); - - /** @brief To Gray. - */ - Mat toGray(IO io, CAM method = BRADFORD, bool save = true); - - /** @brief To Luminant. - */ - Mat toLuminant(IO io, CAM method = BRADFORD, bool save = true); - - /** @brief Diff without IO. - @param other type of Color. - @param method type of distance. - @return distance between self and other - */ - Mat diff(Color& other, DISTANCE_TYPE method = CIE2000); - - /** @brief Diff with IO. - @param other type of Color. - @param io type of IO. - @param method type of distance. - @return distance between self and other - */ - Mat diff(Color& other, IO io, DISTANCE_TYPE method = CIE2000); - - /** @brief Calculate gray mask. - */ - void getGray(double JDN = 2.0); - - /** @brief Operator for mask copy. - */ - Color operator[](Mat mask); - -}; - - -/** @brief Macbeth and Vinyl ColorChecker with 2deg D50 . -*/ -enum CONST_COLOR { - Macbeth, - Vinyl, - DigitalSG -}; -class CV_EXPORTS_W GetColor { -public: - static Color get_color(CONST_COLOR const_color); - static double create(); - static Mat get_ColorChecker(const double *checker,int row); - static Mat get_ColorChecker_MASK(const uchar *checker,int row); -}; - - - -} // namespace ccm -} // namespace cv - - -#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/colorspace.hpp b/modules/mcc/include/opencv2/mcc/colorspace.hpp deleted file mode 100644 index 118b88d5163..00000000000 --- a/modules/mcc/include/opencv2/mcc/colorspace.hpp +++ /dev/null @@ -1,430 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. -// Third party copyrights are property of their respective owners. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Author: Longbu Wang -// Jinheng Zhang -// Chenqi Shan - - -#ifndef __OPENCV_MCC_COLORSPACE_HPP__ -#define __OPENCV_MCC_COLORSPACE_HPP__ - -#include -#include -#include -#include "opencv2/mcc/io.hpp" -#include "opencv2/mcc/operations.hpp" - -namespace cv -{ -namespace ccm -{ - -/** Supported Color Space. -*/ -enum COLOR_SPACE { - sRGB, - sRGBL, - AdobeRGB, - AdobeRGBL, - WideGamutRGB, - WideGamutRGBL, - ProPhotoRGB, - ProPhotoRGBL, - DCI_P3_RGB, - DCI_P3_RGBL, - AppleRGB, - AppleRGBL, - REC_709_RGB, - REC_709_RGBL, - REC_2020_RGB, - REC_2020_RGBL, - XYZ_D65_2, - XYZ_D65_10, - XYZ_D50_2, - XYZ_D50_10, - XYZ_A_2, - XYZ_A_10, - XYZ_D55_2, - XYZ_D55_10, - XYZ_D75_2, - XYZ_D75_10, - XYZ_E_2, - XYZ_E_10, - Lab_D65_2, - Lab_D65_10, - Lab_D50_2, - Lab_D50_10, - Lab_A_2, - Lab_A_10, - Lab_D55_2, - Lab_D55_10, - Lab_D75_2, - Lab_D75_10, - Lab_E_2, - Lab_E_10 -}; - -/** @brief Basic class for ColorSpace. -*/ -class CV_EXPORTS_W ColorSpace -{ -public: - IO io; - std::string type; - bool linear; - Operations to; - Operations from; - ColorSpace* l; - ColorSpace* nl; - - ColorSpace() {}; - - ColorSpace(IO io_, std::string type_, bool linear_) :io(io_), type(type_), linear(linear_) {}; - - virtual ~ColorSpace() - { - l = 0; - nl = 0; - }; - virtual bool relate(const ColorSpace& other) const; - - virtual Operations relation(const ColorSpace& /*other*/) const; - - bool operator<(const ColorSpace& other)const; - -}; - -/** @brief Base of RGB color space; - the argument values are from AdobeRGB; - Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space -*/ - -class CV_EXPORTS_W RGBBase_ : public ColorSpace -{ -public: - // primaries - double xr; - double yr; - double xg; - double yg; - double xb; - double yb; - MatFunc toL; - MatFunc fromL; - Mat M_to; - Mat M_from; - - using ColorSpace::ColorSpace; - - /** @brief There are 3 kinds of relationships for RGB: - 1. Different types; - no operation - 1. Same type, same linear; - copy - 2. Same type, different linear, self is nonlinear; - 2 toL - 3. Same type, different linear, self is linear - 3 fromL - @param other type of ColorSpace. - @return Operations. - */ - Operations relation(const ColorSpace& other) const CV_OVERRIDE; - - /** @brief Initial operations. - */ - void init(); - /** @brief Produce color space instance with linear and non-linear versions. - @param rgbl type of RGBBase_. - */ - void bind(RGBBase_& rgbl); - -private: - virtual void setParameter() {}; - - /** @brief Calculation of M_RGBL2XYZ_base. - see ColorSpace.pdf for details. - */ - virtual void calM(); - - /** @brief operations to or from XYZ. - */ - virtual void calOperations(); - - virtual void calLinear() {}; - - virtual Mat toLFunc(Mat& /*rgb*/); - - virtual Mat fromLFunc(Mat& /*rgbl*/); - - -}; - -/** @brief Base of Adobe RGB color space; -*/ -class CV_EXPORTS_W AdobeRGBBase_ : public RGBBase_ - -{ -public: - using RGBBase_::RGBBase_; - double gamma; - -private: - Mat toLFunc(Mat& rgb) CV_OVERRIDE; - Mat fromLFunc(Mat& rgbl) CV_OVERRIDE; -}; - -/** @brief Base of sRGB color space; -*/ -class CV_EXPORTS_W sRGBBase_ : public RGBBase_ - -{ -public: - using RGBBase_::RGBBase_; - double a; - double gamma; - double alpha; - double beta; - double phi; - double K0; - -private: - /** @brief linearization parameters - see ColorSpace.pdf for details; - */ - virtual void calLinear() CV_OVERRIDE; - /** @brief Used by toLFunc. - */ - double toLFuncEW(double& x); - - /** @brief Linearization. - see ColorSpace.pdf for details. - @param rgb the input array, type of cv::Mat. - @return the output array, type of cv::Mat. - */ - Mat toLFunc(Mat& rgb) CV_OVERRIDE; - - /** @brief Used by fromLFunc. - */ - double fromLFuncEW(double& x); - - /** @brief Delinearization. - see ColorSpace.pdf for details. - @param rgbl the input array, type of cv::Mat. - @return the output array, type of cv::Mat. - */ - Mat fromLFunc(Mat& rgbl) CV_OVERRIDE; - -}; - -/** @brief sRGB color space. - data from https://en.wikipedia.org/wiki/SRGB. -*/ -class CV_EXPORTS_W sRGB_ :public sRGBBase_ - -{ -public: - sRGB_(bool linear_) :sRGBBase_(D65_2, "sRGB", linear_) {}; - -private: - void setParameter() CV_OVERRIDE; -}; - -/** @brief Adobe RGB color space. -*/ -class CV_EXPORTS_W AdobeRGB_ : public AdobeRGBBase_ -{ -public: - AdobeRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AdobeRGB", linear_) {}; - -private: - void setParameter() CV_OVERRIDE; - -}; - -/** @brief Wide-gamut RGB color space. - data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. -*/ -class CV_EXPORTS_W WideGamutRGB_ : public AdobeRGBBase_ -{ -public: - WideGamutRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "WideGamutRGB", linear_) {}; - -private: - void setParameter() CV_OVERRIDE; -}; - -/** @brief ProPhoto RGB color space. - data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. -*/ - -class CV_EXPORTS_W ProPhotoRGB_ : public AdobeRGBBase_ -{ -public: - ProPhotoRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "ProPhotoRGB", linear_) {}; - -private: - void setParameter() CV_OVERRIDE; -}; - -/** @brief DCI-P3 RGB color space. - data from https://en.wikipedia.org/wiki/DCI-P3. -*/ -class CV_EXPORTS_W DCI_P3_RGB_ : public AdobeRGBBase_ -{ -public: - DCI_P3_RGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "DCI_P3_RGB", linear_) {}; - -private: - void setParameter() CV_OVERRIDE; -}; - -/** @brief Apple RGB color space. - data from http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. -*/ -class CV_EXPORTS_W AppleRGB_ : public AdobeRGBBase_ -{ -public: - AppleRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AppleRGB", linear_) {}; - -private: - void setParameter() CV_OVERRIDE; -}; - -/** @brief REC_709 RGB color space. - data from https://en.wikipedia.org/wiki/Rec._709. -*/ -class CV_EXPORTS_W REC_709_RGB_ : public sRGBBase_ -{ -public: - REC_709_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_709_RGB", linear_) {}; - -private: - void setParameter() CV_OVERRIDE; -}; - -/** @brief REC_2020 RGB color space. - data from https://en.wikipedia.org/wiki/Rec._2020. -*/ -class CV_EXPORTS_W REC_2020_RGB_ : public sRGBBase_ -{ -public: - REC_2020_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_2020_RGB", linear_) {}; - -private: - void setParameter() CV_OVERRIDE; -}; - - -/** @brief Enum of the possible types of CAMs. -*/ -enum CAM -{ - IDENTITY, - VON_KRIES, - BRADFORD -}; - -static std::map , Mat > cams; -const static Mat Von_Kries = (Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); -const static Mat Bradford = (Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); -const static std::map > MAs = { - {IDENTITY , { Mat::eye(Size(3,3),CV_64FC1) , Mat::eye(Size(3,3),CV_64FC1)} }, - {VON_KRIES, { Von_Kries ,Von_Kries.inv() }}, - {BRADFORD, { Bradford ,Bradford.inv() }} -}; - -/** @brief XYZ color space. - Chromatic adaption matrices. -*/ -class CV_EXPORTS_W XYZ :public ColorSpace -{ -public: - XYZ(IO io_) : ColorSpace(io_, "XYZ", true) {}; - Operations cam(IO dio, CAM method = BRADFORD); - static std::map > xyz_cs; - static std::shared_ptr get(IO io); - -private: - /** @brief Get cam. - @param sio the input IO of src. - @param dio the input IO of dst. - @param method type of CAM. - @return the output array, type of cv::Mat. - */ - Mat cam_(IO sio, IO dio, CAM method = BRADFORD) const; -}; - -/** @brief Define XYZ_D65_2 and XYZ_D50_2. -*/ -const XYZ XYZ_D65_2_CS(D65_2); -const XYZ XYZ_D50_2_CS(D50_2); - -/** @brief Lab color space. -*/ -class CV_EXPORTS_W Lab :public ColorSpace -{ -public: - static std::map > lab_cs; - Lab(IO io_); - static std::shared_ptr get(IO io); - -private: - static constexpr double delta = (6. / 29.); - static constexpr double m = 1. / (3. * delta * delta); - static constexpr double t0 = delta * delta * delta; - static constexpr double c = 4. / 29.; - - Vec3d fromxyz(Vec3d& xyz); - - - /** @brief Calculate From. - @param src the input array, type of cv::Mat. - @return the output array, type of cv::Mat - */ - Mat fromsrc(Mat& src); - - Vec3d tolab(Vec3d& lab); - - /** @brief Calculate To. - @param src the input array, type of cv::Mat. - @return the output array, type of cv::Mat - */ - Mat tosrc(Mat& src); -}; - -/** @brief Define Lab_D65_2 and Lab_D50_2. -*/ -const Lab Lab_D65_2_CS(D65_2); -const Lab Lab_D50_2_CS(D50_2); - -//static std::map map_cs ; - -class CV_EXPORTS_W GetCS { -public: - static std::map > map_cs; - static std::shared_ptr get_rgb(enum COLOR_SPACE cs_name); - static std::shared_ptr get_cs(enum COLOR_SPACE cs_name); -}; - - -} // namespace ccm -} // namespace cv - -#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/distance.hpp b/modules/mcc/include/opencv2/mcc/distance.hpp deleted file mode 100644 index aaf9ff514b3..00000000000 --- a/modules/mcc/include/opencv2/mcc/distance.hpp +++ /dev/null @@ -1,116 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. -// Third party copyrights are property of their respective owners. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Author: Longbu Wang -// Jinheng Zhang -// Chenqi Shan - -#ifndef __OPENCV_MCC_DISTANCE_HPP__ -#define __OPENCV_MCC_DISTANCE_HPP__ - -#include "opencv2/mcc/utils.hpp" - -namespace cv -{ -namespace ccm -{ - -/** @brief Enum of possibale functions to calculate the distance between - colors.see https://en.wikipedia.org/wiki/Color_difference for details;*/ -enum DISTANCE_TYPE -{ - CIE76, - CIE94_GRAPHIC_ARTS, - CIE94_TEXTILES, - CIE2000, - CMC_1TO1, - CMC_2TO1, - RGB, - RGBL -}; - - -/** @brief distance between two points in formula CIE76 - @param lab1 a 3D vector - @param lab2 a 3D vector - @return distance between lab1 and lab2 -*/ - -double deltaCIE76(Vec3d lab1, Vec3d lab2); - -/** @brief distance between two points in formula CIE94 - @param lab1 a 3D vector - @param lab2 a 3D vector - @param kH Hue scale - @param kC Chroma scale - @param kL Lightness scale - @param k1 first scale parameter - @param k2 second scale parameter - @return distance between lab1 and lab2 -*/ - -double deltaCIE94(Vec3d lab1, Vec3d lab2, double kH = 1.0, - double kC = 1.0, double kL = 1.0, double k1 = 0.045, - double k2 = 0.015); - -double deltaCIE94GraphicArts(Vec3d lab1, Vec3d lab2); - -double toRad(double degree); - -double deltaCIE94Textiles(Vec3d lab1, Vec3d lab2); - - -/** @brief distance between two points in formula CIE2000 - @param lab1 a 3D vector - @param lab2 a 3D vector - @param kL Lightness scale - @param kC Chroma scale - @param kH Hue scale - @return distance between lab1 and lab2 -*/ -double deltaCIEDE2000_(Vec3d lab1, Vec3d lab2, double kL = 1.0, - double kC = 1.0, double kH = 1.0); -double deltaCIEDE2000(Vec3d lab1, Vec3d lab2); - - -/** @brief distance between two points in formula CMC - @param lab1 a 3D vector - @param lab2 a 3D vector - @param kL Lightness scale - @param kC Chroma scale - @return distance between lab1 and lab2 -*/ - -double deltaCMC(Vec3d lab1, Vec3d lab2, double kL = 1, double kC = 1); - -double deltaCMC1To1(Vec3d lab1, Vec3d lab2); - -double deltaCMC2To1(Vec3d lab1, Vec3d lab2); - -Mat distance(Mat src, Mat ref, DISTANCE_TYPE distance_type); - -} // namespace ccm -} // namespace cv - - -#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/io.hpp b/modules/mcc/include/opencv2/mcc/io.hpp deleted file mode 100644 index 0b44a8561a2..00000000000 --- a/modules/mcc/include/opencv2/mcc/io.hpp +++ /dev/null @@ -1,82 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. -// Third party copyrights are property of their respective owners. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Author: Longbu Wang -// Jinheng Zhang -// Chenqi Shan - - -#ifndef __OPENCV_MCC_IO_HPP__ -#define __OPENCV_MCC_IO_HPP__ - - -#include -#include - - -namespace cv -{ -namespace ccm -{ - -/** @brief Io is the meaning of illuminant and observer. See notes of ccm.hpp - for supported list for illuminant and observer*/ -class CV_EXPORTS_W IO -{ -public: - std::string illuminant; - std::string observer; - IO(){}; - IO(std::string illuminant_, std::string observer_) ; - virtual ~IO(){}; - bool operator<(const IO& other) const; - bool operator==(const IO& other) const; - -}; - -const IO A_2("A", "2"), A_10("A", "10"), - D50_2("D50", "2"), D50_10("D50", "10"), - D55_2("D55", "2"), D55_10("D55", "10"), - D65_2("D65", "2"), D65_10("D65", "10"), - D75_2("D75", "2"), D75_10("D75", "10"), - E_2("E", "2"), E_10("E", "10"); - -// data from https://en.wikipedia.org/wiki/Standard_illuminant. -const static std::map> illuminants_xy = -{ - {A_2, { 0.44757, 0.40745 }}, {A_10, { 0.45117, 0.40594 }}, - {D50_2, { 0.34567, 0.35850 }}, {D50_10, { 0.34773, 0.35952 }}, - {D55_2, { 0.33242, 0.34743 }}, {D55_10, { 0.33411, 0.34877 }}, - {D65_2, { 0.31271, 0.32902 }}, {D65_10, { 0.31382, 0.33100 }}, - {D75_2, { 0.29902, 0.31485 }}, {D75_10, { 0.45117, 0.40594 }}, - {E_2, { 1 / 3, 1 / 3 }}, {E_10, { 1 / 3, 1 / 3 }}, -}; - -std::vector xyY2XYZ(const std::vector& xyY); - - -} // namespace ccm -} // namespace cv - - -#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/linearize.hpp b/modules/mcc/include/opencv2/mcc/linearize.hpp deleted file mode 100644 index 9604d5701b1..00000000000 --- a/modules/mcc/include/opencv2/mcc/linearize.hpp +++ /dev/null @@ -1,235 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. -// Third party copyrights are property of their respective owners. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Author: Longbu Wang -// Jinheng Zhang -// Chenqi Shan - - -#ifndef __OPENCV_MCC_LINEARIZE_HPP__ -#define __OPENCV_MCC_LINEARIZE_HPP__ - -#include "opencv2/mcc/color.hpp" - -namespace cv -{ -namespace ccm -{ - -/** @brief Enum of the possible types of linearization. -*/ -enum LINEAR_TYPE -{ - IDENTITY_, - GAMMA, - COLORPOLYFIT, - COLORLOGPOLYFIT, - GRAYPOLYFIT, - GRAYLOGPOLYFIT -}; - -/** @brief Polyfit model. -*/ -class CV_EXPORTS_W Polyfit -{ -public: - int deg; - Mat p; - Polyfit() {}; - - /** @brief Polyfit method. - https://en.wikipedia.org/wiki/Polynomial_regression - polynomial: yi = a0 + a1*xi + a2*xi^2 + ... + an*xi^deg (i = 1,2,...,n) - and deduct: Ax = y - See linear.pdf for details - */ - - Polyfit(Mat x, Mat y, int deg_); - - virtual ~Polyfit() {}; - - Mat operator()(const Mat& inp); - -private: - double fromEW(double x); - -}; - -/** @brief Logpolyfit model. -*/ - -class CV_EXPORTS_W LogPolyfit - -{ -public: - int deg; - Polyfit p; - - LogPolyfit() {}; - - /** @brief Logpolyfit method. - */ - - LogPolyfit(Mat x, Mat y, int deg_); - - virtual ~LogPolyfit() {}; - - Mat operator()(const Mat& inp); - -}; - -/** @brief Linearization base. -*/ - -class CV_EXPORTS_W Linear -{ -public: - Linear() {}; - - virtual ~Linear() {}; - - /** @brief Inference. - @param inp the input array, type of cv::Mat. - */ - - virtual Mat linearize(Mat inp); - - - /* *\brief Evaluate linearization model. - */ - virtual void value(void) {}; -}; - - -/** @brief Linearization identity. - make no change. -*/ -class CV_EXPORTS_W LinearIdentity : public Linear {}; - -/** @brief Linearization gamma correction. -*/ -class CV_EXPORTS_W LinearGamma : public Linear -{ -public: - double gamma; - - LinearGamma(double gamma_) :gamma(gamma_) {}; - - Mat linearize(Mat inp) CV_OVERRIDE; -}; - -/** @brief Linearization. - Grayscale polynomial fitting. -*/ -template -class LinearGray :public Linear -{ -public: - int deg; - T p; - LinearGray(int deg_, Mat src, Color dst, Mat mask, RGBBase_ cs) :deg(deg_) - { - dst.getGray(); - Mat lear_gray_mask = mask & dst.grays; - - // the grayscale function is approximate for src is in relative color space. - src = rgb2gray(maskCopyTo(src, lear_gray_mask)); - Mat dst_ = maskCopyTo(dst.toGray(cs.io), lear_gray_mask); - calc(src, dst_); - } - - /** @brief monotonically increase is not guaranteed. - @param src the input array, type of cv::Mat. - @param dst the input array, type of cv::Mat. - */ - void calc(const Mat& src, const Mat& dst) - { - p = T(src, dst, deg); - }; - - Mat linearize(Mat inp) CV_OVERRIDE - { - return p(inp); - }; -}; - -/** @brief Linearization. - Fitting channels respectively. -*/ -template -class LinearColor :public Linear -{ -public: - int deg; - T pr; - T pg; - T pb; - - LinearColor(int deg_, Mat src_, Color dst, Mat mask, RGBBase_ cs) :deg(deg_) - { - Mat src = maskCopyTo(src_, mask); - Mat dst_ = maskCopyTo(dst.to(*cs.l).colors, mask); - calc(src, dst_); - } - - void calc(const Mat& src, const Mat& dst) - { - Mat schannels[3]; - Mat dchannels[3]; - split(src, schannels); - split(dst, dchannels); - pr = T(schannels[0], dchannels[0], deg); - pg = T(schannels[1], dchannels[1], deg); - pb = T(schannels[2], dchannels[2], deg); - }; - - Mat linearize(Mat inp) CV_OVERRIDE - { - Mat channels[3]; - split(inp, channels); - std::vector channel; - Mat res; - merge(std::vector{ pr(channels[0]), pg(channels[1]), pb(channels[2]) }, res); - return res; - }; -}; - -/** @brief Get linearization method. - used in ccm model. - @param gamma used in LinearGamma. - @param deg degrees. - @param src the input array, type of cv::Mat. - @param dst the input array, type of cv::Mat. - @param mask the input array, type of cv::Mat. - @param cs type of RGBBase_. - @param linear_type type of linear. -*/ - -std::shared_ptr getLinear(double gamma, int deg, Mat src, Color dst, Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type); - - -} // namespace ccm -} // namespace cv - - -#endif diff --git a/modules/mcc/include/opencv2/mcc/operations.hpp b/modules/mcc/include/opencv2/mcc/operations.hpp deleted file mode 100644 index 05749c56242..00000000000 --- a/modules/mcc/include/opencv2/mcc/operations.hpp +++ /dev/null @@ -1,100 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. -// Third party copyrights are property of their respective owners. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Author: Longbu Wang -// Jinheng Zhang -// Chenqi Shan - - -#ifndef __OPENCV_MCC_OPERATIONS_HPP__ -#define __OPENCV_MCC_OPERATIONS_HPP__ - -#include -#include -#include "opencv2/mcc/utils.hpp" - -namespace cv -{ -namespace ccm -{ - -typedef std::function MatFunc; - -/** @brief Operation class contains some operarions used for color space - conversion containing linear transformation and non-linear transformation - */ -class CV_EXPORTS_W Operation -{ -public: - bool linear; - Mat M; - MatFunc f; - - Operation() : linear(true), M(Mat()) {}; - - Operation(Mat M_) :linear(true), M(M_) {}; - - Operation(MatFunc f_) : linear(false), f(f_) {}; - virtual ~Operation() {}; - - /** @brief operator function will run operation - */ - Mat operator()(Mat& abc); - - /** @brief add function will conbine this operation - with other linear transformation operation - */ - void add(const Operation& other); - - void clear(); -}; - -const Operation IDENTITY_OP([](Mat x) {return x; }); - -class CV_EXPORTS_W Operations -{ -public: - std::vector ops; - - Operations() :ops{ } {}; - - Operations(std::initializer_list op) :ops{ op } {}; - - virtual ~Operations() {}; - - /** @brief add function will conbine this operation with other transformation operations - */ - Operations& add(const Operations& other); - - /** @brief run operations to make color conversion - */ - Mat run(Mat abc); -}; - -const Operations IDENTITY_OPS{ IDENTITY_OP }; - -} // namespace ccm -} // namespace cv - - -#endif \ No newline at end of file diff --git a/modules/mcc/include/opencv2/mcc/utils.hpp b/modules/mcc/include/opencv2/mcc/utils.hpp deleted file mode 100644 index 989971cb0fb..00000000000 --- a/modules/mcc/include/opencv2/mcc/utils.hpp +++ /dev/null @@ -1,153 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. -// Third party copyrights are property of their respective owners. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Author: Longbu Wang -// Jinheng Zhang -// Chenqi Shan - -#ifndef __OPENCV_MCC_UTILS_HPP__ -#define __OPENCV_MCC_UTILS_HPP__ - -#include - -namespace cv { -namespace ccm { - -CV_EXPORTS_W double gammaCorrection_(const double& element, const double& gamma); - -/** @brief gamma correction ,see ColorSpace.pdf for details. - @param src the input array,type of Mat. - @param gamma a constant for gamma correction. - */ -CV_EXPORTS_W Mat gammaCorrection(const Mat& src, const double& gamma); - -/** @brief maskCopyTo a function to delete unsatisfied elementwise. - @param src the input array, type of Mat. - @param mask operation mask that used to choose satisfided elementwise. - */ -CV_EXPORTS_W Mat maskCopyTo(const Mat& src, const Mat& mask); - -/** @brief multiple the function used to compute an array with n channels - mulipied by ccm. - @param xyz the input array, type of Mat. - @param ccm the ccm matrix to make color correction. - */ -CV_EXPORTS_W Mat multiple(const Mat& xyz, const Mat& ccm); - -/** @brief multiple the function used to get the mask of saturated colors, - colors between low and up will be choosed. - @param src the input array, type of Mat. - @param low the threshold to choose saturated colors - @param up the threshold to choose saturated colors -*/ -CV_EXPORTS_W Mat saturate(Mat& src, const double& low, const double& up); - -/** @brief rgb2gray it is an approximation grayscale function for relative RGB - color space, see Miscellaneous.pdf for details; - @param rgb the input array,type of Mat. - */ -CV_EXPORTS_W Mat rgb2gray(Mat rgb); - -/** @brief function for elementWise operation - @param src the input array, type of Mat - @param lambda a for operation - */ -template -Mat elementWise(const Mat& src, F&& lambda) -{ - Mat dst = src.clone(); - const int channel = src.channels(); - switch (channel) - { - case 1: - { - - MatIterator_ it, end; - for (it = dst.begin(), end = dst.end(); it != end; ++it) - { - (*it) = lambda((*it)); - } - break; - } - case 3: - { - MatIterator_ it, end; - for (it = dst.begin(), end = dst.end(); it != end; ++it) - { - for (int j = 0; j < 3; j++) - { - (*it)[j] = lambda((*it)[j]); - } - } - break; - } - default: - throw std::invalid_argument { "Wrong channel!" }; - break; - } - return dst; -} - -/** @brief function for channel operation - @param src the input array, type of Mat - @param lambda the function for operation -*/ -template -Mat channelWise(const Mat& src, F&& lambda) -{ - Mat dst = src.clone(); - MatIterator_ it, end; - for (it = dst.begin(), end = dst.end(); it != end; ++it) - { - *it = lambda(*it); - } - return dst; -} - -/** @brief function for distance operation. - @param src the input array, type of Mat. - @param ref another input array, type of Mat. - @param lambda the computing method for distance . - */ -template -Mat distanceWise(Mat& src, Mat& ref, F&& lambda) -{ - Mat dst = Mat(src.size(), CV_64FC1); - MatIterator_ it_src = src.begin(), end_src = src.end(), - it_ref = ref.begin(); - MatIterator_ it_dst = dst.begin(); - for (; it_src != end_src; ++it_src, ++it_ref, ++it_dst) - { - *it_dst = lambda(*it_src, *it_ref); - } - return dst; -} - -CV_EXPORTS_W Mat multiple(const Mat& xyz, const Mat& ccm); - -const static Mat m_gray = (Mat_(3, 1) << 0.2126, 0.7152, 0.0722); - -} // namespace ccm -} // namespace cv - -#endif \ No newline at end of file diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 279404ded70..740c8d85c22 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -25,69 +25,150 @@ // Jinheng Zhang // Chenqi Shan -#include "precomp.hpp" - +//#include "precomp.hpp" +#include "opencv2/mcc/ccm.hpp" +#include "linearize.hpp" namespace cv { namespace ccm { -ColorCorrectionModel::ColorCorrectionModel(Mat src_, CONST_COLOR constcolor, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, - double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, - INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : - ColorCorrectionModel(src_, GetColor::get_color(constcolor), *GetCS::get_rgb(cs_), ccm_type_, distance_, linear_type, - gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} -ColorCorrectionModel::ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE ref_cs_, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, - double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, - INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : - ColorCorrectionModel(src_, Color(colors_, *GetCS::get_cs(ref_cs_)), *GetCS::get_rgb(cs_), ccm_type_, distance_, linear_type, - gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} - -ColorCorrectionModel::ColorCorrectionModel(Mat src_, Color dst_, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, - double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, - INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : - ColorCorrectionModel(src_, dst_, *GetCS::get_rgb(cs_), ccm_type_, distance_, linear_type, - gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} - -ColorCorrectionModel::ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, - double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, - INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : - src(src_), dst(dst_), cs(cs_), ccm_type(ccm_type_), distance(distance_), max_count(max_count_), epsilon(epsilon_) -{ - Mat saturate_mask = saturate(src, saturated_threshold[0], saturated_threshold[1]); - this->linear = getLinear(gamma, deg, this->src, this->dst, saturate_mask, this->cs, linear_type); - calWeightsMasks(weights_list, weights_coeff, saturate_mask); - src_rgbl = this->linear->linearize(maskCopyTo(this->src, mask)); - dst.colors = maskCopyTo(dst.colors, mask); - dst_rgbl = this->dst.to(*(this->cs.l)).colors; + class ColorCorrectionModel::Impl{ + public: + Mat src; + Color dst;//Color::Color(){};ColorSpace(){}; dst + Mat dist; + RGBBase_& cs; + Mat mask; - // make no change for CCM_3x3, make change for CCM_4x3. - src_rgbl = prepare(src_rgbl); + // RGBl of detected data and the reference + Mat src_rgbl; + Mat dst_rgbl; - // distance function may affect the loss function and the fitting function - switch (this->distance) - { - case cv::ccm::RGBL: - initialLeastSquare(true); - break; - default: - switch (initial_method_type) + // ccm type and shape + CCM_TYPE ccm_type; + int shape; + + // linear method and distance + std::shared_ptr linear; + DISTANCE_TYPE distance; + LINEAR_TYPE linear_type; + + Mat weights; + Mat ccm; + Mat ccm0; + double gamma; + int deg; + std::vector saturated_threshold; + INITIAL_METHOD_TYPE initial_method_type; + double weights_coeff; + int masked_len; + double loss; + int max_count; + double epsilon; + Impl(); + + /** @brief Make no change for CCM_3x3. + convert cv::Mat A to [A, 1] in CCM_4x3. + @param inp the input array, type of cv::Mat. + @return the output array, type of cv::Mat + */ + Mat prepare(const Mat& inp); + + /** @brief Calculate weights and mask. + @param weights_list the input array, type of cv::Mat. + @param weights_coeff type of double. + @param saturate_mask the input array, type of cv::Mat. + */ + void calWeightsMasks(Mat weights_list, double weights_coeff, Mat saturate_mask); + + /** @brief Fitting nonlinear - optimization initial value by white balance. + see CCM.pdf for details. + @return the output array, type of Mat + */ + void initialWhiteBalance(void); + + /** @brief Fitting nonlinear-optimization initial value by least square. + see CCM.pdf for details + @param fit if fit is True, return optimalization for rgbl distance function. + */ + void initialLeastSquare(bool fit = false); + + double calc_loss_(Color color); + double calc_loss(const Mat ccm_); + + /** @brief Fitting ccm if distance function is associated with CIE Lab color space. + see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp + Set terminal criteria for solver is possible. + */ + void fitting(void); + + /** @brief Infer using fitting ccm. + @param img the input image, type of cv::Mat. + @param islinear default false. + @return the output array, type of cv::Mat. + */ + Mat infer(const Mat& img, bool islinear = false); + + /** @brief Infer image and output as an BGR image with uint8 type. + mainly for test or debug. + input size and output size should be 255. + @param img_ image to infer, type of cv::Mat. + @param islinear if linearize or not. + @return the output array, type of cv::Mat. + */ + Mat inferImage(Mat& img_, bool islinear = false); + void get_color(Mat& img_, bool islinear = false); + void get_color(CONST_COLOR constcolor); + void get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_); + + + /** @brief Loss function base on cv::MinProblemSolver::Function. + see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp + */ + class LossFunction : public MinProblemSolver::Function { - case cv::ccm::WHITE_BALANCE: - initialWhiteBalance(); - break; - case cv::ccm::LEAST_SQUARE: - initialLeastSquare(); - break; - default: - throw std::invalid_argument{ "Wrong initial_methoddistance_type!" }; - break; - } - break; - } - fitting(); -} + public: + //ColorCorrectionModel* ccm_loss; + ColorCorrectionModel::Impl * ccm_loss; + // LossFunction(ColorCorrectionModel* ccm) : ccm_loss(ccm) {}; + LossFunction(ColorCorrectionModel::Impl* ccm) : ccm_loss(ccm) {}; -Mat ColorCorrectionModel::prepare(const Mat& inp) + /** @brief Reset dims to ccm->shape. + */ + int getDims() const CV_OVERRIDE + { + return ccm_loss->shape; + } + + /** @brief Reset calculation. + */ + double calc(const double* x) const CV_OVERRIDE + { + Mat ccm_(ccm_loss->shape, 1, CV_64F); + for (int i = 0; i < ccm_loss->shape; i++) + { + ccm_.at(i, 0) = x[i]; + } + ccm_ = ccm_.reshape(0, ccm_loss->shape / 3); + return ccm_loss->calc_loss(ccm_); + } + }; +}; +// ColorCorrectionModel::Impl::Impl():cs(sRGB),ccm_type(CCM_3x3), distance(), +// linear_type(linear_type),gamma(gamma),deg(deg),saturated_threshold(saturated_threshold),weights_coeff(0),initial_method_type(initial_method_type), +// max_count(max_count_),epsilon(epsilon_) +// { +// // run(); +// } //写成默认参数 +ColorCorrectionModel::Impl::Impl():cs(sRGB),ccm_type(CCM_3x3), distance(CIE2000),linear_type(GAMMA),gamma(2.2),deg(3),saturated_threshold({ 0, 0.98 }), + weights(Mat()),weights_coeff(0),initial_method_type(LEAST_SQUARE),max_count(5000),epsilon(1.e-4) + { + // run(); + } //写成默认参数 +// Mat src_, Color dst_, RGBBase_& cs_ , CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, +// double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, +// INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4 +Mat ColorCorrectionModel::Impl::prepare(const Mat& inp) { switch (ccm_type) { @@ -110,7 +191,7 @@ Mat ColorCorrectionModel::prepare(const Mat& inp) } } -void ColorCorrectionModel::calWeightsMasks(Mat weights_list, double weights_coeff, Mat saturate_mask) +void ColorCorrectionModel::Impl::calWeightsMasks(Mat weights_list, double weights_coeff, Mat saturate_mask) { // weights if (!weights_list.empty()) @@ -139,7 +220,7 @@ void ColorCorrectionModel::calWeightsMasks(Mat weights_list, double weights_coef masked_len = (int)sum(mask)[0]; } -void ColorCorrectionModel::initialWhiteBalance(void) +void ColorCorrectionModel::Impl::initialWhiteBalance(void) { Mat schannels[4]; split(src_rgbl, schannels); @@ -153,7 +234,7 @@ void ColorCorrectionModel::initialWhiteBalance(void) ccm0 = initial_white_balance; } -void ColorCorrectionModel::initialLeastSquare(bool fit) +void ColorCorrectionModel::Impl::initialLeastSquare(bool fit) { Mat A, B, w; if (weights.empty()) @@ -182,7 +263,7 @@ void ColorCorrectionModel::initialLeastSquare(bool fit) } } -double ColorCorrectionModel::calc_loss_(Color color) +double ColorCorrectionModel::Impl::calc_loss_(Color color) { Mat distlist = color.diff(dst, distance); Color lab = color.to(Lab_D50_2); @@ -196,14 +277,14 @@ double ColorCorrectionModel::calc_loss_(Color color) return ss[0]; } -double ColorCorrectionModel::calc_loss(const Mat ccm_) +double ColorCorrectionModel::Impl::calc_loss(const Mat ccm_) { Mat converted = src_rgbl.reshape(1, 0) * ccm_; Color color(converted.reshape(3, 0), *(cs.l)); return calc_loss_(color); } -void ColorCorrectionModel::fitting(void) +void ColorCorrectionModel::Impl::fitting(void) { cv::Ptr solver = cv::DownhillSolver::create(); cv::Ptr ptr_F(new LossFunction(this)); @@ -220,7 +301,7 @@ void ColorCorrectionModel::fitting(void) std::cout << " loss " << loss << std::endl; } -Mat ColorCorrectionModel::infer(const Mat& img, bool islinear) +Mat ColorCorrectionModel::Impl::infer(const Mat& img, bool islinear) { if (!ccm.data) { @@ -237,7 +318,7 @@ Mat ColorCorrectionModel::infer(const Mat& img, bool islinear) return cs.fromL(img_ccm); } -Mat ColorCorrectionModel::inferImage(Mat& img_, bool islinear) +Mat ColorCorrectionModel::Impl::inferImage(Mat& img_, bool islinear) { const int inp_size = 255; const int out_size = 255; @@ -250,6 +331,162 @@ Mat ColorCorrectionModel::inferImage(Mat& img_, bool islinear) cvtColor(img_out, out_img, COLOR_RGB2BGR); return out_img; } +void ColorCorrectionModel::Impl::get_color(CONST_COLOR constcolor){ + p->dst = GetColor::get_color(constcolor); +} +void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE ref_cs_){ + p->dst = Color(colors_, *GetCS::get_cs(ref_cs_)); +} +void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_){ + p->dst =Color(colors_, *GetCS::get_cs(cs_),colored_); +} +ColorCorrectionModel::ColorCorrectionModel(Mat src_, CONST_COLOR constcolor): p(new Impl){ + p->src = src_; + p->get_color(constcolor); + // dst= GetColor::get_color(constcolor) +} +ColorCorrectionModel:: ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE ref_cs_): p(new Impl){ + p->src = src_; + p->get_color(colors_, ref_cs_); + //dst= Color(colors_, *GetCS::get_cs(ref_cs_)) +} +ColorCorrectionModel::ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE cs_, Mat colored_): p(new Impl){ + p->src = src_; + // p->cs = *GetCS::get_rgb(cs_); + // p->get_color(colors_, *GetCS::get_cs(cs_),colored_); + p->get_color(colors_, cs_, colored_); +} +// ColorCorrectionModel::ColorCorrectionModel(Mat src_, CONST_COLOR constcolor, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, +// double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, +// INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : +// ColorCorrectionModel(src_, GetColor::get_color(constcolor), *GetCS::get_rgb(cs_), ccm_type_, distance_, linear_type, +// gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} +// ColorCorrectionModel::ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE ref_cs_, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, +// double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, +// INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : +// ColorCorrectionModel(src_, Color(colors_, *GetCS::get_cs(ref_cs_)), *GetCS::get_rgb(cs_), ccm_type_, distance_, linear_type, +// gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} + +// ColorCorrectionModel::ColorCorrectionModel(Mat src_, Color dst_, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, +// double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, +// INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : +// ColorCorrectionModel(src_, dst_, *GetCS::get_rgb(cs_), ccm_type_, distance_, linear_type, +// gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} + +// ColorCorrectionModel::ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, +// double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, +// INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : +// src(src_), dst(dst_), cs(cs_), ccm_type(ccm_type_), distance(distance_), max_count(max_count_), epsilon(epsilon_) +// { +// Mat saturate_mask = saturate(src, saturated_threshold[0], saturated_threshold[1]); +// this->linear = getLinear(gamma, deg, this->src, this->dst, saturate_mask, this->cs, linear_type); +// calWeightsMasks(weights_list, weights_coeff, saturate_mask); +// src_rgbl = this->linear->linearize(maskCopyTo(this->src, mask)); +// dst.colors = maskCopyTo(dst.colors, mask); +// dst_rgbl = this->dst.to(*(this->cs.l)).colors; + +// // make no change for CCM_3x3, make change for CCM_4x3. +// src_rgbl = prepare(src_rgbl); + +// // distance function may affect the loss function and the fitting function +// switch (this->distance) +// { +// case cv::ccm::RGBL: +// initialLeastSquare(true); +// break; +// default: +// switch (initial_method_type) +// { +// case cv::ccm::WHITE_BALANCE: +// initialWhiteBalance(); +// break; +// case cv::ccm::LEAST_SQUARE: +// initialLeastSquare(); +// break; +// default: +// throw std::invalid_argument{ "Wrong initial_methoddistance_type!" }; +// break; +// } +// break; +// } +// fitting(); +// } + + + +void ColorCorrectionModel::setColorSpace(COLOR_SPACE cs_){ + p->cs = cs_; +} +void ColorCorrectionModel::setCCM(CCM_TYPE ccm_type_){ + p->ccm_type = ccm_type_; +} +void ColorCorrectionModel::setDistance(DISTANCE_TYPE distance_){ + p->distance = distance_; +} +void ColorCorrectionModel::setLinear(LINEAR_TYPE linear_type){ + p->linear_type = linear_type; +} +void ColorCorrectionModel::setLinearGamma(double gamma){ + p->gamma = gamma; +} +void ColorCorrectionModel::setLinearDegree(int deg){ + p->deg = deg; +} +void ColorCorrectionModel::setSaturatedThreshold(double lower, double upper){//std::vector saturated_threshold + p->saturated_threshold = {lower, upper}; +} +void ColorCorrectionModel::setWeightsList(Mat weights_list){ + p->weights = weights_list; +} +void ColorCorrectionModel::setWeightCoeff(double weights_coeff){ + p->weights_coeff = weights_coeff; + +} +void ColorCorrectionModel::setInitialMethod(INITIAL_METHOD_TYPE initial_method_type){ + p->initial_method_type = initial_method_type; +} +void ColorCorrectionModel::setMaxCount(int max_count_){ + p->max_count = max_count_; +} +void ColorCorrectionModel::setEpsilon(double epsilon_){ + p->epsilon = epsilon_; +} +bool ColorCorrectionModel::run(){ + + Mat saturate_mask = saturate(p->src, p->saturated_threshold[0], p->saturated_threshold[1]); + p->linear = getLinear(p->gamma, p->deg, p->src, p->dst, p->saturate_mask, p->cs, p->linear_type); + p->calWeightsMasks(p->weights_list, p->weights_coeff, saturate_mask); + p->src_rgbl = p->linear->linearize(maskCopyTo(p->src, p->mask)); + p->dst.colors = maskCopyTo(p->dst.colors, p->mask); + p->dst_rgbl = p->dst.to(*(p->cs.l)).colors; + + // make no change for CCM_3x3, make change for CCM_4x3. + p->src_rgbl = p->prepare(p->src_rgbl); + + // distance function may affect the loss function and the fitting function + switch (p->distance) + { + case cv::ccm::RGBL: + p->initialLeastSquare(true); + break; + default: + switch (p->initial_method_type) + { + case cv::ccm::WHITE_BALANCE: + p->initialWhiteBalance(); + break; + case cv::ccm::LEAST_SQUARE: + p->initialLeastSquare(); + break; + default: + throw std::invalid_argument{ "Wrong initial_methoddistance_type!" }; + break; + } + break; + } + p->fitting(); + +} } // namespace ccm } // namespace cv diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index e8c533cd447..fb0d7f24801 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -25,12 +25,13 @@ // Jinheng Zhang // Chenqi Shan -#include "precomp.hpp" +#include "color.hpp" namespace cv { namespace ccm { +Color::Color():cs(std::shared_ptr ptr(new ColorSpace)) {}; Color::Color(Mat colors_, enum COLOR_SPACE cs_) :colors(colors_), cs(*GetCS::get_cs(cs_)) {}; Color::Color(Mat colors_, const ColorSpace& cs_, Mat colored_) : colors(colors_), cs(cs_), colored(colored_) @@ -41,6 +42,9 @@ Color::Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_) : colors(colors_), grays = ~colored; } Color::Color(Mat colors_, const ColorSpace& cs_) : colors(colors_), cs(cs_) {}; +// Color::Color(CONST_COLOR constcolor){ +// *this = GetColor::g et_color(constcolor); +// } Color Color::to(const ColorSpace& other, CAM method , bool save) { if (history.count(other) == 1) diff --git a/modules/mcc/src/colorspace.cpp b/modules/mcc/src/colorspace.cpp index 46ddd3a9070..54fdaf59948 100644 --- a/modules/mcc/src/colorspace.cpp +++ b/modules/mcc/src/colorspace.cpp @@ -25,7 +25,9 @@ // Jinheng Zhang // Chenqi Shan -#include "precomp.hpp" +#include "colorspace.hpp" +#include "operations.hpp" +#include "io.hpp" namespace cv { namespace ccm { diff --git a/modules/mcc/src/distance.cpp b/modules/mcc/src/distance.cpp index dd39f0c614a..e1ec1c824a7 100644 --- a/modules/mcc/src/distance.cpp +++ b/modules/mcc/src/distance.cpp @@ -25,7 +25,8 @@ // Jinheng Zhang // Chenqi Shan -#include "precomp.hpp" +//#include "precomp.hpp" +#include "distance.hpp" namespace cv { diff --git a/modules/mcc/src/io.cpp b/modules/mcc/src/io.cpp index 6d061326b48..d2fe9dbfe4d 100644 --- a/modules/mcc/src/io.cpp +++ b/modules/mcc/src/io.cpp @@ -25,7 +25,7 @@ // Jinheng Zhang // Chenqi Shan -#include "opencv2/mcc/io.hpp" +#include "io.hpp" namespace cv { namespace ccm diff --git a/modules/mcc/src/linearize.cpp b/modules/mcc/src/linearize.cpp index cfa2f661282..9002aac3d89 100644 --- a/modules/mcc/src/linearize.cpp +++ b/modules/mcc/src/linearize.cpp @@ -25,7 +25,7 @@ // Jinheng Zhang // Chenqi Shan -#include "precomp.hpp" +#include "linearize.hpp" namespace cv { diff --git a/modules/mcc/src/operations.cpp b/modules/mcc/src/operations.cpp index 42c05784c72..ccca1b67ee4 100644 --- a/modules/mcc/src/operations.cpp +++ b/modules/mcc/src/operations.cpp @@ -25,8 +25,8 @@ // Jinheng Zhang // Chenqi Shan -#include "precomp.hpp" - +#include "operations.hpp" +#include "utils.hpp" namespace cv { namespace ccm diff --git a/modules/mcc/src/utils.cpp b/modules/mcc/src/utils.cpp index 56f3be7aaba..e338cc1f1c4 100644 --- a/modules/mcc/src/utils.cpp +++ b/modules/mcc/src/utils.cpp @@ -25,7 +25,7 @@ // Jinheng Zhang // Chenqi Shan -#include "precomp.hpp" +#include "utils.hpp" namespace cv { diff --git a/modules/mcc/test/test_ccm.cpp b/modules/mcc/test/test_ccm.cpp deleted file mode 100644 index 68ef741d108..00000000000 --- a/modules/mcc/test/test_ccm.cpp +++ /dev/null @@ -1,148 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. - -#include "test_precomp.hpp" - -#include - -namespace opencv_test -{ -namespace -{ - -Mat s = (Mat_(24, 1) << - Vec3d(214.11, 98.67, 37.97), - Vec3d(231.94, 153.1, 85.27), - Vec3d(204.08, 143.71, 78.46), - Vec3d(190.58, 122.99, 30.84), - Vec3d(230.93, 148.46, 100.84), - Vec3d(228.64, 206.97, 97.5), - Vec3d(229.09, 137.07, 55.29), - Vec3d(189.21, 111.22, 92.66), - Vec3d(223.5, 96.42, 75.45), - Vec3d(201.82, 69.71, 50.9), - Vec3d(240.52, 196.47, 59.3), - Vec3d(235.73, 172.13, 54.), - Vec3d(131.6, 75.04, 68.86), - Vec3d(189.04, 170.43, 42.05), - Vec3d(222.23, 74., 71.95), - Vec3d(241.01, 199.1, 61.15), - Vec3d(224.99, 101.4, 100.24), - Vec3d(174.58, 152.63, 91.52), - Vec3d(248.06, 227.69, 140.5), - Vec3d(241.15, 201.38, 115.58), - Vec3d(236.49, 175.87, 88.86), - Vec3d(212.19, 133.49, 54.79), - Vec3d(181.17, 102.94, 36.18), - Vec3d(115.1, 53.77, 15.23)); - -TEST(CV_ccmRunColorCorrection, test_model) -{ - ColorCorrectionModel model(s / 255, Macbeth); - Mat src_rgbl = (Mat_(24, 1) << - Vec3d(0.68078957, 0.12382801, 0.01514889), - Vec3d(0.81177942, 0.32550452, 0.089818), - Vec3d(0.61259378, 0.2831933, 0.07478902), - Vec3d(0.52696493, 0.20105976, 0.00958657), - Vec3d(0.80402284, 0.30419523, 0.12989841), - Vec3d(0.78658646, 0.63184111, 0.12062068), - Vec3d(0.78999637, 0.25520249, 0.03462853), - Vec3d(0.51866697, 0.16114393, 0.1078387), - Vec3d(0.74820768, 0.11770076, 0.06862177), - Vec3d(0.59776825, 0.05765816, 0.02886627), - Vec3d(0.8793145, 0.56346033, 0.0403954), - Vec3d(0.84124847, 0.42120746, 0.03287592), - Vec3d(0.23333214, 0.06780408, 0.05612276), - Vec3d(0.5176423, 0.41210976, 0.01896255), - Vec3d(0.73888613, 0.06575388, 0.06181293), - Vec3d(0.88326036, 0.58018751, 0.04321991), - Vec3d(0.75922531, 0.13149072, 0.1282041), - Vec3d(0.4345097, 0.32331019, 0.10494139), - Vec3d(0.94110142, 0.77941419, 0.26946323), - Vec3d(0.88438952, 0.5949049 , 0.17536928), - Vec3d(0.84722687, 0.44160449, 0.09834799), - Vec3d(0.66743106, 0.24076803, 0.03394333), - Vec3d(0.47141286, 0.13592419, 0.01362205), - Vec3d(0.17377101, 0.03256864, 0.00203026)); - ASSERT_MAT_NEAR(src_rgbl, model.src_rgbl, 1e-4); - - Mat dst_rgbl = (Mat_(24, 1) << - Vec3d(0.17303173, 0.08211037, 0.05672686), - Vec3d(0.56832031, 0.29269488, 0.21835529), - Vec3d(0.10365019, 0.19588357, 0.33140475), - Vec3d(0.10159676, 0.14892193, 0.05188294), - Vec3d(0.22159627, 0.21584476, 0.43461196), - Vec3d(0.10806379, 0.51437196, 0.41264213), - Vec3d(0.74736423, 0.20062878, 0.02807988), - Vec3d(0.05757947, 0.10516793, 0.40296109), - Vec3d(0.56676218, 0.08424805, 0.11969461), - Vec3d(0.11099515, 0.04230796, 0.14292554), - Vec3d(0.34546869, 0.50872001, 0.04944204), - Vec3d(0.79461323, 0.35942459, 0.02051968), - Vec3d(0.01710416, 0.05022043, 0.29220674), - Vec3d(0.05598012, 0.30021149, 0.06871162), - Vec3d(0.45585457, 0.03033727, 0.04085654), - Vec3d(0.85737614, 0.56757335, 0.0068503), - Vec3d(0.53348585, 0.08861148, 0.30750446), - Vec3d(-0.0374061, 0.24699498, 0.40041217), - Vec3d(0.91262695, 0.91493909, 0.89367049), - Vec3d(0.57981916, 0.59200418, 0.59328881), - Vec3d(0.35490581, 0.36544831, 0.36755375), - Vec3d(0.19007357, 0.19186587, 0.19308397), - Vec3d(0.08529188, 0.08887994, 0.09257601), - Vec3d(0.0303193, 0.03113818, 0.03274845)); - ASSERT_MAT_NEAR(dst_rgbl, model.dst_rgbl, 1e-4); - - Mat ccm = (Mat_(3, 3) << - 0.37408717, 0.02066172, 0.05796725, - 0.12684056, 0.77364991, -0.01566532, - -0.27464866, 0.00652140, 2.74593262); - ASSERT_MAT_NEAR(model.ccm, ccm, 1e-4); - - Mat mask = Mat::ones(24, 1, CV_8U); - ASSERT_MAT_NEAR(model.mask, mask, 0.0); -} - -TEST(CV_ccmRunColorCorrection, test_masks_weights_1) -{ - Mat weights_list_ = (Mat_(24, 1) << - 1.1, 0, 0, 1.2, 0, 0, - 1.3, 0, 0, 1.4, 0, 0, - 0.5, 0, 0, 0.6, 0, 0, - 0.7, 0, 0, 0.8, 0, 0); - ColorCorrectionModel model1(s / 255,Macbeth, sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, { 0, 0.98 }, weights_list_, 1.5); - Mat weights = (Mat_(8, 1) << - 1.15789474, 1.26315789, 1.36842105, 1.47368421, - 0.52631579, 0.63157895, 0.73684211, 0.84210526); - ASSERT_MAT_NEAR(model1.weights, weights, 1e-4); - - Mat mask = (Mat_(24, 1) << - true, false, false, true, false, false, - true, false, false, true, false, false, - true, false, false, true, false, false, - true, false, false, true, false, false); - ASSERT_MAT_NEAR(model1.mask, mask, 0.0); -} - -TEST(CV_ccmRunColorCorrection, test_masks_weights_2) -{ - ColorCorrectionModel model2(s / 255, Macbeth, sRGB, CCM_3x3, CIE2000, GAMMA, 2.2, 3, { 0.05, 0.93 }, Mat(), 1.5); - - Mat weights = (Mat_(20, 1) << - 0.65554256, 1.49454705, 1.00499244, 0.79735434, 1.16327759, - 1.68623868, 1.37973155, 0.73213388, 1.0169629, 0.47430246, - 1.70312161, 0.45414218, 1.15910007, 0.7540434, 1.05049802, - 1.04551645, 1.54082353, 1.02453421, 0.6015915, 0.26154558); - ASSERT_MAT_NEAR(model2.weights, weights, 1e-4); - - Mat mask = (Mat_(24, 1) << - true, true, true, true, true, true, - true, true, true, true, false, true, - true, true, true, false, true, true, - false, false, true, true, true, true); - ASSERT_MAT_NEAR(model2.mask, mask, 0.0); -} - -} // namespace -} // namespace opencv_test diff --git a/modules/mcc/test/test_color.cpp b/modules/mcc/test/test_color.cpp deleted file mode 100644 index 83469f7ea92..00000000000 --- a/modules/mcc/test/test_color.cpp +++ /dev/null @@ -1,219 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. - -#include "test_precomp.hpp" - -namespace opencv_test -{ -namespace -{ - -TEST(CV_ccmColor, test_srgb) -{ - Color color = Color((Mat_(1, 1) << Vec3d(0.3, 0.2, 0.5)), sRGB); - Color color_rgb = color.to(sRGB); - Color color_rgbl = color.to(sRGBL); - Color color_xyz = color.to(XYZ_D65_2); - Color color_lab = color.to(Lab_D65_2); - Color color_xyz_d50 = color.to(XYZ_D50_2); - Color color_lab_d50 = color.to(Lab_D50_2); - - Mat color_rgb_M = (Mat_(1, 1) << Vec3d(0.3, 0.2, 0.5)); - Mat color_rgbl_M = (Mat_(1, 1) << Vec3d(0.07323896, 0.03310477, 0.21404114)); - Mat color_xyz_M = (Mat_(1, 1) << Vec3d(0.080666, 0.054699, 0.208766)); - Mat color_lab_M = (Mat_(1, 1) << Vec3d(28.0337, 29.9289, -39.4065)); - Mat color_xyz_d50_M = (Mat_(1, 1) << Vec3d(0.075310, 0.053003, 0.157097)); - Mat color_lab_d50_M = (Mat_(1, 1) << Vec3d(27.5736, 25.9112, -39.9261)); - - ASSERT_MAT_NEAR(color_rgb.colors, color_rgb_M, 1e-4); - ASSERT_MAT_NEAR(color_rgbl.colors, color_rgbl_M, 1e-4); - ASSERT_MAT_NEAR(color_xyz.colors, color_xyz_M, 1e-4); - ASSERT_MAT_NEAR(color_lab.colors, color_lab_M, 1e-2); - ASSERT_MAT_NEAR(color_xyz_d50.colors, color_xyz_d50_M, 1e-4); - ASSERT_MAT_NEAR(color_lab_d50.colors, color_lab_d50_M, 1e-2); -} - -TEST(CV_ccmColor, test_adobergbl) -{ - Color color = Color((Mat_(2, 1) << Vec3d(0.3, 0.2, 0.5), Vec3d(0.7, 0.1, 0.4)), AdobeRGBL); - Color color_rgb = color.to(AdobeRGB); - Color color_rgbl = color.to(AdobeRGBL); - Color color_xyz = color.to(XYZ_D65_2); - Color color_lab = color.to(Lab_D65_2); - Color color_xyz_d50 = color.to(XYZ_D50_2); - Color color_lab_d50 = color.to(Lab_D50_2); - - Mat color_rgb_M = (Mat_(2, 1) << Vec3d(0.578533, 0.481157, 0.729740), Vec3d(0.850335, 0.351119, 0.659353)); - Mat color_rgbl_M = (Mat_(2, 1) << Vec3d(0.3, 0.2, 0.5), Vec3d(0.7, 0.1, 0.4)); - Mat color_xyz_M = (Mat_(2, 1) << Vec3d(0.304223, 0.252320, 0.517802), Vec3d(0.497541, 0.301008, 0.422436)); - Mat color_lab_M = (Mat_(2, 1) << Vec3d(57.3008, 26.0707, -29.7295), Vec3d(61.7411, 67.8735, -11.8328)); - Mat color_xyz_d50_M = (Mat_(2, 1) << Vec3d(0.298587, 0.250078, 0.390442), Vec3d(0.507043, 0.305640, 0.317661)); - Mat color_lab_d50_M = (Mat_(2, 1) << Vec3d(57.0831, 23.2605, -29.8401), Vec3d(62.1379, 66.7756, -10.7684)); - - ASSERT_MAT_NEAR(color_rgb.colors, color_rgb_M, 1e-4); - ASSERT_MAT_NEAR(color_rgbl.colors, color_rgbl_M, 1e-4); - ASSERT_MAT_NEAR(color_xyz.colors, color_xyz_M, 1e-4); - ASSERT_MAT_NEAR(color_lab.colors, color_lab_M, 1e-2); - ASSERT_MAT_NEAR(color_xyz_d50.colors, color_xyz_d50_M, 1e-4); - ASSERT_MAT_NEAR(color_lab_d50.colors, color_lab_d50_M, 1e-2); -} - -TEST(CV_ccmColor, test_xyz) -{ - Color color = Color((Mat_(1, 1) << Vec3d(0.3, 0.2, 0.5)), XYZ_D65_2); - Color color_rgb = color.to(ProPhotoRGB, VON_KRIES); - Color color_rgbl = color.to(ProPhotoRGBL, VON_KRIES); - Color color_xyz = color.to(XYZ_D65_2, VON_KRIES); - Color color_lab = color.to(Lab_D65_2, VON_KRIES); - Color color_xyz_d50 = color.to(XYZ_D50_2, VON_KRIES); - Color color_lab_d50 = color.to(Lab_D50_2, VON_KRIES); - - Mat color_rgb_M = (Mat_(1, 1) << Vec3d(0.530513, 0.351224, 0.648975)); - Mat color_rgbl_M = (Mat_(1, 1) << Vec3d(0.319487, 0.152073, 0.459209)); - Mat color_xyz_M = (Mat_(1, 1) << Vec3d(0.3, 0.2, 0.5)); - Mat color_lab_M = (Mat_(1, 1) << Vec3d(51.8372, 48.0307, -37.3395)); - Mat color_xyz_d50_M = (Mat_(1, 1) << Vec3d(0.289804, 0.200321, 0.378944)); - Mat color_lab_d50_M = (Mat_(1, 1) << Vec3d(51.8735, 42.3654, -37.2770)); - - ASSERT_MAT_NEAR(color_rgb.colors, color_rgb_M, 1e-4); - ASSERT_MAT_NEAR(color_rgbl.colors, color_rgbl_M, 1e-4); - ASSERT_MAT_NEAR(color_xyz.colors, color_xyz_M, 1e-4); - ASSERT_MAT_NEAR(color_lab.colors, color_lab_M, 1e-2); - ASSERT_MAT_NEAR(color_xyz_d50.colors, color_xyz_d50_M, 1e-4); - ASSERT_MAT_NEAR(color_lab_d50.colors, color_lab_d50_M, 1e-2); -} - -TEST(CV_ccmColor, test_lab) -{ - Color color = Color((Mat_(1, 1) << Vec3d(30., 20., 10.)), Lab_D50_2); - Color color_rgb = color.to(AppleRGB, IDENTITY); - Color color_rgbl = color.to(AppleRGBL, IDENTITY); - Color color_xyz = color.to(XYZ_D65_2, IDENTITY); - Color color_lab = color.to(Lab_D65_2, IDENTITY); - Color color_xyz_d50 = color.to(XYZ_D50_2, IDENTITY); - Color color_lab_d50 = color.to(Lab_D50_2, IDENTITY); - - Mat color_rgb_M = (Mat_(1, 1) << Vec3d(0.323999, 0.167314, 0.165874)); - Mat color_rgbl_M = (Mat_(1, 1) << Vec3d(0.131516, 0.040028, 0.039410)); - Mat color_xyz_M = (Mat_(1, 1) << Vec3d(0.079076, 0.062359, 0.045318)); - Mat color_lab_M = (Mat_(1, 1) << Vec3d(30.0001, 19.9998, 9.9999)); - Mat color_xyz_d50_M = (Mat_(1, 1) << Vec3d(0.080220, 0.062359, 0.034345)); - Mat color_lab_d50_M = (Mat_(1, 1) << Vec3d(30., 20., 10.)); - - ASSERT_MAT_NEAR(color_rgb.colors, color_rgb_M, 1e-4); - ASSERT_MAT_NEAR(color_rgbl.colors, color_rgbl_M, 1e-4); - ASSERT_MAT_NEAR(color_xyz.colors, color_xyz_M, 1e-4); - ASSERT_MAT_NEAR(color_lab.colors, color_lab_M, 1e-2); - ASSERT_MAT_NEAR(color_xyz_d50.colors, color_xyz_d50_M, 1e-4); - ASSERT_MAT_NEAR(color_lab_d50.colors, color_lab_d50_M, 1e-2); -} - -TEST(CV_ccmColor, test_grays) -{ - const double ColorChecker2005_LAB_D50_2 [24][3] = - { {37.986, 13.555, 14.059}, - {65.711, 18.13, 17.81}, - {49.927, -4.88, -21.925}, - {43.139, -13.095, 21.905}, - {55.112, 8.844, -25.399}, - {70.719, -33.397, -0.199}, - {62.661, 36.067, 57.096}, - {40.02, 10.41, -45.964}, - {51.124, 48.239, 16.248}, - {30.325, 22.976, -21.587}, - {72.532, -23.709, 57.255}, - {71.941, 19.363, 67.857}, - {28.778, 14.179, -50.297}, - {55.261, -38.342, 31.37}, - {42.101, 53.378, 28.19}, - {81.733, 4.039, 79.819}, - {51.935, 49.986, -14.574}, - {51.038, -28.631, -28.638}, - {96.539, -0.425, 1.186}, - {81.257, -0.638, -0.335}, - {66.766, -0.734, -0.504}, - {50.867, -0.153, -0.27}, - {35.656, -0.421, -1.231}, - {20.461, -0.079, -0.973}}; - -const double ColorChecker2005_LAB_D65_2[24][3]= - {{37.542, 12.018, 13.33}, - {65.2, 14.821, 17.545}, - {50.366, -1.573, -21.431}, - {43.125, -14.63, 22.12}, - {55.343, 11.449, -25.289}, - {71.36, -32.718, 1.636}, - {61.365, 32.885, 55.155}, - {40.712, 16.908, -45.085}, - {49.86, 45.934, 13.876}, - {30.15, 24.915, -22.606}, - {72.438, -27.464, 58.469}, - {70.916, 15.583, 66.543}, - {29.624, 21.425, -49.031}, - {55.643, -40.76, 33.274}, - {40.554, 49.972, 25.46}, - {80.982, -1.037, 80.03}, - {51.006, 49.876, -16.93}, - {52.121, -24.61, -26.176}, - {96.536, -0.694, 1.354}, - {81.274, -0.61, -0.24}, - {66.787, -0.647, -0.429}, - {50.872, -0.059, -0.247}, - {35.68, -0.22, -1.205}, - {20.475, 0.049, -0.972}}; - Mat ColorChecker2005_LAB_D50_2_test = GetColor::get_ColorChecker(*ColorChecker2005_LAB_D50_2,24); - Mat ColorChecker2005_LAB_D65_2_test = GetColor::get_ColorChecker(*ColorChecker2005_LAB_D65_2,24); - Color color_d50_2(ColorChecker2005_LAB_D50_2_test, Lab_D50_2); - - Color color_d65_2(ColorChecker2005_LAB_D65_2_test, Lab_D65_2); - - Mat grays = (Mat_(24, 1) << - false, false, false, false, false, false, - false, false, false, false, false, false, - false, false, false, false, false, false, - true, true, true, true, true, true); - color_d50_2.getGray(); - color_d65_2.getGray(); - - ASSERT_MAT_NEAR(color_d50_2.grays > 0, grays > 0, 0.0); - ASSERT_MAT_NEAR(color_d65_2.grays > 0, grays > 0, 0.0); -} - -TEST(CV_ccmColor, test_gray_luminant) -{ - Color color1 = Color((Mat_(1, 1) << Vec3d(0.3, 0.2, 0.5)), sRGB); - Mat toGray1 = (Mat_(1, 1) <<0.054699); - Mat toLuminant1 = (Mat_(1, 1) <<28.0337); - ASSERT_MAT_NEAR(color1.toGray(color1.cs.io), toGray1, 1e-4); - ASSERT_MAT_NEAR(color1.toLuminant(color1.cs.io), toLuminant1, 1e-4); - - Color color2 = Color((Mat_(2, 1) << Vec3d(0.3, 0.2, 0.5), Vec3d(0.7, 0.1, 0.4)), sRGB); - Mat toGray2 = (Mat_(2, 1) <<0.054699, 0.112033); - Mat toLuminant2 = (Mat_(2, 1) <<28.0337, 39.9207); - ASSERT_MAT_NEAR(color2.toGray(color2.cs.io), toGray2, 1e-4); - ASSERT_MAT_NEAR(color2.toLuminant(color2.cs.io), toLuminant2, 1e-4); -} - -TEST(CV_ccmColor, test_diff) -{ - Color color1 = Color((Mat_(1, 1) << Vec3d(0.3, 0.2, 0.5)), sRGB); - Color color2 = Color((Mat_(1, 1) << Vec3d(0.3, 0.2, 0.5)), XYZ_D50_2); - - Mat diff_CIE2000 = (Mat_(1, 1) <<22.58031); - Mat diff_CIE94_GRAPHIC_ARTS = (Mat_(1, 1) <<25.701214); - Mat diff_CIE76 = (Mat_(1, 1) <<34.586351); - Mat diff_CMC_1TO1 = (Mat_(1, 1) <<33.199419); - Mat diff_RGB = (Mat_(1, 1) <<0.51057); - Mat diff_RGBL = (Mat_(1, 1) <<0.556741); - - ASSERT_MAT_NEAR(color1.diff(color2, D65_2, CIE2000), diff_CIE2000, 1e-2); - ASSERT_MAT_NEAR(color1.diff(color2, D65_2, CIE94_GRAPHIC_ARTS), diff_CIE94_GRAPHIC_ARTS, 1e-2); - ASSERT_MAT_NEAR(color1.diff(color2, D65_2, CIE76), diff_CIE76, 1e-2); - ASSERT_MAT_NEAR(color1.diff(color2, D65_2, CMC_1TO1), diff_CMC_1TO1, 1e-2); - ASSERT_MAT_NEAR(color1.diff(color2, D65_2, RGB), diff_RGB, 1e-4); - ASSERT_MAT_NEAR(color1.diff(color2, D65_2, RGBL), diff_RGBL, 1e-4); -} - -} // namespace -} // namespace opencv_test \ No newline at end of file diff --git a/modules/mcc/test/test_colorspace.cpp b/modules/mcc/test/test_colorspace.cpp deleted file mode 100644 index 88e8284b9ed..00000000000 --- a/modules/mcc/test/test_colorspace.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. - -#include "test_precomp.hpp" - -namespace opencv_test -{ -namespace -{ - -TEST(CV_ccmColorspace, test_sRGB_M) -{ - Mat to = (Mat_(3, 3) << - 0.4124564, 0.3575761, 0.1804375, - 0.2126729, 0.7151522, 0.0721750, - 0.0193339, 0.1191920, 0.9503041); - Mat from = (Mat_(3, 3) << - 3.2404542, -1.5371385, -0.4985314, - -0.9692660, 1.8760108, 0.0415560, - 0.0556434, -0.2040259, 1.0572252); - ASSERT_MAT_NEAR((*GetCS::get_rgb(sRGB)).M_to, to, 1e-4); - ASSERT_MAT_NEAR((*GetCS::get_rgb(sRGB)).M_from, from, 1e-4); -} - -TEST(CV_ccmColorspace, test_AdobeRGB_M) -{ - Mat to = (Mat_(3, 3) << - 0.5767309, 0.1855540, 0.1881852, - 0.2973769, 0.6273491, 0.0752741, - 0.0270343, 0.0706872, 0.9911085); - Mat from = (Mat_(3, 3) << - 2.0413690, -0.5649464, -0.3446944, - -0.9692660, 1.8760108, 0.0415560, - 0.0134474, -0.1183897, 1.0154096); - ASSERT_MAT_NEAR((*GetCS::get_rgb(AdobeRGB)).M_to, to, 1e-4); - ASSERT_MAT_NEAR((*GetCS::get_rgb(AdobeRGB)).M_from, from, 1e-4); -} - -TEST(CV_ccmColorspace, test_WideGamutRGB_M) -{ - Mat to = (Mat_(3, 3) << - 0.7161046, 0.1009296, 0.1471858, - 0.2581874, 0.7249378, 0.0168748, - 0.0000000, 0.0517813, 0.7734287); - Mat from = (Mat_(3, 3) << - 1.4628067, -0.1840623, -0.2743606, - -0.5217933, 1.4472381, 0.0677227, - 0.0349342, -0.0968930, 1.2884099); - ASSERT_MAT_NEAR((*GetCS::get_rgb(WideGamutRGB)).M_to, to, 1e-2); - ASSERT_MAT_NEAR((*GetCS::get_rgb(WideGamutRGB)).M_from, from, 1e-2); -} - -TEST(CV_ccmColorspace, test_ProPhotoRGB_M) -{ - Mat to = (Mat_(3, 3) << - 0.7976749, 0.1351917, 0.0313534, - 0.2880402, 0.7118741, 0.0000857, - 0.0000000, 0.0000000, 0.8252100); - Mat from = (Mat_(3, 3) << - 1.3459433, -0.2556075, -0.0511118, - -0.5445989, 1.5081673, 0.0205351, - 0.0000000, 0.0000000, 1.2118128); - ASSERT_MAT_NEAR((*GetCS::get_rgb(ProPhotoRGB)).M_to, to, 1e-2); - ASSERT_MAT_NEAR((*GetCS::get_rgb(ProPhotoRGB)).M_from, from, 1e-2); -} - -} // namespace -} // namespace opencv_test diff --git a/modules/mcc/test/test_linearize.cpp b/modules/mcc/test/test_linearize.cpp deleted file mode 100644 index d90399fe475..00000000000 --- a/modules/mcc/test/test_linearize.cpp +++ /dev/null @@ -1,232 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. - -#include "test_precomp.hpp" - -namespace opencv_test -{ -namespace -{ - -Mat s_origin = (Mat_(24, 1) << - Vec3d(214.11, 98.67, 37.97), - Vec3d(231.94, 153.1, 85.27), - Vec3d(204.08, 143.71, 78.46), - Vec3d(190.58, 122.99, 30.84), - Vec3d(230.93, 148.46, 100.84), - Vec3d(228.64, 206.97, 97.5), - Vec3d(229.09, 137.07, 55.29), - Vec3d(189.21, 111.22, 92.66), - Vec3d(223.5, 96.42, 75.45), - Vec3d(201.82, 69.71, 50.9), - Vec3d(240.52, 196.47, 59.3), - Vec3d(235.73, 172.13, 54.), - Vec3d(131.6, 75.04, 68.86), - Vec3d(189.04, 170.43, 42.05), - Vec3d(222.23, 74., 71.95), - Vec3d(241.01, 199.1, 61.15), - Vec3d(224.99, 101.4, 100.24), - Vec3d(174.58, 152.63, 91.52), - Vec3d(248.06, 227.69, 140.5), - Vec3d(241.15, 201.38, 115.58), - Vec3d(236.49, 175.87, 88.86), - Vec3d(212.19, 133.49, 54.79), - Vec3d(181.17, 102.94, 36.18), - Vec3d(115.1, 53.77, 15.23)); -Mat s = s_origin / 255; -double gamma = 2.2; -int deg = 3; - -Color color = GetColor::get_color(Macbeth); -RGBBase_ cs = *GetCS::get_rgb(sRGB); -Mat mask = saturate(s, 0.05, 0.93); - -TEST(CV_ccmLinearize, test_identity) -{ - Mat y = (Mat_(24, 1) << - Vec3d(0.83964706, 0.38694118, 0.14890196), - Vec3d(0.90956863, 0.60039216, 0.33439216), - Vec3d(0.80031373, 0.56356863, 0.30768627), - Vec3d(0.74737255, 0.48231373, 0.12094118), - Vec3d(0.90560784, 0.58219608, 0.39545098), - Vec3d(0.89662745, 0.81164706, 0.38235294), - Vec3d(0.89839216, 0.53752941, 0.21682353), - Vec3d(0.742, 0.43615686, 0.36337255), - Vec3d(0.87647059, 0.37811765, 0.29588235), - Vec3d(0.79145098, 0.27337255, 0.19960784), - Vec3d(0.94321569, 0.77047059, 0.23254902), - Vec3d(0.92443137, 0.67501961, 0.21176471), - Vec3d(0.51607843, 0.29427451, 0.27003922), - Vec3d(0.74133333, 0.66835294, 0.16490196), - Vec3d(0.8714902, 0.29019608, 0.28215686), - Vec3d(0.94513725, 0.78078431, 0.23980392), - Vec3d(0.88231373, 0.39764706, 0.39309804), - Vec3d(0.68462745, 0.59854902, 0.35890196), - Vec3d(0.97278431, 0.89290196, 0.55098039), - Vec3d(0.94568627, 0.78972549, 0.4532549), - Vec3d(0.92741176, 0.68968627, 0.34847059), - Vec3d(0.83211765, 0.5234902 , 0.21486275), - Vec3d(0.71047059, 0.40368627, 0.14188235), - Vec3d(0.45137255, 0.21086275, 0.05972549)); - - ASSERT_MAT_NEAR(LinearIdentity().linearize(s), y, 1e-4); -} - -TEST(CV_ccmLinearize, test_gamma) -{ - Mat y = (Mat_(24, 1) << - Vec3d(0.68078957, 0.12382801, 0.01514889), - Vec3d(0.81177942, 0.32550452, 0.089818), - Vec3d(0.61259378, 0.2831933 , 0.07478902), - Vec3d(0.52696493, 0.20105976, 0.00958657), - Vec3d(0.80402284, 0.30419523, 0.12989841), - Vec3d(0.78658646, 0.63184111, 0.12062068), - Vec3d(0.78999637, 0.25520249, 0.03462853), - Vec3d(0.51866697, 0.16114393, 0.1078387), - Vec3d(0.74820768, 0.11770076, 0.06862177), - Vec3d(0.59776825, 0.05765816, 0.02886627), - Vec3d(0.8793145, 0.56346033, 0.0403954), - Vec3d(0.84124847, 0.42120746, 0.03287592), - Vec3d(0.23333214, 0.06780408, 0.05612276), - Vec3d(0.5176423, 0.41210976, 0.01896255), - Vec3d(0.73888613, 0.06575388, 0.06181293), - Vec3d(0.88326036, 0.58018751, 0.04321991), - Vec3d(0.75922531, 0.13149072, 0.1282041), - Vec3d(0.4345097, 0.32331019, 0.10494139), - Vec3d(0.94110142, 0.77941419, 0.26946323), - Vec3d(0.88438952, 0.5949049 , 0.17536928), - Vec3d(0.84722687, 0.44160449, 0.09834799), - Vec3d(0.66743106, 0.24076803, 0.03394333), - Vec3d(0.47141286, 0.13592419, 0.01362205), - Vec3d(0.17377101, 0.03256864, 0.00203026)); - - ASSERT_MAT_NEAR(LinearGamma(gamma).linearize(s), y, 1e-4); -} - -TEST(CV_ccmLinearize, test_color_polyfit) -{ - Mat y = (Mat_(24, 1) << - Vec3d(2.63480590e-01, 8.19784230e-02, 5.88380570e-02), - Vec3d(5.00308824e-01, 2.55670153e-01, 2.84774400e-01), - Vec3d(1.65547676e-01, 2.18326729e-01, 2.34834241e-01), - Vec3d(6.91579431e-02, 1.46243551e-01, 4.85506219e-02), - Vec3d(4.84584944e-01, 2.36873580e-01, 4.21828895e-01), - Vec3d(4.49999903e-01, 5.15593650e-01, 3.89716261e-01), - Vec3d(4.56680121e-01, 1.93624454e-01, 1.09260805e-01), - Vec3d(6.14667752e-02, 1.12219287e-01, 3.45822331e-01), - Vec3d(3.77645006e-01, 7.72485552e-02, 2.14671313e-01), - Vec3d(1.46690033e-01, 3.83676678e-02, 9.30261311e-02), - Vec3d(6.45841448e-01, 4.59722537e-01, 1.26168624e-01), - Vec3d(5.61924874e-01, 3.39304873e-01, 1.04244341e-01), - Vec3d(-1.24921202e-03, 4.34819857e-02, 1.74574965e-01), - Vec3d(6.05378564e-02, 3.31429676e-01, 6.74475908e-02), - Vec3d(3.60866062e-01, 4.23768038e-02, 1.92686670e-01), - Vec3d(6.54814616e-01, 4.73515714e-01, 1.34642338e-01), - Vec3d(3.97880165e-01, 8.80047529e-02, 4.15950016e-01), - Vec3d(8.88761384e-04, 2.53736288e-01, 3.35935826e-01), - Vec3d(7.92140863e-01, 6.31444183e-01, 9.20127919e-01), - Vec3d(6.57391804e-01, 4.85584457e-01, 5.81564694e-01), - Vec3d(5.74784077e-01, 3.56891943e-01, 3.13534251e-01), - Vec3d(2.42877023e-01, 1.80918764e-01, 1.07292088e-01), - Vec3d(2.34750448e-02, 9.15416417e-02, 5.56885760e-02), - Vec3d(4.16360011e-02, 3.14799517e-02, 4.67810688e-02)); - color.getGray(); - ASSERT_MAT_NEAR(LinearColor(deg, s, color, mask, cs).linearize(s), y, 1e-4); -} - -TEST(CV_ccmLinearize, test_color_logpolyfit) -{ - Mat y = (Mat_(24, 1) << - Vec3d(0.21210199, 0.08042872, 0.06177358), - Vec3d(0.43902276, 0.25803696, 0.22625212), - Vec3d(0.1392843, 0.21910892, 0.16649895), - Vec3d(0.07929871, 0.14429388, 0.06124959), - Vec3d(0.42175787, 0.23847603, 0.50200816), - Vec3d(0.38486859, 0.49908647, 0.41903521), - Vec3d(0.39187715, 0.19330825, 0.07678465), - Vec3d(0.07496683, 0.10997862, 0.3253915), - Vec3d(0.31256906, 0.07589457, 0.14682645), - Vec3d(0.12666458, 0.03865245, 0.07035133), - Vec3d(0.61317011, 0.453896, 0.08471713), - Vec3d(0.509618, 0.34295792, 0.07466823), - Vec3d(0.01792609, 0.04375426, 0.11416985), - Vec3d(0.07444757, 0.33517131, 0.06308572), - Vec3d(0.29675398, 0.04267084, 0.1279182), - Vec3d(0.62473933, 0.46546083, 0.08914635), - Vec3d(0.33211973, 0.08623901, 0.48580852), - Vec3d(0.04223237, 0.25602914, 0.30707565), - Vec3d(0.81340438, 0.57786249, 5.63433098), - Vec3d(0.62807965, 0.47536376, 1.17181577), - Vec3d(0.52493661, 0.36014609, 0.26894465), - Vec3d(0.19575899, 0.18007616, 0.0759408), - Vec3d(0.05430091, 0.08966718, 0.06150038), - Vec3d(0.02983422, 0.03045434, 0.03305337)); - color.getGray(); - ASSERT_MAT_NEAR(LinearColor(deg, s, color, mask, cs).linearize(s), y, 1e-4); -} - -TEST(CV_ccmLinearize, test_gray_polyfit) -{ - Mat y = (Mat_(24, 1) << - Vec3d(0.51666899, 0.05119734, 0.08355961), - Vec3d(0.59846831, 0.22746696, 0.03275719), - Vec3d(0.46851612, 0.18821734, 0.02831637), - Vec3d(0.40274707, 0.11294869, 0.10983447), - Vec3d(0.59401581, 0.20773439, 0.05530918), - Vec3d(0.58382767, 0.48249077, 0.04910519), - Vec3d(0.58583962, 0.16222916, 0.04147151), - Vec3d(0.39606823, 0.07893876, 0.04140637), - Vec3d(0.56052673, 0.0472528, 0.02748943), - Vec3d(0.45754742, 0.02793019, 0.04935323), - Vec3d(0.63517156, 0.43148826, 0.0358448), - Vec3d(0.61493813, 0.31386138, 0.04359845), - Vec3d(0.14207934, 0.02743228, 0.02822652), - Vec3d(0.39523985, 0.30585866, 0.07094004), - Vec3d(0.55468508, 0.02734776, 0.0274375), - Vec3d(0.6372021, 0.44431108, 0.03374266), - Vec3d(0.56733935, 0.05641847, 0.05414246), - Vec3d(0.32546855, 0.22544012, 0.0398225), - Vec3d(0.66553671, 0.57956479, 0.17545548), - Vec3d(0.63778086, 0.45540855, 0.09069633), - Vec3d(0.61819338, 0.33161218, 0.03647687), - Vec3d(0.50753594, 0.14890516, 0.0422774), - Vec3d(0.35705032, 0.05956936, 0.08964481), - Vec3d(0.0893518, 0.04399409, 0.18717526)); - color.getGray(); - ASSERT_MAT_NEAR(LinearGray(deg, s, color, mask, cs).linearize(s), y, 1e-4); -} - -TEST(CV_ccmLinearize, test_gray_logpolyfit) -{ - Mat y = (Mat_(24, 1) << - Vec3d(4.60331981e-01, 5.51120816e-02, 3.97365482e-01), - Vec3d(4.73679407e-01, 2.29393836e-01, 3.84195886e-02), - Vec3d(4.38764462e-01, 1.88051166e-01, 3.33576233e-02), - Vec3d(3.95560026e-01, 1.11621603e-01, 5.06142257e+00), - Vec3d(4.73785486e-01, 2.08586471e-01, 5.87127685e-02), - Vec3d(4.73648490e-01, 4.45971601e-01, 5.32792915e-02), - Vec3d(4.73716999e-01, 1.61001724e-01, 4.02782927e-02), - Vec3d(3.90399630e-01, 7.97334727e-02, 4.64809651e-02), - Vec3d(4.71407192e-01, 5.16538838e-02, 3.18491932e-02), - Vec3d(4.32594201e-01, 3.03426453e-02, 5.36226594e-02), - Vec3d(4.68788432e-01, 4.16218138e-01, 3.42954435e-02), - Vec3d(4.72387015e-01, 3.17700868e-01, 4.32262905e-02), - Vec3d(1.40435644e-01, 3.16799217e-02, 3.02925240e-02), - Vec3d(3.89750609e-01, 3.09885279e-01, 1.63338781e-01), - Vec3d(4.70437333e-01, 3.12909236e-02, 3.07003735e-02), - Vec3d(4.68300410e-01, 4.24570259e-01, 3.26637048e-02), - Vec3d(4.72334300e-01, 5.96850848e-02, 5.76907392e-02), - Vec3d(3.28844114e-01, 2.27258414e-01, 4.50583791e-02), - Vec3d(4.58942833e-01, 4.73436696e-01, 1.74710299e-01), - Vec3d(4.68156974e-01, 4.31339830e-01, 9.05259853e-02), - Vec3d(4.71960375e-01, 3.34642678e-01, 4.19957551e-02), - Vec3d(4.56964629e-01, 1.47352730e-01, 4.13462335e-02), - Vec3d(3.57831381e-01, 6.24515609e-02, 6.54872609e-01), - Vec3d(8.92793201e-02, 4.38221622e-02, 3.22837394e+08)); - color.getGray(); - ASSERT_MAT_NEAR(LinearGray(deg, s, color, mask, cs).linearize(s)(cv::Rect(0, 0, 1, 23)), y(cv::Rect(0, 0, 1, 23)), 1e-4); -} - -} // namespace -} // namespace opencv_test \ No newline at end of file diff --git a/modules/mcc/test/test_utils.cpp b/modules/mcc/test/test_utils.cpp deleted file mode 100644 index f7fe5ca2160..00000000000 --- a/modules/mcc/test/test_utils.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. - -#include "test_precomp.hpp" - -namespace opencv_test -{ -namespace -{ - -TEST(CV_ccmUtils, test_gamma_correction) -{ - Mat x = (Mat_(4, 3) << - 0.8, -0.5, 0.6, - 0.2, 0.9, -0.9, - 1. , -0.2 , 0.4, - -0.4, 0.1, 0.3); - Mat y = (Mat_(4, 3) << - 0.6120656, -0.21763764, 0.32503696, - 0.02899119, 0.79311017, -0.79311017, - 1., -0.02899119, 0.13320851, - -0.13320851, 0.00630957, 0.07074028); - ASSERT_MAT_NEAR(gammaCorrection(x, 2.2), y, 1e-4); -} - -TEST(CV_ccmUtils, test_saturate) -{ - Mat x = (Mat_(5, 1) << - Vec3d(0., 0.5, 0.), - Vec3d(0., 0.3, 0.4), - Vec3d(0.3, 0.8, 0.4), - Vec3d(0.7, 0.6, 0.2), - Vec3d(1., 0.8, 0.5)); - Mat y = (Mat_(5, 1) <(1, 1) << Vec3d(0.2, 0.3, 0.4)); - Mat y = (Mat_(1, 1) <<0.28596); - ASSERT_MAT_NEAR(rgb2gray(x), y, 1e-4); -} - -} // namespace -} // namespace opencv_test From 785934ccd10b4f538ffd10d5dfad0093d5b2e68b Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Sun, 8 Nov 2020 17:22:57 +0800 Subject: [PATCH 40/71] add hpp to opencv/model/mcc/ --- modules/mcc/src/ccmimpl.cpp | 0 modules/mcc/src/color.hpp | 130 ++++++++++ modules/mcc/src/colorspace.hpp | 431 +++++++++++++++++++++++++++++++++ modules/mcc/src/distance.hpp | 114 +++++++++ modules/mcc/src/io.hpp | 82 +++++++ modules/mcc/src/linearize.hpp | 225 +++++++++++++++++ modules/mcc/src/operations.hpp | 101 ++++++++ modules/mcc/src/utils.hpp | 153 ++++++++++++ 8 files changed, 1236 insertions(+) create mode 100644 modules/mcc/src/ccmimpl.cpp create mode 100644 modules/mcc/src/color.hpp create mode 100644 modules/mcc/src/colorspace.hpp create mode 100644 modules/mcc/src/distance.hpp create mode 100644 modules/mcc/src/io.hpp create mode 100644 modules/mcc/src/linearize.hpp create mode 100644 modules/mcc/src/operations.hpp create mode 100644 modules/mcc/src/utils.hpp diff --git a/modules/mcc/src/ccmimpl.cpp b/modules/mcc/src/ccmimpl.cpp new file mode 100644 index 00000000000..e69de29bb2d diff --git a/modules/mcc/src/color.hpp b/modules/mcc/src/color.hpp new file mode 100644 index 00000000000..7e119b70519 --- /dev/null +++ b/modules/mcc/src/color.hpp @@ -0,0 +1,130 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#ifndef __OPENCV_MCC_COLOR_HPP__ +#define __OPENCV_MCC_COLOR_HPP__ + +#include +//#include "opencv2/mcc/colorspace.hpp" +#include "distance.hpp" +#include "colorspace.hpp" +#include "opencv2/mcc/ccm.hpp" + + +namespace cv +{ +namespace ccm +{ + +/** @brief Color defined by color_values and color space +*/ + +class CV_EXPORTS_W Color +{ +public: + + /** @param grays mask of grayscale color + @param colored mask of colored color + @param history storage of historical conversion + */ + Mat colors; + const ColorSpace& cs ; + Mat grays; + Mat colored; + std::map> history; + Color(); + Color(Mat colors_, enum COLOR_SPACE cs_); + Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_); + // Color(CONST_COLOR constcolor); + Color(Mat colors_, const ColorSpace& cs_, Mat colored_); + Color(Mat colors_, const ColorSpace& cs_); + + virtual ~Color() {}; + + /** @brief Change to other color space. + The conversion process incorporates linear transformations to speed up. + @param other type of ColorSpace. + @param method the chromatic adapation method. + @param save when save if True, get data from history first. + @return Color. + */ + Color to(COLOR_SPACE other, CAM method = BRADFORD, bool save = true); + Color to(const ColorSpace& other, CAM method = BRADFORD, bool save = true); + /** @brief Channels split. + @return each channel. + */ + Mat channel(Mat m, int i); + + /** @brief To Gray. + */ + Mat toGray(IO io, CAM method = BRADFORD, bool save = true); + + /** @brief To Luminant. + */ + Mat toLuminant(IO io, CAM method = BRADFORD, bool save = true); + + /** @brief Diff without IO. + @param other type of Color. + @param method type of distance. + @return distance between self and other + */ + Mat diff(Color& other, DISTANCE_TYPE method = CIE2000); + + /** @brief Diff with IO. + @param other type of Color. + @param io type of IO. + @param method type of distance. + @return distance between self and other + */ + Mat diff(Color& other, IO io, DISTANCE_TYPE method = CIE2000); + + /** @brief Calculate gray mask. + */ + void getGray(double JDN = 2.0); + + /** @brief Operator for mask copy. + */ + Color operator[](Mat mask); + +}; + + +class CV_EXPORTS_W GetColor { +public: + static Color get_color(CONST_COLOR const_color); + static double create(); + static Mat get_ColorChecker(const double *checker,int row); + static Mat get_ColorChecker_MASK(const uchar *checker,int row); +}; + + + +} // namespace ccm +} // namespace cv + + +#endif \ No newline at end of file diff --git a/modules/mcc/src/colorspace.hpp b/modules/mcc/src/colorspace.hpp new file mode 100644 index 00000000000..f89d124aabe --- /dev/null +++ b/modules/mcc/src/colorspace.hpp @@ -0,0 +1,431 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + + +#ifndef __OPENCV_MCC_COLORSPACE_HPP__ +#define __OPENCV_MCC_COLORSPACE_HPP__ + +#include +#include +#include +#include "operations.hpp" +#include "io.hpp" +#include "opencv2/mcc/ccm.hpp" + +namespace cv +{ +namespace ccm +{ + +/** Supported Color Space. +*/ +// enum COLOR_SPACE { +// sRGB, +// sRGBL, +// AdobeRGB, +// AdobeRGBL, +// WideGamutRGB, +// WideGamutRGBL, +// ProPhotoRGB, +// ProPhotoRGBL, +// DCI_P3_RGB, +// DCI_P3_RGBL, +// AppleRGB, +// AppleRGBL, +// REC_709_RGB, +// REC_709_RGBL, +// REC_2020_RGB, +// REC_2020_RGBL, +// XYZ_D65_2, +// XYZ_D65_10, +// XYZ_D50_2, +// XYZ_D50_10, +// XYZ_A_2, +// XYZ_A_10, +// XYZ_D55_2, +// XYZ_D55_10, +// XYZ_D75_2, +// XYZ_D75_10, +// XYZ_E_2, +// XYZ_E_10, +// Lab_D65_2, +// Lab_D65_10, +// Lab_D50_2, +// Lab_D50_10, +// Lab_A_2, +// Lab_A_10, +// Lab_D55_2, +// Lab_D55_10, +// Lab_D75_2, +// Lab_D75_10, +// Lab_E_2, +// Lab_E_10 +// }; + +/** @brief Basic class for ColorSpace. +*/ +class CV_EXPORTS_W ColorSpace +{ +public: + IO io; + std::string type; + bool linear; + Operations to; + Operations from; + ColorSpace* l; + ColorSpace* nl; + + ColorSpace() {}; + + ColorSpace(IO io_, std::string type_, bool linear_) :io(io_), type(type_), linear(linear_) {}; + + virtual ~ColorSpace() + { + l = 0; + nl = 0; + }; + virtual bool relate(const ColorSpace& other) const; + + virtual Operations relation(const ColorSpace& /*other*/) const; + + bool operator<(const ColorSpace& other)const; + +}; + +/** @brief Base of RGB color space; + the argument values are from AdobeRGB; + Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space +*/ + +class CV_EXPORTS_W RGBBase_ : public ColorSpace +{ +public: + // primaries + double xr; + double yr; + double xg; + double yg; + double xb; + double yb; + MatFunc toL; + MatFunc fromL; + Mat M_to; + Mat M_from; + + using ColorSpace::ColorSpace; + + /** @brief There are 3 kinds of relationships for RGB: + 1. Different types; - no operation + 1. Same type, same linear; - copy + 2. Same type, different linear, self is nonlinear; - 2 toL + 3. Same type, different linear, self is linear - 3 fromL + @param other type of ColorSpace. + @return Operations. + */ + Operations relation(const ColorSpace& other) const CV_OVERRIDE; + + /** @brief Initial operations. + */ + void init(); + /** @brief Produce color space instance with linear and non-linear versions. + @param rgbl type of RGBBase_. + */ + void bind(RGBBase_& rgbl); + +private: + virtual void setParameter() {}; + + /** @brief Calculation of M_RGBL2XYZ_base. + see ColorSpace.pdf for details. + */ + virtual void calM(); + + /** @brief operations to or from XYZ. + */ + virtual void calOperations(); + + virtual void calLinear() {}; + + virtual Mat toLFunc(Mat& /*rgb*/); + + virtual Mat fromLFunc(Mat& /*rgbl*/); + + +}; + +/** @brief Base of Adobe RGB color space; +*/ +class CV_EXPORTS_W AdobeRGBBase_ : public RGBBase_ + +{ +public: + using RGBBase_::RGBBase_; + double gamma; + +private: + Mat toLFunc(Mat& rgb) CV_OVERRIDE; + Mat fromLFunc(Mat& rgbl) CV_OVERRIDE; +}; + +/** @brief Base of sRGB color space; +*/ +class CV_EXPORTS_W sRGBBase_ : public RGBBase_ + +{ +public: + using RGBBase_::RGBBase_; + double a; + double gamma; + double alpha; + double beta; + double phi; + double K0; + +private: + /** @brief linearization parameters + see ColorSpace.pdf for details; + */ + virtual void calLinear() CV_OVERRIDE; + /** @brief Used by toLFunc. + */ + double toLFuncEW(double& x); + + /** @brief Linearization. + see ColorSpace.pdf for details. + @param rgb the input array, type of cv::Mat. + @return the output array, type of cv::Mat. + */ + Mat toLFunc(Mat& rgb) CV_OVERRIDE; + + /** @brief Used by fromLFunc. + */ + double fromLFuncEW(double& x); + + /** @brief Delinearization. + see ColorSpace.pdf for details. + @param rgbl the input array, type of cv::Mat. + @return the output array, type of cv::Mat. + */ + Mat fromLFunc(Mat& rgbl) CV_OVERRIDE; + +}; + +/** @brief sRGB color space. + data from https://en.wikipedia.org/wiki/SRGB. +*/ +class CV_EXPORTS_W sRGB_ :public sRGBBase_ + +{ +public: + sRGB_(bool linear_) :sRGBBase_(D65_2, "sRGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE; +}; + +/** @brief Adobe RGB color space. +*/ +class CV_EXPORTS_W AdobeRGB_ : public AdobeRGBBase_ +{ +public: + AdobeRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AdobeRGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE; + +}; + +/** @brief Wide-gamut RGB color space. + data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. +*/ +class CV_EXPORTS_W WideGamutRGB_ : public AdobeRGBBase_ +{ +public: + WideGamutRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "WideGamutRGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE; +}; + +/** @brief ProPhoto RGB color space. + data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. +*/ + +class CV_EXPORTS_W ProPhotoRGB_ : public AdobeRGBBase_ +{ +public: + ProPhotoRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "ProPhotoRGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE; +}; + +/** @brief DCI-P3 RGB color space. + data from https://en.wikipedia.org/wiki/DCI-P3. +*/ +class CV_EXPORTS_W DCI_P3_RGB_ : public AdobeRGBBase_ +{ +public: + DCI_P3_RGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "DCI_P3_RGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE; +}; + +/** @brief Apple RGB color space. + data from http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. +*/ +class CV_EXPORTS_W AppleRGB_ : public AdobeRGBBase_ +{ +public: + AppleRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AppleRGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE; +}; + +/** @brief REC_709 RGB color space. + data from https://en.wikipedia.org/wiki/Rec._709. +*/ +class CV_EXPORTS_W REC_709_RGB_ : public sRGBBase_ +{ +public: + REC_709_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_709_RGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE; +}; + +/** @brief REC_2020 RGB color space. + data from https://en.wikipedia.org/wiki/Rec._2020. +*/ +class CV_EXPORTS_W REC_2020_RGB_ : public sRGBBase_ +{ +public: + REC_2020_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_2020_RGB", linear_) {}; + +private: + void setParameter() CV_OVERRIDE; +}; + + +/** @brief Enum of the possible types of CAMs. +*/ +enum CAM +{ + IDENTITY, + VON_KRIES, + BRADFORD +}; + +static std::map , Mat > cams; +const static Mat Von_Kries = (Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); +const static Mat Bradford = (Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); +const static std::map > MAs = { + {IDENTITY , { Mat::eye(Size(3,3),CV_64FC1) , Mat::eye(Size(3,3),CV_64FC1)} }, + {VON_KRIES, { Von_Kries ,Von_Kries.inv() }}, + {BRADFORD, { Bradford ,Bradford.inv() }} +}; + +/** @brief XYZ color space. + Chromatic adaption matrices. +*/ +class CV_EXPORTS_W XYZ :public ColorSpace +{ +public: + XYZ(IO io_) : ColorSpace(io_, "XYZ", true) {}; + Operations cam(IO dio, CAM method = BRADFORD); + static std::map > xyz_cs; + static std::shared_ptr get(IO io); + +private: + /** @brief Get cam. + @param sio the input IO of src. + @param dio the input IO of dst. + @param method type of CAM. + @return the output array, type of cv::Mat. + */ + Mat cam_(IO sio, IO dio, CAM method = BRADFORD) const; +}; + +/** @brief Define XYZ_D65_2 and XYZ_D50_2. +*/ +const XYZ XYZ_D65_2_CS(D65_2); +const XYZ XYZ_D50_2_CS(D50_2); + +/** @brief Lab color space. +*/ +class CV_EXPORTS_W Lab :public ColorSpace +{ +public: + static std::map > lab_cs; + Lab(IO io_); + static std::shared_ptr get(IO io); + +private: + static constexpr double delta = (6. / 29.); + static constexpr double m = 1. / (3. * delta * delta); + static constexpr double t0 = delta * delta * delta; + static constexpr double c = 4. / 29.; + + Vec3d fromxyz(Vec3d& xyz); + + + /** @brief Calculate From. + @param src the input array, type of cv::Mat. + @return the output array, type of cv::Mat + */ + Mat fromsrc(Mat& src); + + Vec3d tolab(Vec3d& lab); + + /** @brief Calculate To. + @param src the input array, type of cv::Mat. + @return the output array, type of cv::Mat + */ + Mat tosrc(Mat& src); +}; + +/** @brief Define Lab_D65_2 and Lab_D50_2. +*/ +const Lab Lab_D65_2_CS(D65_2); +const Lab Lab_D50_2_CS(D50_2); + +//static std::map map_cs ; + +class CV_EXPORTS_W GetCS { +public: + static std::map > map_cs; + static std::shared_ptr get_rgb(enum COLOR_SPACE cs_name); + static std::shared_ptr get_cs(enum COLOR_SPACE cs_name); +}; + + +} // namespace ccm +} // namespace cv + +#endif \ No newline at end of file diff --git a/modules/mcc/src/distance.hpp b/modules/mcc/src/distance.hpp new file mode 100644 index 00000000000..bdb997646af --- /dev/null +++ b/modules/mcc/src/distance.hpp @@ -0,0 +1,114 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#ifndef __OPENCV_MCC_DISTANCE_HPP__ +#define __OPENCV_MCC_DISTANCE_HPP__ + +#include "utils.hpp" +#include "opencv2/mcc/ccm.hpp" + +namespace cv +{ +namespace ccm +{ +// enum DISTANCE_TYPE +// { +// CIE76, +// CIE94_GRAPHIC_ARTS, +// CIE94_TEXTILES, +// CIE2000, +// CMC_1TO1, +// CMC_2TO1, +// RGB, +// RGBL +// }; + + +/** @brief distance between two points in formula CIE76 + @param lab1 a 3D vector + @param lab2 a 3D vector + @return distance between lab1 and lab2 +*/ + +double deltaCIE76(Vec3d lab1, Vec3d lab2); + +/** @brief distance between two points in formula CIE94 + @param lab1 a 3D vector + @param lab2 a 3D vector + @param kH Hue scale + @param kC Chroma scale + @param kL Lightness scale + @param k1 first scale parameter + @param k2 second scale parameter + @return distance between lab1 and lab2 +*/ + +double deltaCIE94(Vec3d lab1, Vec3d lab2, double kH = 1.0, + double kC = 1.0, double kL = 1.0, double k1 = 0.045, + double k2 = 0.015); + +double deltaCIE94GraphicArts(Vec3d lab1, Vec3d lab2); + +double toRad(double degree); + +double deltaCIE94Textiles(Vec3d lab1, Vec3d lab2); + + +/** @brief distance between two points in formula CIE2000 + @param lab1 a 3D vector + @param lab2 a 3D vector + @param kL Lightness scale + @param kC Chroma scale + @param kH Hue scale + @return distance between lab1 and lab2 +*/ +double deltaCIEDE2000_(Vec3d lab1, Vec3d lab2, double kL = 1.0, + double kC = 1.0, double kH = 1.0); +double deltaCIEDE2000(Vec3d lab1, Vec3d lab2); + + +/** @brief distance between two points in formula CMC + @param lab1 a 3D vector + @param lab2 a 3D vector + @param kL Lightness scale + @param kC Chroma scale + @return distance between lab1 and lab2 +*/ + +double deltaCMC(Vec3d lab1, Vec3d lab2, double kL = 1, double kC = 1); + +double deltaCMC1To1(Vec3d lab1, Vec3d lab2); + +double deltaCMC2To1(Vec3d lab1, Vec3d lab2); + +Mat distance(Mat src, Mat ref, DISTANCE_TYPE distance_type); + +} // namespace ccm +} // namespace cv + + +#endif \ No newline at end of file diff --git a/modules/mcc/src/io.hpp b/modules/mcc/src/io.hpp new file mode 100644 index 00000000000..0b44a8561a2 --- /dev/null +++ b/modules/mcc/src/io.hpp @@ -0,0 +1,82 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + + +#ifndef __OPENCV_MCC_IO_HPP__ +#define __OPENCV_MCC_IO_HPP__ + + +#include +#include + + +namespace cv +{ +namespace ccm +{ + +/** @brief Io is the meaning of illuminant and observer. See notes of ccm.hpp + for supported list for illuminant and observer*/ +class CV_EXPORTS_W IO +{ +public: + std::string illuminant; + std::string observer; + IO(){}; + IO(std::string illuminant_, std::string observer_) ; + virtual ~IO(){}; + bool operator<(const IO& other) const; + bool operator==(const IO& other) const; + +}; + +const IO A_2("A", "2"), A_10("A", "10"), + D50_2("D50", "2"), D50_10("D50", "10"), + D55_2("D55", "2"), D55_10("D55", "10"), + D65_2("D65", "2"), D65_10("D65", "10"), + D75_2("D75", "2"), D75_10("D75", "10"), + E_2("E", "2"), E_10("E", "10"); + +// data from https://en.wikipedia.org/wiki/Standard_illuminant. +const static std::map> illuminants_xy = +{ + {A_2, { 0.44757, 0.40745 }}, {A_10, { 0.45117, 0.40594 }}, + {D50_2, { 0.34567, 0.35850 }}, {D50_10, { 0.34773, 0.35952 }}, + {D55_2, { 0.33242, 0.34743 }}, {D55_10, { 0.33411, 0.34877 }}, + {D65_2, { 0.31271, 0.32902 }}, {D65_10, { 0.31382, 0.33100 }}, + {D75_2, { 0.29902, 0.31485 }}, {D75_10, { 0.45117, 0.40594 }}, + {E_2, { 1 / 3, 1 / 3 }}, {E_10, { 1 / 3, 1 / 3 }}, +}; + +std::vector xyY2XYZ(const std::vector& xyY); + + +} // namespace ccm +} // namespace cv + + +#endif \ No newline at end of file diff --git a/modules/mcc/src/linearize.hpp b/modules/mcc/src/linearize.hpp new file mode 100644 index 00000000000..46e51cae001 --- /dev/null +++ b/modules/mcc/src/linearize.hpp @@ -0,0 +1,225 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + + +#ifndef __OPENCV_MCC_LINEARIZE_HPP__ +#define __OPENCV_MCC_LINEARIZE_HPP__ + +//#include "opencv2/mcc/color.hpp" +#include "color.hpp" +#include "opencv2/mcc/ccm.hpp" +namespace cv +{ +namespace ccm +{ + +// /** @brief Enum of the possible types of linearization. +// */ +// enum LINEAR_TYPE +// { +// IDENTITY_, +// GAMMA, +// COLORPOLYFIT, +// COLORLOGPOLYFIT, +// GRAYPOLYFIT, +// GRAYLOGPOLYFIT +// }; + +/** @brief Polyfit model. +*/ +class CV_EXPORTS_W Polyfit +{ +public: + int deg; + Mat p; + Polyfit() {}; + + /** @brief Polyfit method. + https://en.wikipedia.org/wiki/Polynomial_regression + polynomial: yi = a0 + a1*xi + a2*xi^2 + ... + an*xi^deg (i = 1,2,...,n) + and deduct: Ax = y + See linear.pdf for details + */ + Polyfit(Mat x, Mat y, int deg_); + virtual ~Polyfit() {}; + Mat operator()(const Mat& inp); + +private: + double fromEW(double x); + +}; + +/** @brief Logpolyfit model. +*/ +class CV_EXPORTS_W LogPolyfit + +{ +public: + int deg; + Polyfit p; + + LogPolyfit() {}; + + /** @brief Logpolyfit method. + */ + LogPolyfit(Mat x, Mat y, int deg_); + virtual ~LogPolyfit() {}; + Mat operator()(const Mat& inp); + +}; + +/** @brief Linearization base. +*/ + +class CV_EXPORTS_W Linear +{ +public: + Linear() {}; + virtual ~Linear() {}; + + /** @brief Inference. + @param inp the input array, type of cv::Mat. + */ + virtual Mat linearize(Mat inp); + /* *\brief Evaluate linearization model. + */ + virtual void value(void) {}; +}; + + +/** @brief Linearization identity. + make no change. +*/ +class CV_EXPORTS_W LinearIdentity : public Linear {}; + +/** @brief Linearization gamma correction. +*/ +class CV_EXPORTS_W LinearGamma : public Linear +{ +public: + double gamma; + + LinearGamma(double gamma_) :gamma(gamma_) {}; + + Mat linearize(Mat inp) CV_OVERRIDE; +}; + +/** @brief Linearization. + Grayscale polynomial fitting. +*/ +template +class LinearGray :public Linear +{ +public: + int deg; + T p; + LinearGray(int deg_, Mat src, Color dst, Mat mask, RGBBase_ cs) :deg(deg_) + { + dst.getGray(); + Mat lear_gray_mask = mask & dst.grays; + + // the grayscale function is approximate for src is in relative color space. + src = rgb2gray(maskCopyTo(src, lear_gray_mask)); + Mat dst_ = maskCopyTo(dst.toGray(cs.io), lear_gray_mask); + calc(src, dst_); + } + + /** @brief monotonically increase is not guaranteed. + @param src the input array, type of cv::Mat. + @param dst the input array, type of cv::Mat. + */ + void calc(const Mat& src, const Mat& dst) + { + p = T(src, dst, deg); + }; + + Mat linearize(Mat inp) CV_OVERRIDE + { + return p(inp); + }; +}; + +/** @brief Linearization. + Fitting channels respectively. +*/ +template +class LinearColor :public Linear +{ +public: + int deg; + T pr; + T pg; + T pb; + + LinearColor(int deg_, Mat src_, Color dst, Mat mask, RGBBase_ cs) :deg(deg_) + { + Mat src = maskCopyTo(src_, mask); + Mat dst_ = maskCopyTo(dst.to(*cs.l).colors, mask); + calc(src, dst_); + } + + void calc(const Mat& src, const Mat& dst) + { + Mat schannels[3]; + Mat dchannels[3]; + split(src, schannels); + split(dst, dchannels); + pr = T(schannels[0], dchannels[0], deg); + pg = T(schannels[1], dchannels[1], deg); + pb = T(schannels[2], dchannels[2], deg); + }; + + Mat linearize(Mat inp) CV_OVERRIDE + { + Mat channels[3]; + split(inp, channels); + std::vector channel; + Mat res; + merge(std::vector{ pr(channels[0]), pg(channels[1]), pb(channels[2]) }, res); + return res; + }; +}; + +/** @brief Get linearization method. + used in ccm model. + @param gamma used in LinearGamma. + @param deg degrees. + @param src the input array, type of cv::Mat. + @param dst the input array, type of cv::Mat. + @param mask the input array, type of cv::Mat. + @param cs type of RGBBase_. + @param linear_type type of linear. +*/ + +std::shared_ptr getLinear(double gamma, int deg, Mat src, Color dst, Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type); + + +} // namespace ccm +} // namespace cv + + +#endif diff --git a/modules/mcc/src/operations.hpp b/modules/mcc/src/operations.hpp new file mode 100644 index 00000000000..5e2eb96cce4 --- /dev/null +++ b/modules/mcc/src/operations.hpp @@ -0,0 +1,101 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + + +#ifndef __OPENCV_MCC_OPERATIONS_HPP__ +#define __OPENCV_MCC_OPERATIONS_HPP__ + +#include +#include +//#include "opencv2/mcc/utils.hpp" +#include "utils.hpp" + +namespace cv +{ +namespace ccm +{ + +typedef std::function MatFunc; + +/** @brief Operation class contains some operarions used for color space + conversion containing linear transformation and non-linear transformation + */ +class CV_EXPORTS_W Operation +{ +public: + bool linear; + Mat M; + MatFunc f; + + Operation() : linear(true), M(Mat()) {}; + + Operation(Mat M_) :linear(true), M(M_) {}; + + Operation(MatFunc f_) : linear(false), f(f_) {}; + virtual ~Operation() {}; + + /** @brief operator function will run operation + */ + Mat operator()(Mat& abc); + + /** @brief add function will conbine this operation + with other linear transformation operation + */ + void add(const Operation& other); + + void clear(); +}; + +const Operation IDENTITY_OP([](Mat x) {return x; }); + +class CV_EXPORTS_W Operations +{ +public: + std::vector ops; + + Operations() :ops{ } {}; + + Operations(std::initializer_list op) :ops{ op } {}; + + virtual ~Operations() {}; + + /** @brief add function will conbine this operation with other transformation operations + */ + Operations& add(const Operations& other); + + /** @brief run operations to make color conversion + */ + Mat run(Mat abc); +}; + +const Operations IDENTITY_OPS{ IDENTITY_OP }; + +} // namespace ccm +} // namespace cv + + +#endif \ No newline at end of file diff --git a/modules/mcc/src/utils.hpp b/modules/mcc/src/utils.hpp new file mode 100644 index 00000000000..989971cb0fb --- /dev/null +++ b/modules/mcc/src/utils.hpp @@ -0,0 +1,153 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright(C) 2020, Huawei Technologies Co.,Ltd. All rights reserved. +// Third party copyrights are property of their respective owners. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Longbu Wang +// Jinheng Zhang +// Chenqi Shan + +#ifndef __OPENCV_MCC_UTILS_HPP__ +#define __OPENCV_MCC_UTILS_HPP__ + +#include + +namespace cv { +namespace ccm { + +CV_EXPORTS_W double gammaCorrection_(const double& element, const double& gamma); + +/** @brief gamma correction ,see ColorSpace.pdf for details. + @param src the input array,type of Mat. + @param gamma a constant for gamma correction. + */ +CV_EXPORTS_W Mat gammaCorrection(const Mat& src, const double& gamma); + +/** @brief maskCopyTo a function to delete unsatisfied elementwise. + @param src the input array, type of Mat. + @param mask operation mask that used to choose satisfided elementwise. + */ +CV_EXPORTS_W Mat maskCopyTo(const Mat& src, const Mat& mask); + +/** @brief multiple the function used to compute an array with n channels + mulipied by ccm. + @param xyz the input array, type of Mat. + @param ccm the ccm matrix to make color correction. + */ +CV_EXPORTS_W Mat multiple(const Mat& xyz, const Mat& ccm); + +/** @brief multiple the function used to get the mask of saturated colors, + colors between low and up will be choosed. + @param src the input array, type of Mat. + @param low the threshold to choose saturated colors + @param up the threshold to choose saturated colors +*/ +CV_EXPORTS_W Mat saturate(Mat& src, const double& low, const double& up); + +/** @brief rgb2gray it is an approximation grayscale function for relative RGB + color space, see Miscellaneous.pdf for details; + @param rgb the input array,type of Mat. + */ +CV_EXPORTS_W Mat rgb2gray(Mat rgb); + +/** @brief function for elementWise operation + @param src the input array, type of Mat + @param lambda a for operation + */ +template +Mat elementWise(const Mat& src, F&& lambda) +{ + Mat dst = src.clone(); + const int channel = src.channels(); + switch (channel) + { + case 1: + { + + MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) + { + (*it) = lambda((*it)); + } + break; + } + case 3: + { + MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) + { + for (int j = 0; j < 3; j++) + { + (*it)[j] = lambda((*it)[j]); + } + } + break; + } + default: + throw std::invalid_argument { "Wrong channel!" }; + break; + } + return dst; +} + +/** @brief function for channel operation + @param src the input array, type of Mat + @param lambda the function for operation +*/ +template +Mat channelWise(const Mat& src, F&& lambda) +{ + Mat dst = src.clone(); + MatIterator_ it, end; + for (it = dst.begin(), end = dst.end(); it != end; ++it) + { + *it = lambda(*it); + } + return dst; +} + +/** @brief function for distance operation. + @param src the input array, type of Mat. + @param ref another input array, type of Mat. + @param lambda the computing method for distance . + */ +template +Mat distanceWise(Mat& src, Mat& ref, F&& lambda) +{ + Mat dst = Mat(src.size(), CV_64FC1); + MatIterator_ it_src = src.begin(), end_src = src.end(), + it_ref = ref.begin(); + MatIterator_ it_dst = dst.begin(); + for (; it_src != end_src; ++it_src, ++it_ref, ++it_dst) + { + *it_dst = lambda(*it_src, *it_ref); + } + return dst; +} + +CV_EXPORTS_W Mat multiple(const Mat& xyz, const Mat& ccm); + +const static Mat m_gray = (Mat_(3, 1) << 0.2126, 0.7152, 0.0722); + +} // namespace ccm +} // namespace cv + +#endif \ No newline at end of file From 4e1b46c5cdabbcd6c8c8dc05295081fb918d1ed4 Mon Sep 17 00:00:00 2001 From: shanchenqi Date: Mon, 9 Nov 2020 17:03:54 +0800 Subject: [PATCH 41/71] dst unsolved --- modules/mcc/src/ccm.cpp | 24 +++++++++++++++++------- modules/mcc/src/color.cpp | 14 +++++++------- modules/mcc/src/color.hpp | 4 ++-- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 740c8d85c22..40588886b67 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -120,6 +120,7 @@ namespace ccm void get_color(Mat& img_, bool islinear = false); void get_color(CONST_COLOR constcolor); void get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_); + void get_color(Mat colors_, COLOR_SPACE ref_cs_); /** @brief Loss function base on cv::MinProblemSolver::Function. @@ -160,7 +161,7 @@ namespace ccm // { // // run(); // } //写成默认参数 -ColorCorrectionModel::Impl::Impl():cs(sRGB),ccm_type(CCM_3x3), distance(CIE2000),linear_type(GAMMA),gamma(2.2),deg(3),saturated_threshold({ 0, 0.98 }), +ColorCorrectionModel::Impl::Impl():cs(*GetCS::get_rgb(sRGB)),ccm_type(CCM_3x3), distance(CIE2000),linear_type(GAMMA),gamma(2.2),deg(3),saturated_threshold({ 0, 0.98 }), weights(Mat()),weights_coeff(0),initial_method_type(LEAST_SQUARE),max_count(5000),epsilon(1.e-4) { // run(); @@ -332,13 +333,13 @@ Mat ColorCorrectionModel::Impl::inferImage(Mat& img_, bool islinear) return out_img; } void ColorCorrectionModel::Impl::get_color(CONST_COLOR constcolor){ - p->dst = GetColor::get_color(constcolor); + dst = GetColor::get_color(constcolor); } void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE ref_cs_){ - p->dst = Color(colors_, *GetCS::get_cs(ref_cs_)); + dst = Color(colors_, *GetCS::get_cs(ref_cs_)); } void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_){ - p->dst =Color(colors_, *GetCS::get_cs(cs_),colored_); + dst =Color(colors_, *GetCS::get_cs(cs_),colored_); } ColorCorrectionModel::ColorCorrectionModel(Mat src_, CONST_COLOR constcolor): p(new Impl){ p->src = src_; @@ -413,9 +414,18 @@ ColorCorrectionModel::ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE cs // } +//void ColorCorrectionModel::setDst(CONST_COLOR constcolor) { +// p->dst = GetColor::get_color(constcolor); +//} +//void ColorCorrectionModel::setDst(Mat colors_, COLOR_SPACE ref_cs_) { +// p->dst = Color(colors_, *GetCS::get_cs(ref_cs_)); +//} +//void ColorCorrectionModel::setDst(Mat colors_, COLOR_SPACE cs_, Mat colored_) { +// p->dst = Color(colors_, *GetCS::get_cs(cs_), colored_); +//} void ColorCorrectionModel::setColorSpace(COLOR_SPACE cs_){ - p->cs = cs_; + p->cs = *GetCS::get_rgb(cs_); } void ColorCorrectionModel::setCCM(CCM_TYPE ccm_type_){ p->ccm_type = ccm_type_; @@ -454,8 +464,8 @@ void ColorCorrectionModel::setEpsilon(double epsilon_){ bool ColorCorrectionModel::run(){ Mat saturate_mask = saturate(p->src, p->saturated_threshold[0], p->saturated_threshold[1]); - p->linear = getLinear(p->gamma, p->deg, p->src, p->dst, p->saturate_mask, p->cs, p->linear_type); - p->calWeightsMasks(p->weights_list, p->weights_coeff, saturate_mask); + p->linear = getLinear(p->gamma, p->deg, p->src, p->dst, saturate_mask, (p->cs), p->linear_type); + p->calWeightsMasks(p->weights, p->weights_coeff, saturate_mask); p->src_rgbl = p->linear->linearize(maskCopyTo(p->src, p->mask)); p->dst.colors = maskCopyTo(p->dst.colors, p->mask); p->dst_rgbl = p->dst.to(*(p->cs.l)).colors; diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index fb0d7f24801..14d9a82cc59 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -31,7 +31,7 @@ namespace cv { namespace ccm { -Color::Color():cs(std::shared_ptr ptr(new ColorSpace)) {}; +Color::Color():cs(*new ColorSpace()) {}; Color::Color(Mat colors_, enum COLOR_SPACE cs_) :colors(colors_), cs(*GetCS::get_cs(cs_)) {}; Color::Color(Mat colors_, const ColorSpace& cs_, Mat colored_) : colors(colors_), cs(cs_), colored(colored_) @@ -47,11 +47,11 @@ Color::Color(Mat colors_, const ColorSpace& cs_) : colors(colors_), cs(cs_) {}; // } Color Color::to(const ColorSpace& other, CAM method , bool save) { - if (history.count(other) == 1) + /* if (history.count(other) == 1) { return *history[other]; - } + }*/ if (cs.relate(other)) { return Color(cs.relation(other).run(colors), other); @@ -59,10 +59,10 @@ Color Color::to(const ColorSpace& other, CAM method , bool save) Operations ops; ops.add(cs.to).add(XYZ(cs.io).cam(other.io, method)).add(other.from); std::shared_ptr color(new Color(ops.run(colors), other)); - if (save) - { - history[other] = color; - } + //if (save) + //{ + // history[other] = color; + //} return *color; } Color Color::to( COLOR_SPACE other, CAM method, bool save) diff --git a/modules/mcc/src/color.hpp b/modules/mcc/src/color.hpp index 7e119b70519..26fd047a374 100644 --- a/modules/mcc/src/color.hpp +++ b/modules/mcc/src/color.hpp @@ -53,9 +53,10 @@ class CV_EXPORTS_W Color */ Mat colors; const ColorSpace& cs ; + //ColorSpace& cs; Mat grays; Mat colored; - std::map> history; + //std::map> history; Color(); Color(Mat colors_, enum COLOR_SPACE cs_); Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_); @@ -116,7 +117,6 @@ class CV_EXPORTS_W Color class CV_EXPORTS_W GetColor { public: static Color get_color(CONST_COLOR const_color); - static double create(); static Mat get_ColorChecker(const double *checker,int row); static Mat get_ColorChecker_MASK(const uchar *checker,int row); }; From fd8251d0c7733022bf015630a7a185385c961789 Mon Sep 17 00:00:00 2001 From: shanchenqi Date: Tue, 10 Nov 2020 10:36:34 +0800 Subject: [PATCH 42/71] remove bugs about dst --- modules/mcc/src/ccm.cpp | 21 ++++++++++++--------- modules/mcc/src/color.cpp | 14 +++++++------- modules/mcc/src/color.hpp | 6 ++++-- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 40588886b67..1641ff5fc46 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -35,7 +35,7 @@ namespace ccm class ColorCorrectionModel::Impl{ public: Mat src; - Color dst;//Color::Color(){};ColorSpace(){}; dst + Ptr dst;//Color::Color(){};ColorSpace(){}; dst Mat dist; RGBBase_& cs; Mat mask; @@ -201,7 +201,7 @@ void ColorCorrectionModel::Impl::calWeightsMasks(Mat weights_list, double weight } else if (weights_coeff != 0) { - pow(dst.toLuminant(cs.io), weights_coeff, weights); + pow(dst->toLuminant(cs.io), weights_coeff, weights); } // masks @@ -266,7 +266,7 @@ void ColorCorrectionModel::Impl::initialLeastSquare(bool fit) double ColorCorrectionModel::Impl::calc_loss_(Color color) { - Mat distlist = color.diff(dst, distance); + Mat distlist = color.diff(*dst, distance); Color lab = color.to(Lab_D50_2); Mat dist_; pow(distlist, 2, dist_); @@ -333,13 +333,16 @@ Mat ColorCorrectionModel::Impl::inferImage(Mat& img_, bool islinear) return out_img; } void ColorCorrectionModel::Impl::get_color(CONST_COLOR constcolor){ - dst = GetColor::get_color(constcolor); + dst = &(GetColor::get_color(constcolor)); + //Color dst(GetColor::get_color(constcolor)); + //Color dst_= GetColor::get_color(constcolor); + //dst = dst_; } void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE ref_cs_){ - dst = Color(colors_, *GetCS::get_cs(ref_cs_)); + dst = &Color(colors_, *GetCS::get_cs(ref_cs_)); } void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_){ - dst =Color(colors_, *GetCS::get_cs(cs_),colored_); + dst = &Color(colors_, *GetCS::get_cs(cs_),colored_); } ColorCorrectionModel::ColorCorrectionModel(Mat src_, CONST_COLOR constcolor): p(new Impl){ p->src = src_; @@ -464,11 +467,11 @@ void ColorCorrectionModel::setEpsilon(double epsilon_){ bool ColorCorrectionModel::run(){ Mat saturate_mask = saturate(p->src, p->saturated_threshold[0], p->saturated_threshold[1]); - p->linear = getLinear(p->gamma, p->deg, p->src, p->dst, saturate_mask, (p->cs), p->linear_type); + p->linear = getLinear(p->gamma, p->deg, p->src, *(p->dst), saturate_mask, (p->cs), p->linear_type); p->calWeightsMasks(p->weights, p->weights_coeff, saturate_mask); p->src_rgbl = p->linear->linearize(maskCopyTo(p->src, p->mask)); - p->dst.colors = maskCopyTo(p->dst.colors, p->mask); - p->dst_rgbl = p->dst.to(*(p->cs.l)).colors; + p->dst->colors = maskCopyTo(p->dst->colors, p->mask); + p->dst_rgbl = p->dst->to(*(p->cs.l)).colors; // make no change for CCM_3x3, make change for CCM_4x3. p->src_rgbl = p->prepare(p->src_rgbl); diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index 14d9a82cc59..ee132076db8 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -31,7 +31,7 @@ namespace cv { namespace ccm { -Color::Color():cs(*new ColorSpace()) {}; +Color::Color():colors(Mat()), cs(*new ColorSpace()) {}; Color::Color(Mat colors_, enum COLOR_SPACE cs_) :colors(colors_), cs(*GetCS::get_cs(cs_)) {}; Color::Color(Mat colors_, const ColorSpace& cs_, Mat colored_) : colors(colors_), cs(cs_), colored(colored_) @@ -47,11 +47,11 @@ Color::Color(Mat colors_, const ColorSpace& cs_) : colors(colors_), cs(cs_) {}; // } Color Color::to(const ColorSpace& other, CAM method , bool save) { - /* if (history.count(other) == 1) + if (history.count(other) == 1) { return *history[other]; - }*/ + } if (cs.relate(other)) { return Color(cs.relation(other).run(colors), other); @@ -59,10 +59,10 @@ Color Color::to(const ColorSpace& other, CAM method , bool save) Operations ops; ops.add(cs.to).add(XYZ(cs.io).cam(other.io, method)).add(other.from); std::shared_ptr color(new Color(ops.run(colors), other)); - //if (save) - //{ - // history[other] = color; - //} + if (save) + { + history[other] = color; + } return *color; } Color Color::to( COLOR_SPACE other, CAM method, bool save) diff --git a/modules/mcc/src/color.hpp b/modules/mcc/src/color.hpp index 26fd047a374..3ee237b5d1e 100644 --- a/modules/mcc/src/color.hpp +++ b/modules/mcc/src/color.hpp @@ -56,16 +56,18 @@ class CV_EXPORTS_W Color //ColorSpace& cs; Mat grays; Mat colored; - //std::map> history; + std::map> history; Color(); Color(Mat colors_, enum COLOR_SPACE cs_); Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_); // Color(CONST_COLOR constcolor); Color(Mat colors_, const ColorSpace& cs_, Mat colored_); Color(Mat colors_, const ColorSpace& cs_); - + // Color(const Color& obj) { colors = obj.colors; cs = obj.cs; }; virtual ~Color() {}; + + /** @brief Change to other color space. The conversion process incorporates linear transformations to speed up. @param other type of ColorSpace. From 690332204838195be8b08ff1ff4695fbaf291605 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Tue, 10 Nov 2020 11:46:42 +0800 Subject: [PATCH 43/71] add make passed --- modules/mcc/include/opencv2/mcc/ccm.hpp | 2 +- modules/mcc/src/ccm.cpp | 63 +++++++++++++------------ 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index a9455559a91..3f263aeb304 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -328,7 +328,7 @@ class CV_EXPORTS_W ColorCorrectionModel void setInitialMethod(INITIAL_METHOD_TYPE initial_method_type); void setMaxCount(int max_count_); void setEpsilon(double epsilon_); - bool run(); + void run(); // /** @brief Infer using fitting ccm. // @param img the input image, type of cv::Mat. // @param islinear default false. diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 1641ff5fc46..4278fca41c2 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -107,7 +107,7 @@ namespace ccm @param islinear default false. @return the output array, type of cv::Mat. */ - Mat infer(const Mat& img, bool islinear = false); + // Mat infer(const Mat& img, bool islinear = false); /** @brief Infer image and output as an BGR image with uint8 type. mainly for test or debug. @@ -116,7 +116,7 @@ namespace ccm @param islinear if linearize or not. @return the output array, type of cv::Mat. */ - Mat inferImage(Mat& img_, bool islinear = false); + // Mat inferImage(Mat& img_, bool islinear = false); void get_color(Mat& img_, bool islinear = false); void get_color(CONST_COLOR constcolor); void get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_); @@ -161,8 +161,8 @@ namespace ccm // { // // run(); // } //写成默认参数 -ColorCorrectionModel::Impl::Impl():cs(*GetCS::get_rgb(sRGB)),ccm_type(CCM_3x3), distance(CIE2000),linear_type(GAMMA),gamma(2.2),deg(3),saturated_threshold({ 0, 0.98 }), - weights(Mat()),weights_coeff(0),initial_method_type(LEAST_SQUARE),max_count(5000),epsilon(1.e-4) +ColorCorrectionModel::Impl::Impl():cs(*GetCS::get_rgb(sRGB)),ccm_type(CCM_3x3), distance(CIE2000),linear_type(GAMMA), weights(Mat()),gamma(2.2),deg(3),saturated_threshold({ 0, 0.98 }), + initial_method_type(LEAST_SQUARE),weights_coeff(0),max_count(5000),epsilon(1.e-4) { // run(); } //写成默认参数 @@ -192,16 +192,16 @@ Mat ColorCorrectionModel::Impl::prepare(const Mat& inp) } } -void ColorCorrectionModel::Impl::calWeightsMasks(Mat weights_list, double weights_coeff, Mat saturate_mask) +void ColorCorrectionModel::Impl::calWeightsMasks(Mat weights_list, double weights_coeff_, Mat saturate_mask) { // weights if (!weights_list.empty()) { weights = weights_list; } - else if (weights_coeff != 0) + else if (weights_coeff_ != 0) { - pow(dst->toLuminant(cs.io), weights_coeff, weights); + pow(dst->toLuminant(cs.io), weights_coeff_, weights); } // masks @@ -302,47 +302,50 @@ void ColorCorrectionModel::Impl::fitting(void) std::cout << " loss " << loss << std::endl; } -Mat ColorCorrectionModel::Impl::infer(const Mat& img, bool islinear) +//Mat ColorCorrectionModel::Impl::infer(const Mat& img, bool islinear) +Mat ColorCorrectionModel::infer(const Mat& img, bool islinear) { - if (!ccm.data) + if (!p->ccm.data) { throw "No CCM values!"; } - Mat img_lin = linear->linearize(img); + Mat img_lin = (p->linear)->linearize(img); Mat img_ccm(img_lin.size(), img_lin.type()); - Mat ccm_ = ccm.reshape(0, shape / 3); - img_ccm = multiple(prepare(img_lin), ccm_); + Mat ccm_ = p->ccm.reshape(0, p->shape / 3); + img_ccm = multiple(p->prepare(img_lin), ccm_); if (islinear == true) { return img_ccm; } - return cs.fromL(img_ccm); + return p->cs.fromL(img_ccm); } -Mat ColorCorrectionModel::Impl::inferImage(Mat& img_, bool islinear) -{ - const int inp_size = 255; - const int out_size = 255; - img_ = img_ / inp_size; - Mat out = this->infer(img_, islinear); - Mat out_ = out * out_size; - out_.convertTo(out_, CV_8UC3); - Mat img_out = min(max(out_, 0), out_size); - Mat out_img; - cvtColor(img_out, out_img, COLOR_RGB2BGR); - return out_img; -} +// Mat ColorCorrectionModel::Impl::inferImage(Mat& img_, bool islinear) +// { +// const int inp_size = 255; +// const int out_size = 255; +// img_ = img_ / inp_size; +// Mat out = this->infer(img_, islinear); +// Mat out_ = out * out_size; +// out_.convertTo(out_, CV_8UC3); +// Mat img_out = min(max(out_, 0), out_size); +// Mat out_img; +// cvtColor(img_out, out_img, COLOR_RGB2BGR); +// return out_img; +// } void ColorCorrectionModel::Impl::get_color(CONST_COLOR constcolor){ - dst = &(GetColor::get_color(constcolor)); + //dst = &(GetColor::get_color(constcolor)); + Color dst_ = GetColor::get_color(constcolor); + dst = &dst_; //Color dst(GetColor::get_color(constcolor)); //Color dst_= GetColor::get_color(constcolor); //dst = dst_; } void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE ref_cs_){ - dst = &Color(colors_, *GetCS::get_cs(ref_cs_)); + dst = new Color(colors_, *GetCS::get_cs(ref_cs_)); } void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_){ - dst = &Color(colors_, *GetCS::get_cs(cs_),colored_); + dst = new Color(colors_, *GetCS::get_cs(cs_),colored_); } ColorCorrectionModel::ColorCorrectionModel(Mat src_, CONST_COLOR constcolor): p(new Impl){ p->src = src_; @@ -464,7 +467,7 @@ void ColorCorrectionModel::setMaxCount(int max_count_){ void ColorCorrectionModel::setEpsilon(double epsilon_){ p->epsilon = epsilon_; } -bool ColorCorrectionModel::run(){ +void ColorCorrectionModel::run(){ Mat saturate_mask = saturate(p->src, p->saturated_threshold[0], p->saturated_threshold[1]); p->linear = getLinear(p->gamma, p->deg, p->src, *(p->dst), saturate_mask, (p->cs), p->linear_type); From 85f04d87895bb7b4f067e6db3369245c3888de11 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Tue, 10 Nov 2020 16:05:49 +0800 Subject: [PATCH 44/71] update codes using the structure "impl" --- modules/mcc/include/opencv2/mcc/ccm.hpp | 132 +++--------------- .../mcc/samples/color_correction_model.cpp | 39 ++++-- modules/mcc/src/ccm.cpp | 115 ++------------- modules/mcc/src/color.cpp | 12 +- modules/mcc/src/color.hpp | 5 +- modules/mcc/src/colorspace.cpp | 2 - 6 files changed, 59 insertions(+), 246 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 3f263aeb304..9317ee4976a 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -311,132 +311,32 @@ enum DISTANCE_TYPE class CV_EXPORTS_W ColorCorrectionModel { public: - class Impl; - Ptr p; ColorCorrectionModel(Mat src_, CONST_COLOR constcolor); ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE ref_cs_); ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE cs_, Mat colored_); - void setColorSpace(COLOR_SPACE cs_); - void setCCM(CCM_TYPE ccm_type_); - void setDistance(DISTANCE_TYPE distance_); - void setLinear(LINEAR_TYPE linear_type); - void setLinearGamma(double gamma); - void setLinearDegree(int deg); - void setSaturatedThreshold(double lower, double upper);//std::vector saturated_threshold - void setWeightsList(Mat weights_list); - void setWeightCoeff(double weights_coeff); - void setInitialMethod(INITIAL_METHOD_TYPE initial_method_type); - void setMaxCount(int max_count_); - void setEpsilon(double epsilon_); - void run(); - // /** @brief Infer using fitting ccm. - // @param img the input image, type of cv::Mat. - // @param islinear default false. - // @return the output array, type of cv::Mat. - // */ - Mat infer(const Mat& img, bool islinear = false); - - - - - - // ColorCorrectionModel(Mat src_, CONST_COLOR constcolor, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, - // double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, - // INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); - - // ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE ref_cs_, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, - // double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, - // INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); - - // ColorCorrectionModel(Mat src_, Color dst_, COLOR_SPACE cs_ = sRGB, CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, - // double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, - // INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); - - // ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_ , CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, - // double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, - // INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4); - - - // /** @brief Make no change for CCM_3x3. - // convert cv::Mat A to [A, 1] in CCM_4x3. - // @param inp the input array, type of cv::Mat. - // @return the output array, type of cv::Mat - // */ - // Mat prepare(const Mat& inp); - - // /** @brief Calculate weights and mask. - // @param weights_list the input array, type of cv::Mat. - // @param weights_coeff type of double. - // @param saturate_mask the input array, type of cv::Mat. - // */ - // void calWeightsMasks(Mat weights_list, double weights_coeff, Mat saturate_mask); - - // /** @brief Fitting nonlinear - optimization initial value by white balance. - // see CCM.pdf for details. - // @return the output array, type of Mat - // */ - // void initialWhiteBalance(void); - - // /** @brief Fitting nonlinear-optimization initial value by least square. - // see CCM.pdf for details - // @param fit if fit is True, return optimalization for rgbl distance function. - // */ - // void initialLeastSquare(bool fit = false); - - // double calc_loss_(Color color); - // double calc_loss(const Mat ccm_); - - // /** @brief Fitting ccm if distance function is associated with CIE Lab color space. - // see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp - // Set terminal criteria for solver is possible. - // */ - // void fitting(void); + CV_WRAP class Impl; + CV_WRAP Ptr p; + CV_WRAP void setColorSpace(COLOR_SPACE cs_); + CV_WRAP void setCCM(CCM_TYPE ccm_type_); + CV_WRAP void setDistance(DISTANCE_TYPE distance_); + CV_WRAP void setLinear(LINEAR_TYPE linear_type); + CV_WRAP void setLinearGamma(double gamma); + CV_WRAP void setLinearDegree(int deg); + CV_WRAP void setSaturatedThreshold(double lower, double upper);//std::vector saturated_threshold + CV_WRAP void setWeightsList(Mat weights_list); + CV_WRAP void setWeightCoeff(double weights_coeff); + CV_WRAP void setInitialMethod(INITIAL_METHOD_TYPE initial_method_type); + CV_WRAP void setMaxCount(int max_count_); + CV_WRAP void setEpsilon(double epsilon_); + CV_WRAP void run(); // /** @brief Infer using fitting ccm. // @param img the input image, type of cv::Mat. // @param islinear default false. // @return the output array, type of cv::Mat. // */ - // Mat infer(const Mat& img, bool islinear = false); - - // /** @brief Infer image and output as an BGR image with uint8 type. - // mainly for test or debug. - // input size and output size should be 255. - // @param img_ image to infer, type of cv::Mat. - // @param islinear if linearize or not. - // @return the output array, type of cv::Mat. - // */ - // Mat inferImage(Mat& img_, bool islinear = false); - - // /** @brief Loss function base on cv::MinProblemSolver::Function. - // see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp - // */ - // class LossFunction : public MinProblemSolver::Function - // { - // public: - // ColorCorrectionModel* ccm_loss; - // LossFunction(ColorCorrectionModel* ccm) : ccm_loss(ccm) {}; - - // /** @brief Reset dims to ccm->shape. - // */ - // int getDims() const CV_OVERRIDE - // { - // return ccm_loss->shape; - // } + CV_WRAP Mat infer(const Mat& img, bool islinear = false); - // /** @brief Reset calculation. - // */ - // double calc(const double* x) const CV_OVERRIDE - // { - // Mat ccm_(ccm_loss->shape, 1, CV_64F); - // for (int i = 0; i < ccm_loss->shape; i++) - // { - // ccm_.at(i, 0) = x[i]; - // } - // ccm_ = ccm_.reshape(0, ccm_loss->shape / 3); - // return ccm_loss->calc_loss(ccm_); - // } - // }; }; diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp index c5327279a72..6887f82a337 100644 --- a/modules/mcc/samples/color_correction_model.cpp +++ b/modules/mcc/samples/color_correction_model.cpp @@ -78,26 +78,25 @@ int main(int argc, char *argv[]) //compte color correction matrix //! [get_ccm_Matrix] ColorCorrectionModel model1(src, Vinyl); - //! [get_ccm_Matrix] - - /* brief More models with different parameters, try it & check the document for details. + /* brief More models with different parameters, try it & check the document for details. */ - // ColorCorrectionModel model2(src, Vinyl, AdobeRGB, CCM_4x3, CIE2000, GAMMA, 2.2, 3); - // ColorCorrectionModel model3(src, Vinyl, WideGamutRGB, CCM_4x3, CIE2000, GRAYPOLYFIT, 2.2, 3); - // ColorCorrectionModel model4(src, Vinyl, ProPhotoRGB, CCM_4x3, RGBL, GRAYLOGPOLYFIT, 2.2, 3); - // ColorCorrectionModel model5(src, Vinyl, DCI_P3_RGB, CCM_3x3, RGB, IDENTITY_, 2.2, 3); - // ColorCorrectionModel model6(src, Vinyl, AppleRGB, CCM_3x3, CIE2000, COLORPOLYFIT, 2.2, 2,{ 0, 0.98 },Mat(),2); - // ColorCorrectionModel model7(src, Vinyl, REC_2020_RGB, CCM_3x3, CIE94_GRAPHIC_ARTS, COLORLOGPOLYFIT, 2.2, 3); + // model1.setColorSpace(sRGB); + // model1.setCCM(CCM_4x3); + // model1.setDistance(CIE2000); + // model1.setLinear(GAMMA); + // model1.setLinearGamma(2.2); + // model1.setLinearDegree(3); + // model1.setSaturatedThreshold(0, 0.98); /* If you use a customized ColorChecker, you can use your own reference color values and corresponding color space in a way like: */ //! [reference_color_values] // cv::Mat ref = (Mat_(18, 1) << - // Vec3d(100, 0.00520000001, -0.0104), - // Vec3d(73.0833969, -0.819999993, -2.02099991), - // Vec3d(62.493, 0.425999999, -2.23099995), - // Vec3d(50.4640007, 0.446999997, -2.32399988), - // Vec3d(37.7970009, 0.0359999985, -1.29700005), + // Vec3d(100, 0.0052, -0.0104), + // Vec3d(73.0834, -0.82, -2.021), + // Vec3d(62.493, 0.426, -2.231), + // Vec3d(50.464, 0.447, -2.324), + // Vec3d(37.797, 0.0359999985, -1.29700005), // Vec3d(0, 0, 0), // Vec3d(51.5880013, 73.5179977, 51.5690002), // Vec3d(93.6989975, -15.7340002, 91.9420013), @@ -119,11 +118,20 @@ int main(int argc, char *argv[]) Mat img_; cvtColor(image, img_, COLOR_BGR2RGB); img_.convertTo(img_, CV_64F); - Mat calibratedImage = model1.inferImage(img_); + const int inp_size = 255; + const int out_size = 255; + img_ = img_ / inp_size; + //Mat out = this->infer(img_, islinear); + Mat calibratedImage= model1.infer(img_); + Mat out_ = calibratedImage * out_size; //! [make_color_correction] //! [Save_calibrated_image] // Save the calibrated image to {FILE_NAME}.calibrated.{FILE_EXT} + out_.convertTo(out_, CV_8UC3); + Mat img_out = min(max(out_, 0), out_size); + Mat out_img; + cvtColor(img_out, out_img, COLOR_RGB2BGR); string filename = filepath.substr(filepath.find_last_of('/')+1); size_t dotIndex = filename.find_last_of('.'); string baseName = filename.substr(0, dotIndex); @@ -131,6 +139,7 @@ int main(int argc, char *argv[]) string calibratedFilePath = baseName + ".calibrated." + ext; imwrite(calibratedFilePath, calibratedImage); //! [Save_calibrated_image] + } return 0; diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 4278fca41c2..cba50e550d8 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -35,7 +35,7 @@ namespace ccm class ColorCorrectionModel::Impl{ public: Mat src; - Ptr dst;//Color::Color(){};ColorSpace(){}; dst + std::shared_ptr dst =std::make_shared(); Mat dist; RGBBase_& cs; Mat mask; @@ -49,7 +49,7 @@ namespace ccm int shape; // linear method and distance - std::shared_ptr linear; + std::shared_ptr linear=std::make_shared(); DISTANCE_TYPE distance; LINEAR_TYPE linear_type; @@ -129,9 +129,7 @@ namespace ccm class LossFunction : public MinProblemSolver::Function { public: - //ColorCorrectionModel* ccm_loss; ColorCorrectionModel::Impl * ccm_loss; - // LossFunction(ColorCorrectionModel* ccm) : ccm_loss(ccm) {}; LossFunction(ColorCorrectionModel::Impl* ccm) : ccm_loss(ccm) {}; /** @brief Reset dims to ccm->shape. @@ -155,20 +153,10 @@ namespace ccm } }; }; -// ColorCorrectionModel::Impl::Impl():cs(sRGB),ccm_type(CCM_3x3), distance(), -// linear_type(linear_type),gamma(gamma),deg(deg),saturated_threshold(saturated_threshold),weights_coeff(0),initial_method_type(initial_method_type), -// max_count(max_count_),epsilon(epsilon_) -// { -// // run(); -// } //写成默认参数 + ColorCorrectionModel::Impl::Impl():cs(*GetCS::get_rgb(sRGB)),ccm_type(CCM_3x3), distance(CIE2000),linear_type(GAMMA), weights(Mat()),gamma(2.2),deg(3),saturated_threshold({ 0, 0.98 }), - initial_method_type(LEAST_SQUARE),weights_coeff(0),max_count(5000),epsilon(1.e-4) - { - // run(); - } //写成默认参数 -// Mat src_, Color dst_, RGBBase_& cs_ , CCM_TYPE ccm_type_ = CCM_3x3, DISTANCE_TYPE distance_ = CIE2000, LINEAR_TYPE linear_type = GAMMA, -// double gamma = 2.2, int deg = 3, std::vector saturated_threshold = { 0, 0.98 }, Mat weights_list = Mat(), double weights_coeff = 0, -// INITIAL_METHOD_TYPE initial_method_type = LEAST_SQUARE, int max_count_ = 5000, double epsilon_ = 1.e-4 + initial_method_type(LEAST_SQUARE),weights_coeff(0),max_count(5000),epsilon(1.e-4){} + Mat ColorCorrectionModel::Impl::prepare(const Mat& inp) { switch (ccm_type) @@ -302,7 +290,6 @@ void ColorCorrectionModel::Impl::fitting(void) std::cout << " loss " << loss << std::endl; } -//Mat ColorCorrectionModel::Impl::infer(const Mat& img, bool islinear) Mat ColorCorrectionModel::infer(const Mat& img, bool islinear) { if (!p->ccm.data) @@ -320,36 +307,26 @@ Mat ColorCorrectionModel::infer(const Mat& img, bool islinear) return p->cs.fromL(img_ccm); } -// Mat ColorCorrectionModel::Impl::inferImage(Mat& img_, bool islinear) -// { -// const int inp_size = 255; -// const int out_size = 255; -// img_ = img_ / inp_size; -// Mat out = this->infer(img_, islinear); -// Mat out_ = out * out_size; -// out_.convertTo(out_, CV_8UC3); -// Mat img_out = min(max(out_, 0), out_size); -// Mat out_img; -// cvtColor(img_out, out_img, COLOR_RGB2BGR); -// return out_img; -// } void ColorCorrectionModel::Impl::get_color(CONST_COLOR constcolor){ //dst = &(GetColor::get_color(constcolor)); - Color dst_ = GetColor::get_color(constcolor); - dst = &dst_; + // Color dst_ = GetColor::get_color(constcolor); + dst =(GetColor::get_color(constcolor)); //Color dst(GetColor::get_color(constcolor)); //Color dst_= GetColor::get_color(constcolor); //dst = dst_; } void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE ref_cs_){ - dst = new Color(colors_, *GetCS::get_cs(ref_cs_)); + dst.reset( new Color(colors_, *GetCS::get_cs(ref_cs_))); } void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_){ - dst = new Color(colors_, *GetCS::get_cs(cs_),colored_); + dst.reset( new Color(colors_, *GetCS::get_cs(cs_),colored_)); } ColorCorrectionModel::ColorCorrectionModel(Mat src_, CONST_COLOR constcolor): p(new Impl){ p->src = src_; + std::cout<<"**********2"<get_color(constcolor); + std::cout<<"**********"<get_color(colors_, *GetCS::get_cs(cs_),colored_); p->get_color(colors_, cs_, colored_); } -// ColorCorrectionModel::ColorCorrectionModel(Mat src_, CONST_COLOR constcolor, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, -// double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, -// INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : -// ColorCorrectionModel(src_, GetColor::get_color(constcolor), *GetCS::get_rgb(cs_), ccm_type_, distance_, linear_type, -// gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} -// ColorCorrectionModel::ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE ref_cs_, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, -// double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, -// INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : -// ColorCorrectionModel(src_, Color(colors_, *GetCS::get_cs(ref_cs_)), *GetCS::get_rgb(cs_), ccm_type_, distance_, linear_type, -// gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} - -// ColorCorrectionModel::ColorCorrectionModel(Mat src_, Color dst_, COLOR_SPACE cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, -// double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, -// INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : -// ColorCorrectionModel(src_, dst_, *GetCS::get_rgb(cs_), ccm_type_, distance_, linear_type, -// gamma, deg, saturated_threshold, weights_list, weights_coeff, initial_method_type, max_count_, epsilon_) {} - -// ColorCorrectionModel::ColorCorrectionModel(Mat src_, Color dst_, RGBBase_& cs_, CCM_TYPE ccm_type_, DISTANCE_TYPE distance_, LINEAR_TYPE linear_type, -// double gamma, int deg, std::vector saturated_threshold, Mat weights_list, double weights_coeff, -// INITIAL_METHOD_TYPE initial_method_type, int max_count_, double epsilon_) : -// src(src_), dst(dst_), cs(cs_), ccm_type(ccm_type_), distance(distance_), max_count(max_count_), epsilon(epsilon_) -// { -// Mat saturate_mask = saturate(src, saturated_threshold[0], saturated_threshold[1]); -// this->linear = getLinear(gamma, deg, this->src, this->dst, saturate_mask, this->cs, linear_type); -// calWeightsMasks(weights_list, weights_coeff, saturate_mask); -// src_rgbl = this->linear->linearize(maskCopyTo(this->src, mask)); -// dst.colors = maskCopyTo(dst.colors, mask); -// dst_rgbl = this->dst.to(*(this->cs.l)).colors; - -// // make no change for CCM_3x3, make change for CCM_4x3. -// src_rgbl = prepare(src_rgbl); - -// // distance function may affect the loss function and the fitting function -// switch (this->distance) -// { -// case cv::ccm::RGBL: -// initialLeastSquare(true); -// break; -// default: -// switch (initial_method_type) -// { -// case cv::ccm::WHITE_BALANCE: -// initialWhiteBalance(); -// break; -// case cv::ccm::LEAST_SQUARE: -// initialLeastSquare(); -// break; -// default: -// throw std::invalid_argument{ "Wrong initial_methoddistance_type!" }; -// break; -// } -// break; -// } -// fitting(); -// } - - -//void ColorCorrectionModel::setDst(CONST_COLOR constcolor) { -// p->dst = GetColor::get_color(constcolor); -//} -//void ColorCorrectionModel::setDst(Mat colors_, COLOR_SPACE ref_cs_) { -// p->dst = Color(colors_, *GetCS::get_cs(ref_cs_)); -//} -//void ColorCorrectionModel::setDst(Mat colors_, COLOR_SPACE cs_, Mat colored_) { -// p->dst = Color(colors_, *GetCS::get_cs(cs_), colored_); -//} void ColorCorrectionModel::setColorSpace(COLOR_SPACE cs_){ p->cs = *GetCS::get_rgb(cs_); @@ -468,7 +379,7 @@ void ColorCorrectionModel::setEpsilon(double epsilon_){ p->epsilon = epsilon_; } void ColorCorrectionModel::run(){ - + Mat saturate_mask = saturate(p->src, p->saturated_threshold[0], p->saturated_threshold[1]); p->linear = getLinear(p->gamma, p->deg, p->src, *(p->dst), saturate_mask, (p->cs), p->linear_type); p->calWeightsMasks(p->weights, p->weights_coeff, saturate_mask); diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index ee132076db8..4afb5b3fe13 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -42,9 +42,7 @@ Color::Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_) : colors(colors_), grays = ~colored; } Color::Color(Mat colors_, const ColorSpace& cs_) : colors(colors_), cs(cs_) {}; -// Color::Color(CONST_COLOR constcolor){ -// *this = GetColor::g et_color(constcolor); -// } + Color Color::to(const ColorSpace& other, CAM method , bool save) { if (history.count(other) == 1) @@ -156,7 +154,7 @@ Mat GetColor::get_ColorChecker_MASK(const uchar *checker,int row){ return res; } -Color GetColor::get_color(CONST_COLOR const_color) { +std::shared_ptr GetColor::get_color(CONST_COLOR const_color) { /** @brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls see Miscellaneous.md for details. @@ -364,7 +362,7 @@ const double DigitalSG_LAB_D50_2[140][3] = Mat ColorChecker2005_LAB_D50_2_ = GetColor::get_ColorChecker(*ColorChecker2005_LAB_D50_2,24); Mat ColorChecker2005_COLORED_MASK_ = GetColor::get_ColorChecker_MASK(ColorChecker2005_COLORED_MASK,24); std::shared_ptr Macbeth_D50_2(new Color(ColorChecker2005_LAB_D50_2_, Lab_D50_2, ColorChecker2005_COLORED_MASK_)); - return *Macbeth_D50_2; + return Macbeth_D50_2; break; } @@ -372,13 +370,13 @@ const double DigitalSG_LAB_D50_2[140][3] = Mat Vinyl_LAB_D50_2__=GetColor::get_ColorChecker(*Vinyl_LAB_D50_2,18); Mat Vinyl_COLORED_MASK__= GetColor::get_ColorChecker_MASK(Vinyl_COLORED_MASK,18); std::shared_ptr Vinyl_D50_2(new Color(Vinyl_LAB_D50_2__, Lab_D50_2, Vinyl_COLORED_MASK__)); - return *Vinyl_D50_2; + return Vinyl_D50_2; break; } case cv::ccm::DigitalSG: { Mat DigitalSG_LAB_D50_2__= GetColor::get_ColorChecker(*DigitalSG_LAB_D50_2,140); std::shared_ptr DigitalSG_D50_2(new Color( DigitalSG_LAB_D50_2__, Lab_D50_2)); - return *DigitalSG_D50_2; + return DigitalSG_D50_2; break; } diff --git a/modules/mcc/src/color.hpp b/modules/mcc/src/color.hpp index 3ee237b5d1e..cf01aaba87a 100644 --- a/modules/mcc/src/color.hpp +++ b/modules/mcc/src/color.hpp @@ -53,17 +53,14 @@ class CV_EXPORTS_W Color */ Mat colors; const ColorSpace& cs ; - //ColorSpace& cs; Mat grays; Mat colored; std::map> history; Color(); Color(Mat colors_, enum COLOR_SPACE cs_); Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_); - // Color(CONST_COLOR constcolor); Color(Mat colors_, const ColorSpace& cs_, Mat colored_); Color(Mat colors_, const ColorSpace& cs_); - // Color(const Color& obj) { colors = obj.colors; cs = obj.cs; }; virtual ~Color() {}; @@ -118,7 +115,7 @@ class CV_EXPORTS_W Color class CV_EXPORTS_W GetColor { public: - static Color get_color(CONST_COLOR const_color); + static std::shared_ptr get_color(CONST_COLOR const_color); static Mat get_ColorChecker(const double *checker,int row); static Mat get_ColorChecker_MASK(const uchar *checker,int row); }; diff --git a/modules/mcc/src/colorspace.cpp b/modules/mcc/src/colorspace.cpp index 54fdaf59948..c5afa522883 100644 --- a/modules/mcc/src/colorspace.cpp +++ b/modules/mcc/src/colorspace.cpp @@ -411,7 +411,6 @@ std::shared_ptr Lab::get(IO io) { return lab_cs[io]; } -//static std::map map_cs = {}; std::map > GetCS::map_cs = {}; std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) { @@ -519,7 +518,6 @@ std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) { default: throw "Only RGB color spaces are supported"; } - // return (std::shared_ptr < RGBBase_>)(*map_cs[cs_name]); return (std::dynamic_pointer_cast)(map_cs[cs_name]); } From 190d1554e9526d260552121adf6d98c9ce5f4b00 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Thu, 12 Nov 2020 17:48:53 +0800 Subject: [PATCH 45/71] update documents --- modules/mcc/include/opencv2/mcc/ccm.hpp | 607 +++++++++++------- .../mcc/samples/color_correction_model.cpp | 13 +- modules/mcc/src/ccm.cpp | 13 +- modules/mcc/src/colorspace.cpp | 6 +- modules/mcc/src/distance.hpp | 13 +- modules/mcc/src/io.hpp | 1 + modules/mcc/src/operations.hpp | 11 +- modules/mcc/src/utils.hpp | 4 + .../basic_ccm/color_correction_model.markdown | 94 --- 9 files changed, 404 insertions(+), 358 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 9317ee4976a..33ae9a22d11 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -41,195 +41,36 @@ namespace cv namespace ccm { -/** - src : - detected colors of ColorChecker patches; - NOTICE: the color type is RGB not BGR, and the color values are in [0, 1]; - type: cv::Mat; - constcolor : - the Built-in color card; - Supported list: - Macbeth: Macbeth ColorChecker with 24 squares; - Vinyl: DKK ColorChecker with 12 squares and 6 rectangle; - DigitalSG: DigitalSG ColorChecker with 140 squares; - type: enum CONST_COLOR; - Mat colors_ : - the reference color values - and corresponding color space - NOTICE: the color values are in [0, 1] - type: cv::Mat - ref_cs_ : - the corresponding color space - NOTICE: For the list of color spaces supported, see the notes below; - If the color type is some RGB, the format is RGB not BGR; - type:enum COLOR_SPACE; - cs_ : - the absolute color space that detected colors convert to; - NOTICE: it should be some RGB color space; - For the list of RGB color spaces supported, see the notes below; - type: enum COLOR_SPACE; - dst_ : - the reference colors; - NOTICE: custom color card are supported; - You should generate Color instance using reference color values and corresponding color space - For the list of color spaces supported, see the notes below; - If the color type is some RGB, the format is RGB not BGR, and the color values are in [0, 1]; - - ccm_type : - the shape of color correction matrix(CCM); - Supported list: - "CCM_3x3": 3x3 matrix; - "CCM_4x3": 4x3 matrix; - type: enum CCM_TYPE; - default: CCM_3x3; - distance : - the type of color distance; - Supported list: - "CIE2000"; - "CIE94_GRAPHIC_ARTS"; - "CIE94_TEXTILES"; - "CIE76"; - "CMC_1TO1"; - "CMC_2TO1"; - "RGB" : Euclidean distance of rgb color space; - "RGBL" : Euclidean distance of rgbl color space; - type: enum DISTANCE_TYPE; - default: CIE2000; - linear_type : - the method of linearization; - NOTICE: see Linearization.pdf for details; - Supported list: - "IDENTITY_" : no change is made; - "GAMMA": gamma correction; - Need assign a value to gamma simultaneously; - "COLORPOLYFIT": polynomial fitting channels respectively; - Need assign a value to deg simultaneously; - "GRAYPOLYFIT": grayscale polynomial fitting; - Need assign a value to deg and dst_whites simultaneously; - "COLORLOGPOLYFIT": logarithmic polynomial fitting channels respectively; - Need assign a value to deg simultaneously; - "GRAYLOGPOLYFIT": grayscale Logarithmic polynomial fitting; - Need assign a value to deg and dst_whites simultaneously; - type: enum LINEAR_TYPE; - default: IDENTITY_; - gamma : - the gamma value of gamma correction; - NOTICE: only valid when linear is set to "gamma"; - type: double; - default: 2.2; - deg : - the degree of linearization polynomial; - NOTICE: only valid when linear is set to "COLORPOLYFIT", "GRAYPOLYFIT", - "COLORLOGPOLYFIT" and "GRAYLOGPOLYFIT"; - type: int; - default: 3; - saturated_threshold : - the threshold to determine saturation; - NOTICE: it is a tuple of [low, up]; - The colors in the closed interval [low, up] are reserved to participate - in the calculation of the loss function and initialization parameters. - type: std::vector; - default: { 0, 0.98 }; - --------------------------------------------------- - There are some ways to set weights: - 1. set weights_list only; - 2. set weights_coeff only; - see CCM.pdf for details; - weights_list : - the list of weight of each color; - type: cv::Mat; - default: empty array; - weights_coeff : - the exponent number of L* component of the reference color in CIE Lab color space; - type: double; - default: 0; - --------------------------------------------------- - initial_method_type : - the method of calculating CCM initial value; - see CCM.pdf for details; - Supported list: - 'LEAST_SQUARE': least-squre method; - 'WHITE_BALANCE': white balance method; - type: enum INITIAL_METHOD_TYPE; - max_count, epsilon : - used in MinProblemSolver-DownhillSolver; - Terminal criteria to the algorithm; - type: int, double; - default: 5000, 1e-4; - --------------------------------------------------- - Supported Color Space: - Supported list of RGB color spaces: - sRGB; - AdobeRGB; - WideGamutRGB; - ProPhotoRGB; - DCI_P3_RGB; - AppleRGB; - REC_709_RGB; - REC_2020_RGB; - Supported list of linear RGB color spaces: - sRGBL; - AdobeRGBL; - WideGamutRGBL; - ProPhotoRGBL; - DCI_P3_RGBL; - AppleRGBL; - REC_709_RGBL; - REC_2020_RGBL; - Supported list of non-RGB color spaces: - Lab_D50_2; - Lab_D65_2; - XYZ_D50_2; - XYZ_D65_2; - XYZ_D65_10; - XYZ_D50_10; - XYZ_A_2; - XYZ_A_10; - XYZ_D55_2; - XYZ_D55_10; - XYZ_D75_2; - XYZ_D75_10; - XYZ_E_2; - XYZ_E_10; - Lab_D65_10; - Lab_D50_10; - Lab_A_2; - Lab_A_10; - Lab_D55_2; - Lab_D55_10; - Lab_D75_2; - Lab_D75_10; - Lab_E_2; - Lab_E_10; - --------------------------------------------------- - Abbr. - src, s: source; - dst, d: destination; - io: illuminant & observer; - sio, dio: source of io; destination of io; - rgbl: linear RGB - cs: color space; - cc: Colorchecker; - M, m: matrix - ccm: color correction matrix; - cam: chromatic adaption matrix; -*/ - /** @brief Enum of the possible types of ccm. */ enum CCM_TYPE { - CCM_3x3, - CCM_4x3 + CCM_3x3, ///0\\ +C_{sl}=0, \qquad C_s=0 +\f] + +Because \f$exp(ln(0))\to\infin\f$, the channel whose component is 0 is directly mapped to 0 in the formula above. + +For fitting channels respectively, we have: +\f[ +r=polyfit(ln(R_s),ln(R_{dl}))\\ +g=polyfit(ln(G_s),ln(G_{dl}))\\ +b=polyfit(ln(B_s),ln(B_{dl}))\\ +\f] +Note that the parameter of $ln$ cannot be 0. Therefore, we need to delete the channels whose values are 0 from $R_s$ and $R_{dl}$, $G_s$ and $G_{dl}$, $B_s$ and $B_{dl}$. + +Therefore: + +\f[ +ln(R_{sl})=r(ln(R_s)), \qquad R_s>0\\ +R_{sl}=0, \qquad R_s=0\\ +ln(G_{sl})=g(ln(G_s)),\qquad G_s>0\\ +G_{sl}=0, \qquad G_s=0\\ +ln(B_{sl})=b(ln(B_s)),\qquad B_s>0\\ +B_{sl}=0, \qquad B_s=0\\ +\f] + +For grayscale polynomials, there are also: +\f[ +f=polyfit(ln(G_{sl}),ln(G_{dl})) +\f] +and: +\f[ +ln(C_{sl})=f(ln(C_s)), \qquad C_s>0\\ +C_sl=0, \qquad C_s=0 +\f] +*/ enum LINEAR_TYPE { IDENTITY_, @@ -294,11 +309,11 @@ enum LINEAR_TYPE colors.see https://en.wikipedia.org/wiki/Color_difference for details;*/ enum DISTANCE_TYPE { - CIE76, - CIE94_GRAPHIC_ARTS, - CIE94_TEXTILES, + CIE76, ///The 1976 formula is the first formula that related a measured color difference to a known set of CIELAB coordinates. + CIE94_GRAPHIC_ARTS, ///The 1976 definition was extended to address perceptual non-uniformities. + CIE94_TEXTILES, CIE2000, - CMC_1TO1, + CMC_1TO1, //In 1984, the Colour Measurement Committee of the Society of Dyers and Colourists defined a difference measure, also based on the L*C*h color model. CMC_2TO1, RGB, RGBL @@ -311,23 +326,153 @@ enum DISTANCE_TYPE class CV_EXPORTS_W ColorCorrectionModel { public: - ColorCorrectionModel(Mat src_, CONST_COLOR constcolor); - ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE ref_cs_); - ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE cs_, Mat colored_); + /** @brief Color Correction Model + @param src detected colors of ColorChecker patches;\n + the color type is RGB not BGR, and the color values are in [0, 1]; + type is cv::Mat; + @param constcolor the Built-in color card;\n + Supported list: + Macbeth(Macbeth ColorChecker) ; + Vinyl(DKK ColorChecker) ; + DigitalSG(DigitalSG ColorChecker with 140 squares);\n + type: enum CONST_COLOR;\n + */ + ColorCorrectionModel(Mat src, CONST_COLOR constcolor); + /** @brief Color Correction Model + @param src detected colors of ColorChecker patches;\n + the color type is RGB not BGR, and the color values are in [0, 1]; + type is cv::Mat; + @param colors the reference color values,the color values are in [0, 1].\n + type: cv::Mat + @param ref_cs the corresponding color space + NOTICE: For the list of color spaces supported, see the notes above;\n + If the color type is some RGB, the format is RGB not BGR;\n + type:enum COLOR_SPACE; + */ + ColorCorrectionModel(Mat src, Mat colors, COLOR_SPACE ref_cs); + /** @brief Color Correction Model + @param src detected colors of ColorChecker patches;\n + the color type is RGB not BGR, and the color values are in [0, 1]; + type is cv::Mat; + @param colors the reference color values,the color values are in [0, 1].\n + type: cv::Mat + @param ref_cs the corresponding color space + NOTICE: For the list of color spaces supported, see the notes above;\n + If the color type is some RGB, the format is RGB not BGR;\n + type:enum COLOR_SPACE; + @param colored mask of colored color + */ + ColorCorrectionModel(Mat src, Mat colors, COLOR_SPACE ref_cs, Mat colored); CV_WRAP class Impl; CV_WRAP Ptr p; + /** @brief set ColorSpace + @param cs_ the absolute color space that detected colors convert to;\n + NOTICE: it should be some RGB color space;\n + For the list of RGB color spaces supported, see the notes above; + type: enum COLOR_SPACE;\n + default: sRGB; + */ CV_WRAP void setColorSpace(COLOR_SPACE cs_); - CV_WRAP void setCCM(CCM_TYPE ccm_type_); - CV_WRAP void setDistance(DISTANCE_TYPE distance_); + /** @brief set ccm_type + @param ccm_type :the shape of color correction matrix(CCM);\n + Supported list: "CCM_3x3"(3x3 matrix);"CCM_4x3"( 4x3 matrix);\n + type: enum CCM_TYPE;\n + default: CCM_3x3;\n + */ + CV_WRAP void setCCM(CCM_TYPE ccm_type); + /** @brief set Distance + @param distance the type of color distance;\n + Supported list:"CIE2000"; "CIE94_GRAPHIC_ARTS";"CIE94_TEXTILES"; + "CIE76"; + "CMC_1TO1"; + "CMC_2TO1"; + "RGB" (Euclidean distance of rgb color space); + "RGBL" () Euclidean distance of rgbl color space);\n + type: enum DISTANCE_TYPE;\n + default: CIE2000;\n + */ + CV_WRAP void setDistance(DISTANCE_TYPE distance); + /** @brief set Linear + @param linear_type the method of linearization; + NOTICE: see Linearization.pdf for details;\n + Supported list: + "IDENTITY_" (no change is made); + "GAMMA"( gamma correction; + Need assign a value to gamma simultaneously); + "COLORPOLYFIT" (polynomial fitting channels respectively; + Need assign a value to deg simultaneously); + "GRAYPOLYFIT"( grayscale polynomial fitting; + Need assign a value to deg and dst_whites simultaneously); + "COLORLOGPOLYFIT"(logarithmic polynomial fitting channels respectively; + Need assign a value to deg simultaneously); + "GRAYLOGPOLYFIT" (grayscale Logarithmic polynomial fitting; + Need assign a value to deg and dst_whites simultaneously);\n + type: enum LINEAR_TYPE;\n + default: GAMMA;\n + */ CV_WRAP void setLinear(LINEAR_TYPE linear_type); + + /** @brief set Gamma + @param gamma the gamma value of gamma correction; + NOTICE: only valid when linear is set to "gamma";\n + type: double;\n + default: 2.2;\n + */ CV_WRAP void setLinearGamma(double gamma); + + /** @brief set degree + @param deg the degree of linearization polynomial;\n + NOTICE: only valid when linear is set to "COLORPOLYFIT", "GRAYPOLYFIT", + "COLORLOGPOLYFIT" and "GRAYLOGPOLYFIT";\n + type: int;\n + default: 3;\n + */ CV_WRAP void setLinearDegree(int deg); - CV_WRAP void setSaturatedThreshold(double lower, double upper);//std::vector saturated_threshold + /** @brief set SaturatedThreshold + @param lower the lower threshold to determine saturation;\n + default: 0; + @param upper the upper threshold to determine saturation; + NOTICE: it is a tuple of [lower, upper]; + The colors in the closed interval [lower, upper] are reserved to participate + in the calculation of the loss function and initialization parameters\n + default: 0; + */ + CV_WRAP void setSaturatedThreshold(double lower, double upper); + /** @brief set WeightsList + @param weights_list the list of weight of each color;\n + type: cv::Mat;\n + default: empty array; + */ CV_WRAP void setWeightsList(Mat weights_list); + /** @brief set WeightCoeff + @param weights_coeff the exponent number of L* component of the reference color in CIE Lab color space;\n + type: double;\n + default: 0;\n + */ CV_WRAP void setWeightCoeff(double weights_coeff); + /** @brief set InitialMethod + @param initial_method_type the method of calculating CCM initial value;\n + Supported list: + 'LEAST_SQUARE' (least-squre method); + 'WHITE_BALANCE' (white balance method);\n + type: enum INITIAL_METHOD_TYPE; + */ CV_WRAP void setInitialMethod(INITIAL_METHOD_TYPE initial_method_type); - CV_WRAP void setMaxCount(int max_count_); - CV_WRAP void setEpsilon(double epsilon_); + /** @brief set MaxCount + @param max_count used in MinProblemSolver-DownhillSolver;\n + Terminal criteria to the algorithm;\n + type: int; + default: 5000; + */ + CV_WRAP void setMaxCount(int max_count); + /** @brief set Epsilon + @param epsilon used in MinProblemSolver-DownhillSolver;\n + Terminal criteria to the algorithm;\n + type: double; + default: 1e-4; + */ + CV_WRAP void setEpsilon(double epsilon); + /** @brief make color correction*/ CV_WRAP void run(); // /** @brief Infer using fitting ccm. diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp index 6887f82a337..5f70b2da3ce 100644 --- a/modules/mcc/samples/color_correction_model.cpp +++ b/modules/mcc/samples/color_correction_model.cpp @@ -78,10 +78,11 @@ int main(int argc, char *argv[]) //compte color correction matrix //! [get_ccm_Matrix] ColorCorrectionModel model1(src, Vinyl); + //! [get_ccm_Matrix] /* brief More models with different parameters, try it & check the document for details. */ // model1.setColorSpace(sRGB); - // model1.setCCM(CCM_4x3); + // model1.setCCM(CCM_3x3); // model1.setDistance(CIE2000); // model1.setLinear(GAMMA); // model1.setLinearGamma(2.2); @@ -92,11 +93,11 @@ int main(int argc, char *argv[]) */ //! [reference_color_values] // cv::Mat ref = (Mat_(18, 1) << - // Vec3d(100, 0.0052, -0.0104), - // Vec3d(73.0834, -0.82, -2.021), - // Vec3d(62.493, 0.426, -2.231), - // Vec3d(50.464, 0.447, -2.324), - // Vec3d(37.797, 0.0359999985, -1.29700005), + // Vec3d(100, 0.00520000001, -0.0104), + // Vec3d(73.0833969, -0.819999993, -2.02099991), + // Vec3d(62.493, 0.425999999, -2.23099995), + // Vec3d(50.4640007, 0.446999997, -2.32399988), + // Vec3d(37.7970009, 0.0359999985, -1.29700005), // Vec3d(0, 0, 0), // Vec3d(51.5880013, 73.5179977, 51.5690002), // Vec3d(93.6989975, -15.7340002, 91.9420013), diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index cba50e550d8..45c07175d64 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -279,6 +279,7 @@ void ColorCorrectionModel::Impl::fitting(void) cv::Ptr ptr_F(new LossFunction(this)); solver->setFunction(ptr_F); Mat reshapeccm = ccm0.clone().reshape(0, 1); + std::cout << " ccm0 " << ccm0 << std::endl; Mat step = Mat::ones(reshapeccm.size(), CV_64F); solver->setInitStep(step); TermCriteria termcrit = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, max_count, epsilon); @@ -308,12 +309,7 @@ Mat ColorCorrectionModel::infer(const Mat& img, bool islinear) } void ColorCorrectionModel::Impl::get_color(CONST_COLOR constcolor){ - //dst = &(GetColor::get_color(constcolor)); - // Color dst_ = GetColor::get_color(constcolor); dst =(GetColor::get_color(constcolor)); - //Color dst(GetColor::get_color(constcolor)); - //Color dst_= GetColor::get_color(constcolor); - //dst = dst_; } void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE ref_cs_){ dst.reset( new Color(colors_, *GetCS::get_cs(ref_cs_))); @@ -323,21 +319,14 @@ void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE cs_, Mat col } ColorCorrectionModel::ColorCorrectionModel(Mat src_, CONST_COLOR constcolor): p(new Impl){ p->src = src_; - std::cout<<"**********2"<get_color(constcolor); - std::cout<<"**********"<src = src_; p->get_color(colors_, ref_cs_); - //dst= Color(colors_, *GetCS::get_cs(ref_cs_)) } ColorCorrectionModel::ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE cs_, Mat colored_): p(new Impl){ p->src = src_; - // p->cs = *GetCS::get_rgb(cs_); - // p->get_color(colors_, *GetCS::get_cs(cs_),colored_); p->get_color(colors_, cs_, colored_); } diff --git a/modules/mcc/src/colorspace.cpp b/modules/mcc/src/colorspace.cpp index c5afa522883..abb12445b0d 100644 --- a/modules/mcc/src/colorspace.cpp +++ b/modules/mcc/src/colorspace.cpp @@ -57,7 +57,8 @@ bool ColorSpace::relate(const ColorSpace& other) const { }; Operations ColorSpace::relation(const ColorSpace& /*other*/) const { - return IDENTITY_OPS; + return Operations::get_IDENTITY_OPS(); + //return IDENTITY_OPS; }; bool ColorSpace::operator<(const ColorSpace& other) const { @@ -71,7 +72,8 @@ bool ColorSpace::operator<(const ColorSpace& other) const { */ Operations RGBBase_::relation(const ColorSpace& other) const { if (linear == other.linear) { - return IDENTITY_OPS; + //return IDENTITY_OPS; + return Operations::get_IDENTITY_OPS(); } if (linear) { return Operations({Operation(fromL)}); diff --git a/modules/mcc/src/distance.hpp b/modules/mcc/src/distance.hpp index bdb997646af..27243929833 100644 --- a/modules/mcc/src/distance.hpp +++ b/modules/mcc/src/distance.hpp @@ -35,17 +35,8 @@ namespace cv { namespace ccm { -// enum DISTANCE_TYPE -// { -// CIE76, -// CIE94_GRAPHIC_ARTS, -// CIE94_TEXTILES, -// CIE2000, -// CMC_1TO1, -// CMC_2TO1, -// RGB, -// RGBL -// }; +/** possibale functions to calculate the distance between + colors.see https://en.wikipedia.org/wiki/Color_difference for details;*/ /** @brief distance between two points in formula CIE76 diff --git a/modules/mcc/src/io.hpp b/modules/mcc/src/io.hpp index 0b44a8561a2..09bd4afcc0e 100644 --- a/modules/mcc/src/io.hpp +++ b/modules/mcc/src/io.hpp @@ -61,6 +61,7 @@ const IO A_2("A", "2"), A_10("A", "10"), D75_2("D75", "2"), D75_10("D75", "10"), E_2("E", "2"), E_10("E", "10"); + // data from https://en.wikipedia.org/wiki/Standard_illuminant. const static std::map> illuminants_xy = { diff --git a/modules/mcc/src/operations.hpp b/modules/mcc/src/operations.hpp index 5e2eb96cce4..98527707fa5 100644 --- a/modules/mcc/src/operations.hpp +++ b/modules/mcc/src/operations.hpp @@ -47,6 +47,7 @@ typedef std::function MatFunc; class CV_EXPORTS_W Operation { public: + typedef std::function MatFunc; bool linear; Mat M; MatFunc f; @@ -68,9 +69,12 @@ class CV_EXPORTS_W Operation void add(const Operation& other); void clear(); + static Operation get_IDENTITY_OP(){ + return Operation([](Mat x) {return x; }); + } }; -const Operation IDENTITY_OP([](Mat x) {return x; }); +//const Operation IDENTITY_OP([](Mat x) {return x; }); class CV_EXPORTS_W Operations { @@ -90,9 +94,12 @@ class CV_EXPORTS_W Operations /** @brief run operations to make color conversion */ Mat run(Mat abc); + static Operations get_IDENTITY_OPS(){ + return Operations{Operation::get_IDENTITY_OP()}; + } }; -const Operations IDENTITY_OPS{ IDENTITY_OP }; +//const Operations IDENTITY_OPS{ IDENTITY_OP }; } // namespace ccm } // namespace cv diff --git a/modules/mcc/src/utils.hpp b/modules/mcc/src/utils.hpp index 989971cb0fb..9aa5e090e6a 100644 --- a/modules/mcc/src/utils.hpp +++ b/modules/mcc/src/utils.hpp @@ -36,6 +36,10 @@ namespace ccm { CV_EXPORTS_W double gammaCorrection_(const double& element, const double& gamma); /** @brief gamma correction ,see ColorSpace.pdf for details. + \f[ + C_l=C_n^{\gamma},\qquad C_n\ge0\\ + C_l=-(-C_n)^{\gamma},\qquad C_n<0\\\\ + \f] @param src the input array,type of Mat. @param gamma a constant for gamma correction. */ diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index b8096f81acc..8b78025450a 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -53,100 +53,6 @@ Here are the parameters for ColorCorrectionModel NOTICE: For the list of color spaces supported, see the notes below; If the color type is some RGB, the format is RGB not BGR; type:enum COLOR_SPACE; - cs_ : - the absolute color space that detected colors convert to; - NOTICE: it should be some RGB color space; - For the list of RGB color spaces supported, see the notes below; - type: enum COLOR_SPACE; - dst_ : - the reference colors; - NOTICE: custom color card are supported; - You should use Color - For the list of color spaces supported, see the notes below; - If the color type is some RGB, the format is RGB not BGR, and the color values are in [0, 1]; - - ccm_type : - the shape of color correction matrix(CCM); - Supported list: - "CCM_3x3": 3x3 matrix; - "CCM_4x3": 4x3 matrix; - type: enum CCM_TYPE; - default: CCM_3x3; - distance : - the type of color distance; - Supported list: - "CIE2000"; - "CIE94_GRAPHIC_ARTS"; - "CIE94_TEXTILES"; - "CIE76"; - "CMC_1TO1"; - "CMC_2TO1"; - "RGB" : Euclidean distance of rgb color space; - "RGBL" : Euclidean distance of rgbl color space; - type: enum DISTANCE_TYPE; - default: CIE2000; - linear_type : - the method of linearization; - NOTICE: see Linearization.pdf for details; - Supported list: - "IDENTITY_" : no change is made; - "GAMMA": gamma correction; - Need assign a value to gamma simultaneously; - "COLORPOLYFIT": polynomial fitting channels respectively; - Need assign a value to deg simultaneously; - "GRAYPOLYFIT": grayscale polynomial fitting; - Need assign a value to deg and dst_whites simultaneously; - "COLORLOGPOLYFIT": logarithmic polynomial fitting channels respectively; - Need assign a value to deg simultaneously; - "GRAYLOGPOLYFIT": grayscale Logarithmic polynomial fitting; - Need assign a value to deg and dst_whites simultaneously; - type: enum LINEAR_TYPE; - default: IDENTITY_; - gamma : - the gamma value of gamma correction; - NOTICE: only valid when linear is set to "gamma"; - type: double; - default: 2.2; - deg : - the degree of linearization polynomial; - NOTICE: only valid when linear is set to "COLORPOLYFIT", "GRAYPOLYFIT", - "COLORLOGPOLYFIT" and "GRAYLOGPOLYFIT"; - type: int; - default: 3; - saturated_threshold : - the threshold to determine saturation; - NOTICE: it is a tuple of [low, up]; - The colors in the closed interval [low, up] are reserved to participate - in the calculation of the loss function and initialization parameters. - type: std::vector; - default: { 0, 0.98 }; - --------------------------------------------------- - There are some ways to set weights: - 1. set weights_list only; - 2. set weights_coeff only; - see CCM.pdf for details; - weights_list : - the list of weight of each color; - type: cv::Mat; - default: empty array; - weights_coeff : - the exponent number of L* component of the reference color in CIE Lab color space; - type: double; - default: 0; - --------------------------------------------------- - initial_method_type : - the method of calculating CCM initial value; - see CCM.pdf for details; - Supported list: - 'LEAST_SQUARE': least-squre method; - 'WHITE_BALANCE': white balance method; - type: enum INITIAL_METHOD_TYPE; - max_count, epsilon : - used in MinProblemSolver-DownhillSolver; - Terminal criteria to the algorithm; - type: int, double; - default: 5000, 1e-4; - --------------------------------------------------- Supported Color Space: Supported list of RGB color spaces: sRGB; From f1e1eb6fbed1884dc3c0130c8976d169452f9531 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Fri, 13 Nov 2020 09:47:53 +0800 Subject: [PATCH 46/71] update ccm member for class ColorCorrectionModel --- modules/mcc/include/opencv2/mcc/ccm.hpp | 1 + modules/mcc/src/ccm.cpp | 2 +- modules/mcc/src/color.hpp | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 33ae9a22d11..cb8e8b7fd4f 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -326,6 +326,7 @@ enum DISTANCE_TYPE class CV_EXPORTS_W ColorCorrectionModel { public: + Mat CV_WRAP ccm; /** @brief Color Correction Model @param src detected colors of ColorChecker patches;\n the color type is RGB not BGR, and the color values are in [0, 1]; diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 45c07175d64..cd595e666e6 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -279,7 +279,6 @@ void ColorCorrectionModel::Impl::fitting(void) cv::Ptr ptr_F(new LossFunction(this)); solver->setFunction(ptr_F); Mat reshapeccm = ccm0.clone().reshape(0, 1); - std::cout << " ccm0 " << ccm0 << std::endl; Mat step = Mat::ones(reshapeccm.size(), CV_64F); solver->setInitStep(step); TermCriteria termcrit = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, max_count, epsilon); @@ -401,6 +400,7 @@ void ColorCorrectionModel::run(){ break; } p->fitting(); + ccm=p->ccm; } diff --git a/modules/mcc/src/color.hpp b/modules/mcc/src/color.hpp index cf01aaba87a..d96458dc08b 100644 --- a/modules/mcc/src/color.hpp +++ b/modules/mcc/src/color.hpp @@ -43,7 +43,7 @@ namespace ccm /** @brief Color defined by color_values and color space */ -class CV_EXPORTS_W Color +class Color { public: @@ -113,7 +113,7 @@ class CV_EXPORTS_W Color }; -class CV_EXPORTS_W GetColor { +class GetColor { public: static std::shared_ptr get_color(CONST_COLOR const_color); static Mat get_ColorChecker(const double *checker,int row); From 89d8514af7f66162afbfd25a95ed1aeb23549718 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Fri, 13 Nov 2020 09:54:28 +0800 Subject: [PATCH 47/71] remove macro CV_EXPORTS_W for codes in src/*.hpp --- modules/mcc/src/colorspace.hpp | 30 +++++++++++++++--------------- modules/mcc/src/io.hpp | 2 +- modules/mcc/src/linearize.hpp | 10 +++++----- modules/mcc/src/operations.hpp | 4 ++-- modules/mcc/src/utils.hpp | 14 +++++++------- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/modules/mcc/src/colorspace.hpp b/modules/mcc/src/colorspace.hpp index f89d124aabe..b124f860955 100644 --- a/modules/mcc/src/colorspace.hpp +++ b/modules/mcc/src/colorspace.hpp @@ -88,7 +88,7 @@ namespace ccm /** @brief Basic class for ColorSpace. */ -class CV_EXPORTS_W ColorSpace +class ColorSpace { public: IO io; @@ -121,7 +121,7 @@ class CV_EXPORTS_W ColorSpace Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space */ -class CV_EXPORTS_W RGBBase_ : public ColorSpace +class RGBBase_ : public ColorSpace { public: // primaries @@ -179,7 +179,7 @@ class CV_EXPORTS_W RGBBase_ : public ColorSpace /** @brief Base of Adobe RGB color space; */ -class CV_EXPORTS_W AdobeRGBBase_ : public RGBBase_ +class AdobeRGBBase_ : public RGBBase_ { public: @@ -193,7 +193,7 @@ class CV_EXPORTS_W AdobeRGBBase_ : public RGBBase_ /** @brief Base of sRGB color space; */ -class CV_EXPORTS_W sRGBBase_ : public RGBBase_ +class sRGBBase_ : public RGBBase_ { public: @@ -237,7 +237,7 @@ class CV_EXPORTS_W sRGBBase_ : public RGBBase_ /** @brief sRGB color space. data from https://en.wikipedia.org/wiki/SRGB. */ -class CV_EXPORTS_W sRGB_ :public sRGBBase_ +class sRGB_ :public sRGBBase_ { public: @@ -249,7 +249,7 @@ class CV_EXPORTS_W sRGB_ :public sRGBBase_ /** @brief Adobe RGB color space. */ -class CV_EXPORTS_W AdobeRGB_ : public AdobeRGBBase_ +class AdobeRGB_ : public AdobeRGBBase_ { public: AdobeRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AdobeRGB", linear_) {}; @@ -262,7 +262,7 @@ class CV_EXPORTS_W AdobeRGB_ : public AdobeRGBBase_ /** @brief Wide-gamut RGB color space. data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. */ -class CV_EXPORTS_W WideGamutRGB_ : public AdobeRGBBase_ +class WideGamutRGB_ : public AdobeRGBBase_ { public: WideGamutRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "WideGamutRGB", linear_) {}; @@ -275,7 +275,7 @@ class CV_EXPORTS_W WideGamutRGB_ : public AdobeRGBBase_ data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. */ -class CV_EXPORTS_W ProPhotoRGB_ : public AdobeRGBBase_ +class ProPhotoRGB_ : public AdobeRGBBase_ { public: ProPhotoRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "ProPhotoRGB", linear_) {}; @@ -287,7 +287,7 @@ class CV_EXPORTS_W ProPhotoRGB_ : public AdobeRGBBase_ /** @brief DCI-P3 RGB color space. data from https://en.wikipedia.org/wiki/DCI-P3. */ -class CV_EXPORTS_W DCI_P3_RGB_ : public AdobeRGBBase_ +class DCI_P3_RGB_ : public AdobeRGBBase_ { public: DCI_P3_RGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "DCI_P3_RGB", linear_) {}; @@ -299,7 +299,7 @@ class CV_EXPORTS_W DCI_P3_RGB_ : public AdobeRGBBase_ /** @brief Apple RGB color space. data from http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. */ -class CV_EXPORTS_W AppleRGB_ : public AdobeRGBBase_ +class AppleRGB_ : public AdobeRGBBase_ { public: AppleRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AppleRGB", linear_) {}; @@ -311,7 +311,7 @@ class CV_EXPORTS_W AppleRGB_ : public AdobeRGBBase_ /** @brief REC_709 RGB color space. data from https://en.wikipedia.org/wiki/Rec._709. */ -class CV_EXPORTS_W REC_709_RGB_ : public sRGBBase_ +class REC_709_RGB_ : public sRGBBase_ { public: REC_709_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_709_RGB", linear_) {}; @@ -323,7 +323,7 @@ class CV_EXPORTS_W REC_709_RGB_ : public sRGBBase_ /** @brief REC_2020 RGB color space. data from https://en.wikipedia.org/wiki/Rec._2020. */ -class CV_EXPORTS_W REC_2020_RGB_ : public sRGBBase_ +class REC_2020_RGB_ : public sRGBBase_ { public: REC_2020_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_2020_RGB", linear_) {}; @@ -354,7 +354,7 @@ const static std::map > MAs = { /** @brief XYZ color space. Chromatic adaption matrices. */ -class CV_EXPORTS_W XYZ :public ColorSpace +class XYZ :public ColorSpace { public: XYZ(IO io_) : ColorSpace(io_, "XYZ", true) {}; @@ -379,7 +379,7 @@ const XYZ XYZ_D50_2_CS(D50_2); /** @brief Lab color space. */ -class CV_EXPORTS_W Lab :public ColorSpace +class Lab :public ColorSpace { public: static std::map > lab_cs; @@ -417,7 +417,7 @@ const Lab Lab_D50_2_CS(D50_2); //static std::map map_cs ; -class CV_EXPORTS_W GetCS { +class GetCS { public: static std::map > map_cs; static std::shared_ptr get_rgb(enum COLOR_SPACE cs_name); diff --git a/modules/mcc/src/io.hpp b/modules/mcc/src/io.hpp index 09bd4afcc0e..46516ff959b 100644 --- a/modules/mcc/src/io.hpp +++ b/modules/mcc/src/io.hpp @@ -41,7 +41,7 @@ namespace ccm /** @brief Io is the meaning of illuminant and observer. See notes of ccm.hpp for supported list for illuminant and observer*/ -class CV_EXPORTS_W IO +class IO { public: std::string illuminant; diff --git a/modules/mcc/src/linearize.hpp b/modules/mcc/src/linearize.hpp index 46e51cae001..e0bc05bfc55 100644 --- a/modules/mcc/src/linearize.hpp +++ b/modules/mcc/src/linearize.hpp @@ -51,7 +51,7 @@ namespace ccm /** @brief Polyfit model. */ -class CV_EXPORTS_W Polyfit +class Polyfit { public: int deg; @@ -75,7 +75,7 @@ class CV_EXPORTS_W Polyfit /** @brief Logpolyfit model. */ -class CV_EXPORTS_W LogPolyfit +class LogPolyfit { public: @@ -95,7 +95,7 @@ class CV_EXPORTS_W LogPolyfit /** @brief Linearization base. */ -class CV_EXPORTS_W Linear +class Linear { public: Linear() {}; @@ -114,11 +114,11 @@ class CV_EXPORTS_W Linear /** @brief Linearization identity. make no change. */ -class CV_EXPORTS_W LinearIdentity : public Linear {}; +class LinearIdentity : public Linear {}; /** @brief Linearization gamma correction. */ -class CV_EXPORTS_W LinearGamma : public Linear +class LinearGamma : public Linear { public: double gamma; diff --git a/modules/mcc/src/operations.hpp b/modules/mcc/src/operations.hpp index 98527707fa5..58e91e0e6f1 100644 --- a/modules/mcc/src/operations.hpp +++ b/modules/mcc/src/operations.hpp @@ -44,7 +44,7 @@ typedef std::function MatFunc; /** @brief Operation class contains some operarions used for color space conversion containing linear transformation and non-linear transformation */ -class CV_EXPORTS_W Operation +class Operation { public: typedef std::function MatFunc; @@ -76,7 +76,7 @@ class CV_EXPORTS_W Operation //const Operation IDENTITY_OP([](Mat x) {return x; }); -class CV_EXPORTS_W Operations +class Operations { public: std::vector ops; diff --git a/modules/mcc/src/utils.hpp b/modules/mcc/src/utils.hpp index 9aa5e090e6a..659e82e736b 100644 --- a/modules/mcc/src/utils.hpp +++ b/modules/mcc/src/utils.hpp @@ -33,7 +33,7 @@ namespace cv { namespace ccm { -CV_EXPORTS_W double gammaCorrection_(const double& element, const double& gamma); +double gammaCorrection_(const double& element, const double& gamma); /** @brief gamma correction ,see ColorSpace.pdf for details. \f[ @@ -43,20 +43,20 @@ CV_EXPORTS_W double gammaCorrection_(const double& element, const double& gamma) @param src the input array,type of Mat. @param gamma a constant for gamma correction. */ -CV_EXPORTS_W Mat gammaCorrection(const Mat& src, const double& gamma); +Mat gammaCorrection(const Mat& src, const double& gamma); /** @brief maskCopyTo a function to delete unsatisfied elementwise. @param src the input array, type of Mat. @param mask operation mask that used to choose satisfided elementwise. */ -CV_EXPORTS_W Mat maskCopyTo(const Mat& src, const Mat& mask); +Mat maskCopyTo(const Mat& src, const Mat& mask); /** @brief multiple the function used to compute an array with n channels mulipied by ccm. @param xyz the input array, type of Mat. @param ccm the ccm matrix to make color correction. */ -CV_EXPORTS_W Mat multiple(const Mat& xyz, const Mat& ccm); +Mat multiple(const Mat& xyz, const Mat& ccm); /** @brief multiple the function used to get the mask of saturated colors, colors between low and up will be choosed. @@ -64,13 +64,13 @@ CV_EXPORTS_W Mat multiple(const Mat& xyz, const Mat& ccm); @param low the threshold to choose saturated colors @param up the threshold to choose saturated colors */ -CV_EXPORTS_W Mat saturate(Mat& src, const double& low, const double& up); +Mat saturate(Mat& src, const double& low, const double& up); /** @brief rgb2gray it is an approximation grayscale function for relative RGB color space, see Miscellaneous.pdf for details; @param rgb the input array,type of Mat. */ -CV_EXPORTS_W Mat rgb2gray(Mat rgb); +Mat rgb2gray(Mat rgb); /** @brief function for elementWise operation @param src the input array, type of Mat @@ -147,7 +147,7 @@ Mat distanceWise(Mat& src, Mat& ref, F&& lambda) return dst; } -CV_EXPORTS_W Mat multiple(const Mat& xyz, const Mat& ccm); +Mat multiple(const Mat& xyz, const Mat& ccm); const static Mat m_gray = (Mat_(3, 1) << 0.2126, 0.7152, 0.0722); From a15630042481e478827cb43e2ff0e219efa4b0b3 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Fri, 13 Nov 2020 10:01:11 +0800 Subject: [PATCH 48/71] move class Impl private --- modules/mcc/include/opencv2/mcc/ccm.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index cb8e8b7fd4f..cc25a8ec607 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -364,8 +364,7 @@ class CV_EXPORTS_W ColorCorrectionModel @param colored mask of colored color */ ColorCorrectionModel(Mat src, Mat colors, COLOR_SPACE ref_cs, Mat colored); - CV_WRAP class Impl; - CV_WRAP Ptr p; + /** @brief set ColorSpace @param cs_ the absolute color space that detected colors convert to;\n NOTICE: it should be some RGB color space;\n @@ -482,7 +481,9 @@ class CV_EXPORTS_W ColorCorrectionModel // @return the output array, type of cv::Mat. // */ CV_WRAP Mat infer(const Mat& img, bool islinear = false); - +private: + CV_WRAP class Impl; + CV_WRAP Ptr p; }; From 9d0f417d50196f4c89476911b27bf6f8f14f4ac3 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Fri, 13 Nov 2020 10:41:01 +0800 Subject: [PATCH 49/71] remove unnesasary notice --- modules/mcc/include/opencv2/mcc/ccm.hpp | 116 ++++++++++++------------ modules/mcc/src/ccm.cpp | 18 +--- modules/mcc/src/color.hpp | 1 - modules/mcc/src/colorspace.hpp | 45 --------- modules/mcc/src/linearize.hpp | 13 --- modules/mcc/src/operations.hpp | 1 - 6 files changed, 60 insertions(+), 134 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index cc25a8ec607..03a0e81ab60 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -55,12 +55,12 @@ enum CCM_TYPE */ enum INITIAL_METHOD_TYPE { - WHITE_BALANCE, ///< The white balance method. The initial value is: + WHITE_BALANCE, ///< The white balance method. The initial value is: /// \f$ /// M_{CCM}= /// \begin{bmatrix} - /// k_R & 0 & 0\\ - /// 0 & k_G & 0\\ + /// k_R & 0 & 0\\ + /// 0 & k_G & 0\\ /// 0 & 0 & k_B\\ /// \end{bmatrix} /// \f$ @@ -97,41 +97,41 @@ enum COLOR_SPACE { REC_2020_RGB, ///0\\ @@ -285,11 +285,11 @@ ln(B_{sl})=b(ln(B_s)),\qquad B_s>0\\ B_{sl}=0, \qquad B_s=0\\ \f] -For grayscale polynomials, there are also: +For grayscale polynomials, there are also: \f[ f=polyfit(ln(G_{sl}),ln(G_{dl})) \f] -and: +and: \f[ ln(C_{sl})=f(ln(C_s)), \qquad C_s>0\\ C_sl=0, \qquad C_s=0 @@ -309,11 +309,11 @@ enum LINEAR_TYPE colors.see https://en.wikipedia.org/wiki/Color_difference for details;*/ enum DISTANCE_TYPE { - CIE76, ///The 1976 formula is the first formula that related a measured color difference to a known set of CIELAB coordinates. + CIE76, ///The 1976 formula is the first formula that related a measured color difference to a known set of CIELAB coordinates. CIE94_GRAPHIC_ARTS, ///The 1976 definition was extended to address perceptual non-uniformities. - CIE94_TEXTILES, + CIE94_TEXTILES, CIE2000, - CMC_1TO1, //In 1984, the Colour Measurement Committee of the Society of Dyers and Colourists defined a difference measure, also based on the L*C*h color model. + CMC_1TO1, //In 1984, the Colour Measurement Committee of the Society of Dyers and Colourists defined a difference measure, also based on the L*C*h color model. CMC_2TO1, RGB, RGBL @@ -364,7 +364,7 @@ class CV_EXPORTS_W ColorCorrectionModel @param colored mask of colored color */ ColorCorrectionModel(Mat src, Mat colors, COLOR_SPACE ref_cs, Mat colored); - + /** @brief set ColorSpace @param cs_ the absolute color space that detected colors convert to;\n NOTICE: it should be some RGB color space;\n @@ -380,7 +380,7 @@ class CV_EXPORTS_W ColorCorrectionModel default: CCM_3x3;\n */ CV_WRAP void setCCM(CCM_TYPE ccm_type); - /** @brief set Distance + /** @brief set Distance @param distance the type of color distance;\n Supported list:"CIE2000"; "CIE94_GRAPHIC_ARTS";"CIE94_TEXTILES"; "CIE76"; diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index cd595e666e6..ce4c9d7d29b 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -25,7 +25,7 @@ // Jinheng Zhang // Chenqi Shan -//#include "precomp.hpp" + #include "opencv2/mcc/ccm.hpp" #include "linearize.hpp" namespace cv @@ -102,21 +102,7 @@ namespace ccm */ void fitting(void); - /** @brief Infer using fitting ccm. - @param img the input image, type of cv::Mat. - @param islinear default false. - @return the output array, type of cv::Mat. - */ - // Mat infer(const Mat& img, bool islinear = false); - - /** @brief Infer image and output as an BGR image with uint8 type. - mainly for test or debug. - input size and output size should be 255. - @param img_ image to infer, type of cv::Mat. - @param islinear if linearize or not. - @return the output array, type of cv::Mat. - */ - // Mat inferImage(Mat& img_, bool islinear = false); + void get_color(Mat& img_, bool islinear = false); void get_color(CONST_COLOR constcolor); void get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_); diff --git a/modules/mcc/src/color.hpp b/modules/mcc/src/color.hpp index d96458dc08b..66cef2a5678 100644 --- a/modules/mcc/src/color.hpp +++ b/modules/mcc/src/color.hpp @@ -29,7 +29,6 @@ #define __OPENCV_MCC_COLOR_HPP__ #include -//#include "opencv2/mcc/colorspace.hpp" #include "distance.hpp" #include "colorspace.hpp" #include "opencv2/mcc/ccm.hpp" diff --git a/modules/mcc/src/colorspace.hpp b/modules/mcc/src/colorspace.hpp index b124f860955..dea69657746 100644 --- a/modules/mcc/src/colorspace.hpp +++ b/modules/mcc/src/colorspace.hpp @@ -41,51 +41,6 @@ namespace cv namespace ccm { -/** Supported Color Space. -*/ -// enum COLOR_SPACE { -// sRGB, -// sRGBL, -// AdobeRGB, -// AdobeRGBL, -// WideGamutRGB, -// WideGamutRGBL, -// ProPhotoRGB, -// ProPhotoRGBL, -// DCI_P3_RGB, -// DCI_P3_RGBL, -// AppleRGB, -// AppleRGBL, -// REC_709_RGB, -// REC_709_RGBL, -// REC_2020_RGB, -// REC_2020_RGBL, -// XYZ_D65_2, -// XYZ_D65_10, -// XYZ_D50_2, -// XYZ_D50_10, -// XYZ_A_2, -// XYZ_A_10, -// XYZ_D55_2, -// XYZ_D55_10, -// XYZ_D75_2, -// XYZ_D75_10, -// XYZ_E_2, -// XYZ_E_10, -// Lab_D65_2, -// Lab_D65_10, -// Lab_D50_2, -// Lab_D50_10, -// Lab_A_2, -// Lab_A_10, -// Lab_D55_2, -// Lab_D55_10, -// Lab_D75_2, -// Lab_D75_10, -// Lab_E_2, -// Lab_E_10 -// }; - /** @brief Basic class for ColorSpace. */ class ColorSpace diff --git a/modules/mcc/src/linearize.hpp b/modules/mcc/src/linearize.hpp index e0bc05bfc55..82e82c2ce36 100644 --- a/modules/mcc/src/linearize.hpp +++ b/modules/mcc/src/linearize.hpp @@ -29,7 +29,6 @@ #ifndef __OPENCV_MCC_LINEARIZE_HPP__ #define __OPENCV_MCC_LINEARIZE_HPP__ -//#include "opencv2/mcc/color.hpp" #include "color.hpp" #include "opencv2/mcc/ccm.hpp" namespace cv @@ -37,18 +36,6 @@ namespace cv namespace ccm { -// /** @brief Enum of the possible types of linearization. -// */ -// enum LINEAR_TYPE -// { -// IDENTITY_, -// GAMMA, -// COLORPOLYFIT, -// COLORLOGPOLYFIT, -// GRAYPOLYFIT, -// GRAYLOGPOLYFIT -// }; - /** @brief Polyfit model. */ class Polyfit diff --git a/modules/mcc/src/operations.hpp b/modules/mcc/src/operations.hpp index 58e91e0e6f1..90fbb18f27a 100644 --- a/modules/mcc/src/operations.hpp +++ b/modules/mcc/src/operations.hpp @@ -31,7 +31,6 @@ #include #include -//#include "opencv2/mcc/utils.hpp" #include "utils.hpp" namespace cv From 0ea01e62c257e36886dbf3616cea6c0df1490fb6 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Fri, 13 Nov 2020 20:15:52 +0800 Subject: [PATCH 50/71] remove trailing whitespace --- modules/mcc/src/ccm.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index ce4c9d7d29b..ee917c72cb8 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -66,7 +66,7 @@ namespace ccm int max_count; double epsilon; Impl(); - + /** @brief Make no change for CCM_3x3. convert cv::Mat A to [A, 1] in CCM_4x3. @param inp the input array, type of cv::Mat. @@ -139,7 +139,7 @@ namespace ccm } }; }; - + ColorCorrectionModel::Impl::Impl():cs(*GetCS::get_rgb(sRGB)),ccm_type(CCM_3x3), distance(CIE2000),linear_type(GAMMA), weights(Mat()),gamma(2.2),deg(3),saturated_threshold({ 0, 0.98 }), initial_method_type(LEAST_SQUARE),weights_coeff(0),max_count(5000),epsilon(1.e-4){} @@ -353,7 +353,7 @@ void ColorCorrectionModel::setEpsilon(double epsilon_){ p->epsilon = epsilon_; } void ColorCorrectionModel::run(){ - + Mat saturate_mask = saturate(p->src, p->saturated_threshold[0], p->saturated_threshold[1]); p->linear = getLinear(p->gamma, p->deg, p->src, *(p->dst), saturate_mask, (p->cs), p->linear_type); p->calWeightsMasks(p->weights, p->weights_coeff, saturate_mask); From 18e544b92dce3f987a2a05d558cd448665e71a6f Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Mon, 16 Nov 2020 16:03:35 +0800 Subject: [PATCH 51/71] update documents&samples --- modules/mcc/include/opencv2/mcc/ccm.hpp | 80 +++++++++---------- .../mcc/samples/color_correction_model.cpp | 3 +- modules/mcc/src/color.hpp | 3 +- modules/mcc/src/colorspace.cpp | 5 +- 4 files changed, 44 insertions(+), 47 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 03a0e81ab60..d3a13950687 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -80,46 +80,46 @@ enum CONST_COLOR { DigitalSG }; enum COLOR_SPACE { - sRGB, ///second); Mat XYZWd = Mat(illuminants.find(sio)->second); Mat MA = MAs.at(method)[0]; From efe5ae7d3fb0ec4a880e400cfa7f45534c8db49d Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Mon, 16 Nov 2020 19:14:21 +0800 Subject: [PATCH 52/71] move typedef MatFunc into class and move dead codes --- modules/mcc/src/color.cpp | 10 +++++----- modules/mcc/src/colorspace.hpp | 8 ++++---- modules/mcc/src/distance.cpp | 2 +- modules/mcc/src/io.hpp | 11 ----------- modules/mcc/src/operations.hpp | 12 ++---------- modules/mcc/src/utils.hpp | 2 +- 6 files changed, 13 insertions(+), 32 deletions(-) diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index 4afb5b3fe13..a83591fa0a1 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -159,7 +159,7 @@ std::shared_ptr GetColor::get_color(CONST_COLOR const_color) { /** @brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls see Miscellaneous.md for details. */ -const double ColorChecker2005_LAB_D50_2 [24][3] = +static const double ColorChecker2005_LAB_D50_2 [24][3] = { {37.986, 13.555, 14.059}, {65.711, 18.13, 17.81}, {49.927, -4.88, -21.925}, @@ -185,12 +185,12 @@ const double ColorChecker2005_LAB_D50_2 [24][3] = {35.656, -0.421, -1.231}, {20.461, -0.079, -0.973}}; -const uchar ColorChecker2005_COLORED_MASK[24] = +static const uchar ColorChecker2005_COLORED_MASK[24] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}; -const double Vinyl_LAB_D50_2[18][3] = +static const double Vinyl_LAB_D50_2[18][3] = { {100, 0.00520000001, -0.0104}, {73.0833969, -0.819999993, -2.02099991}, {62.493, 0.425999999, -2.23099995}, @@ -209,11 +209,11 @@ const double Vinyl_LAB_D50_2[18][3] = {51.2859993, 48.4700012, -15.0579996}, {68.70700069999999, 12.2959995, 16.2129993}, {63.6839981, 10.2930002, 16.7639999}}; -const uchar Vinyl_COLORED_MASK[18]= +static const uchar Vinyl_COLORED_MASK[18]= { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; -const double DigitalSG_LAB_D50_2[140][3] = +static const double DigitalSG_LAB_D50_2[140][3] = { {96.55,-0.91,0.57}, {6.43,-0.06,-0.41}, {49.7,-0.18,0.03}, diff --git a/modules/mcc/src/colorspace.hpp b/modules/mcc/src/colorspace.hpp index dea69657746..8f1739a5423 100644 --- a/modules/mcc/src/colorspace.hpp +++ b/modules/mcc/src/colorspace.hpp @@ -46,6 +46,7 @@ namespace ccm class ColorSpace { public: + typedef std::function MatFunc; IO io; std::string type; bool linear; @@ -298,9 +299,9 @@ enum CAM }; static std::map , Mat > cams; -const static Mat Von_Kries = (Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); -const static Mat Bradford = (Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); -const static std::map > MAs = { +static const Mat Von_Kries = (Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); +static const Mat Bradford = (Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); +static const std::map > MAs = { {IDENTITY , { Mat::eye(Size(3,3),CV_64FC1) , Mat::eye(Size(3,3),CV_64FC1)} }, {VON_KRIES, { Von_Kries ,Von_Kries.inv() }}, {BRADFORD, { Bradford ,Bradford.inv() }} @@ -370,7 +371,6 @@ class Lab :public ColorSpace const Lab Lab_D65_2_CS(D65_2); const Lab Lab_D50_2_CS(D50_2); -//static std::map map_cs ; class GetCS { public: diff --git a/modules/mcc/src/distance.cpp b/modules/mcc/src/distance.cpp index e1ec1c824a7..cebd00210b3 100644 --- a/modules/mcc/src/distance.cpp +++ b/modules/mcc/src/distance.cpp @@ -25,7 +25,7 @@ // Jinheng Zhang // Chenqi Shan -//#include "precomp.hpp" + #include "distance.hpp" namespace cv diff --git a/modules/mcc/src/io.hpp b/modules/mcc/src/io.hpp index 46516ff959b..2b4ce1601fa 100644 --- a/modules/mcc/src/io.hpp +++ b/modules/mcc/src/io.hpp @@ -62,17 +62,6 @@ const IO A_2("A", "2"), A_10("A", "10"), E_2("E", "2"), E_10("E", "10"); -// data from https://en.wikipedia.org/wiki/Standard_illuminant. -const static std::map> illuminants_xy = -{ - {A_2, { 0.44757, 0.40745 }}, {A_10, { 0.45117, 0.40594 }}, - {D50_2, { 0.34567, 0.35850 }}, {D50_10, { 0.34773, 0.35952 }}, - {D55_2, { 0.33242, 0.34743 }}, {D55_10, { 0.33411, 0.34877 }}, - {D65_2, { 0.31271, 0.32902 }}, {D65_10, { 0.31382, 0.33100 }}, - {D75_2, { 0.29902, 0.31485 }}, {D75_10, { 0.45117, 0.40594 }}, - {E_2, { 1 / 3, 1 / 3 }}, {E_10, { 1 / 3, 1 / 3 }}, -}; - std::vector xyY2XYZ(const std::vector& xyY); diff --git a/modules/mcc/src/operations.hpp b/modules/mcc/src/operations.hpp index 90fbb18f27a..d005b71e377 100644 --- a/modules/mcc/src/operations.hpp +++ b/modules/mcc/src/operations.hpp @@ -38,8 +38,6 @@ namespace cv namespace ccm { -typedef std::function MatFunc; - /** @brief Operation class contains some operarions used for color space conversion containing linear transformation and non-linear transformation */ @@ -52,9 +50,7 @@ class Operation MatFunc f; Operation() : linear(true), M(Mat()) {}; - Operation(Mat M_) :linear(true), M(M_) {}; - Operation(MatFunc f_) : linear(false), f(f_) {}; virtual ~Operation() {}; @@ -69,11 +65,11 @@ class Operation void clear(); static Operation get_IDENTITY_OP(){ - return Operation([](Mat x) {return x; }); + static Operation identity_op([](Mat x) {return x; }); + return identity_op; } }; -//const Operation IDENTITY_OP([](Mat x) {return x; }); class Operations { @@ -81,9 +77,7 @@ class Operations std::vector ops; Operations() :ops{ } {}; - Operations(std::initializer_list op) :ops{ op } {}; - virtual ~Operations() {}; /** @brief add function will conbine this operation with other transformation operations @@ -98,8 +92,6 @@ class Operations } }; -//const Operations IDENTITY_OPS{ IDENTITY_OP }; - } // namespace ccm } // namespace cv diff --git a/modules/mcc/src/utils.hpp b/modules/mcc/src/utils.hpp index 659e82e736b..86f7cd62dc9 100644 --- a/modules/mcc/src/utils.hpp +++ b/modules/mcc/src/utils.hpp @@ -149,7 +149,7 @@ Mat distanceWise(Mat& src, Mat& ref, F&& lambda) Mat multiple(const Mat& xyz, const Mat& ccm); -const static Mat m_gray = (Mat_(3, 1) << 0.2126, 0.7152, 0.0722); +static const Mat m_gray = (Mat_(3, 1) << 0.2126, 0.7152, 0.0722); } // namespace ccm } // namespace cv From a51499f652b1aa8b23a0f17b4b2b225286db9104 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Tue, 17 Nov 2020 10:53:53 +0800 Subject: [PATCH 53/71] minimize list of required headers, add getCCM() method --- modules/mcc/include/opencv2/mcc/ccm.hpp | 42 +++++++++---------- .../mcc/samples/color_correction_model.cpp | 2 +- modules/mcc/src/ccm.cpp | 13 +++--- modules/mcc/src/ccmimpl.cpp | 0 4 files changed, 27 insertions(+), 30 deletions(-) delete mode 100644 modules/mcc/src/ccmimpl.cpp diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index d3a13950687..24b608e4370 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -28,20 +28,14 @@ #ifndef __OPENCV_MCC_CCM_HPP__ #define __OPENCV_MCC_CCM_HPP__ -#include -#include -#include -#include #include #include -// #include "opencv2/mcc/linearize.hpp" namespace cv { namespace ccm { - /** @brief Enum of the possible types of ccm. */ enum CCM_TYPE @@ -306,7 +300,8 @@ enum LINEAR_TYPE }; /** @brief Enum of possibale functions to calculate the distance between - colors.see https://en.wikipedia.org/wiki/Color_difference for details;*/ + colors.see https://en.wikipedia.org/wiki/Color_difference for details; +*/ enum DISTANCE_TYPE { CIE76, ///The 1976 formula is the first formula that related a measured color difference to a known set of CIELAB coordinates. @@ -326,19 +321,18 @@ enum DISTANCE_TYPE class CV_EXPORTS_W ColorCorrectionModel { public: - Mat CV_WRAP ccm; - /** @brief Color Correction Model - @param src detected colors of ColorChecker patches;\n - the color type is RGB not BGR, and the color values are in [0, 1]; - type is cv::Mat; - @param constcolor the Built-in color card;\n - Supported list: - Macbeth(Macbeth ColorChecker) ; - Vinyl(DKK ColorChecker) ; - DigitalSG(DigitalSG ColorChecker with 140 squares);\n - type: enum CONST_COLOR;\n - */ - ColorCorrectionModel(Mat src, CONST_COLOR constcolor); + /** @brief Color Correction Model + @param src detected colors of ColorChecker patches;\n + the color type is RGB not BGR, and the color values are in [0, 1]; + type is cv::Mat; + @param constcolor the Built-in color card;\n + Supported list: + Macbeth(Macbeth ColorChecker) ; + Vinyl(DKK ColorChecker) ; + DigitalSG(DigitalSG ColorChecker with 140 squares);\n + type: enum CONST_COLOR;\n + */ + ColorCorrectionModel(const Mat& src, CONST_COLOR constcolor); /** @brief Color Correction Model @param src detected colors of ColorChecker patches;\n the color type is RGB not BGR, and the color values are in [0, 1]; @@ -350,7 +344,7 @@ class CV_EXPORTS_W ColorCorrectionModel If the color type is some RGB, the format is RGB not BGR;\n type:enum COLOR_SPACE; */ - ColorCorrectionModel(Mat src, Mat colors, COLOR_SPACE ref_cs); + ColorCorrectionModel(const Mat& src, Mat colors, COLOR_SPACE ref_cs); /** @brief Color Correction Model @param src detected colors of ColorChecker patches;\n the color type is RGB not BGR, and the color values are in [0, 1]; @@ -363,7 +357,7 @@ class CV_EXPORTS_W ColorCorrectionModel type:enum COLOR_SPACE; @param colored mask of colored color */ - ColorCorrectionModel(Mat src, Mat colors, COLOR_SPACE ref_cs, Mat colored); + ColorCorrectionModel(const Mat& src, Mat colors, COLOR_SPACE ref_cs, Mat colored); /** @brief set ColorSpace @param cs_ the absolute color space that detected colors convert to;\n @@ -379,7 +373,7 @@ class CV_EXPORTS_W ColorCorrectionModel type: enum CCM_TYPE;\n default: CCM_3x3;\n */ - CV_WRAP void setCCM(CCM_TYPE ccm_type); + CV_WRAP void setCCM_TYPE(CCM_TYPE ccm_type); /** @brief set Distance @param distance the type of color distance;\n Supported list:"CIE2000"; "CIE94_GRAPHIC_ARTS";"CIE94_TEXTILES"; @@ -475,6 +469,8 @@ class CV_EXPORTS_W ColorCorrectionModel /** @brief make color correction*/ CV_WRAP void run(); + CV_WRAP Mat getCCM() const; + // /** @brief Infer using fitting ccm. // @param img the input image, type of cv::Mat. // @param islinear default false. diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp index c758e623855..50062809abc 100644 --- a/modules/mcc/samples/color_correction_model.cpp +++ b/modules/mcc/samples/color_correction_model.cpp @@ -82,7 +82,7 @@ int main(int argc, char *argv[]) /* brief More models with different parameters, try it & check the document for details. */ // model1.setColorSpace(sRGB); - // model1.setCCM(CCM_3x3); + // model1.setCCM_TYPE(CCM_3x3); // model1.setDistance(CIE2000); // model1.setLinear(GAMMA); // model1.setLinearGamma(2.2); diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index ee917c72cb8..36e970b0134 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -302,15 +302,15 @@ void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE ref_cs_){ void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_){ dst.reset( new Color(colors_, *GetCS::get_cs(cs_),colored_)); } -ColorCorrectionModel::ColorCorrectionModel(Mat src_, CONST_COLOR constcolor): p(new Impl){ +ColorCorrectionModel::ColorCorrectionModel(const Mat& src_, CONST_COLOR constcolor): p(new Impl){ p->src = src_; p->get_color(constcolor); } -ColorCorrectionModel:: ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE ref_cs_): p(new Impl){ +ColorCorrectionModel:: ColorCorrectionModel(const Mat& src_, Mat colors_, COLOR_SPACE ref_cs_): p(new Impl){ p->src = src_; p->get_color(colors_, ref_cs_); } -ColorCorrectionModel::ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE cs_, Mat colored_): p(new Impl){ +ColorCorrectionModel::ColorCorrectionModel(const Mat& src_, Mat colors_, COLOR_SPACE cs_, Mat colored_): p(new Impl){ p->src = src_; p->get_color(colors_, cs_, colored_); } @@ -318,7 +318,7 @@ ColorCorrectionModel::ColorCorrectionModel(Mat src_, Mat colors_, COLOR_SPACE cs void ColorCorrectionModel::setColorSpace(COLOR_SPACE cs_){ p->cs = *GetCS::get_rgb(cs_); } -void ColorCorrectionModel::setCCM(CCM_TYPE ccm_type_){ +void ColorCorrectionModel::setCCM_TYPE(CCM_TYPE ccm_type_){ p->ccm_type = ccm_type_; } void ColorCorrectionModel::setDistance(DISTANCE_TYPE distance_){ @@ -386,8 +386,9 @@ void ColorCorrectionModel::run(){ break; } p->fitting(); - ccm=p->ccm; - +} +Mat ColorCorrectionModel::getCCM() const{ + return p->ccm; } } // namespace ccm diff --git a/modules/mcc/src/ccmimpl.cpp b/modules/mcc/src/ccmimpl.cpp deleted file mode 100644 index e69de29bb2d..00000000000 From 9b1fa9bdf79ba47deacdd3ce3122d519a0ad88f8 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Tue, 17 Nov 2020 11:06:21 +0800 Subject: [PATCH 54/71] move type: information for parameters --- modules/mcc/include/opencv2/mcc/ccm.hpp | 37 +++++-------------- .../basic_ccm/color_correction_model.markdown | 4 -- 2 files changed, 9 insertions(+), 32 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 24b608e4370..451d4b6b83a 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -324,37 +324,29 @@ class CV_EXPORTS_W ColorCorrectionModel /** @brief Color Correction Model @param src detected colors of ColorChecker patches;\n the color type is RGB not BGR, and the color values are in [0, 1]; - type is cv::Mat; @param constcolor the Built-in color card;\n Supported list: Macbeth(Macbeth ColorChecker) ; Vinyl(DKK ColorChecker) ; DigitalSG(DigitalSG ColorChecker with 140 squares);\n - type: enum CONST_COLOR;\n */ ColorCorrectionModel(const Mat& src, CONST_COLOR constcolor); /** @brief Color Correction Model @param src detected colors of ColorChecker patches;\n the color type is RGB not BGR, and the color values are in [0, 1]; - type is cv::Mat; @param colors the reference color values,the color values are in [0, 1].\n - type: cv::Mat @param ref_cs the corresponding color space NOTICE: For the list of color spaces supported, see the notes above;\n If the color type is some RGB, the format is RGB not BGR;\n - type:enum COLOR_SPACE; */ ColorCorrectionModel(const Mat& src, Mat colors, COLOR_SPACE ref_cs); /** @brief Color Correction Model @param src detected colors of ColorChecker patches;\n the color type is RGB not BGR, and the color values are in [0, 1]; - type is cv::Mat; - @param colors the reference color values,the color values are in [0, 1].\n - type: cv::Mat + @param colors the reference color values,the color values are in [0, 1]. @param ref_cs the corresponding color space NOTICE: For the list of color spaces supported, see the notes above;\n - If the color type is some RGB, the format is RGB not BGR;\n - type:enum COLOR_SPACE; + If the color type is some RGB, the format is RGB not BGR; @param colored mask of colored color */ ColorCorrectionModel(const Mat& src, Mat colors, COLOR_SPACE ref_cs, Mat colored); @@ -362,15 +354,13 @@ class CV_EXPORTS_W ColorCorrectionModel /** @brief set ColorSpace @param cs_ the absolute color space that detected colors convert to;\n NOTICE: it should be some RGB color space;\n - For the list of RGB color spaces supported, see the notes above; - type: enum COLOR_SPACE;\n + For the list of RGB color spaces supported, see the notes above;\n default: sRGB; */ CV_WRAP void setColorSpace(COLOR_SPACE cs_); /** @brief set ccm_type @param ccm_type :the shape of color correction matrix(CCM);\n Supported list: "CCM_3x3"(3x3 matrix);"CCM_4x3"( 4x3 matrix);\n - type: enum CCM_TYPE;\n default: CCM_3x3;\n */ CV_WRAP void setCCM_TYPE(CCM_TYPE ccm_type); @@ -382,7 +372,6 @@ class CV_EXPORTS_W ColorCorrectionModel "CMC_2TO1"; "RGB" (Euclidean distance of rgb color space); "RGBL" () Euclidean distance of rgbl color space);\n - type: enum DISTANCE_TYPE;\n default: CIE2000;\n */ CV_WRAP void setDistance(DISTANCE_TYPE distance); @@ -401,7 +390,6 @@ class CV_EXPORTS_W ColorCorrectionModel Need assign a value to deg simultaneously); "GRAYLOGPOLYFIT" (grayscale Logarithmic polynomial fitting; Need assign a value to deg and dst_whites simultaneously);\n - type: enum LINEAR_TYPE;\n default: GAMMA;\n */ CV_WRAP void setLinear(LINEAR_TYPE linear_type); @@ -409,7 +397,6 @@ class CV_EXPORTS_W ColorCorrectionModel /** @brief set Gamma @param gamma the gamma value of gamma correction; NOTICE: only valid when linear is set to "gamma";\n - type: double;\n default: 2.2;\n */ CV_WRAP void setLinearGamma(double gamma); @@ -418,7 +405,6 @@ class CV_EXPORTS_W ColorCorrectionModel @param deg the degree of linearization polynomial;\n NOTICE: only valid when linear is set to "COLORPOLYFIT", "GRAYPOLYFIT", "COLORLOGPOLYFIT" and "GRAYLOGPOLYFIT";\n - type: int;\n default: 3;\n */ CV_WRAP void setLinearDegree(int deg); @@ -434,14 +420,12 @@ class CV_EXPORTS_W ColorCorrectionModel CV_WRAP void setSaturatedThreshold(double lower, double upper); /** @brief set WeightsList @param weights_list the list of weight of each color;\n - type: cv::Mat;\n default: empty array; */ CV_WRAP void setWeightsList(Mat weights_list); /** @brief set WeightCoeff @param weights_coeff the exponent number of L* component of the reference color in CIE Lab color space;\n - type: double;\n - default: 0;\n + default: 0; */ CV_WRAP void setWeightCoeff(double weights_coeff); /** @brief set InitialMethod @@ -449,20 +433,17 @@ class CV_EXPORTS_W ColorCorrectionModel Supported list: 'LEAST_SQUARE' (least-squre method); 'WHITE_BALANCE' (white balance method);\n - type: enum INITIAL_METHOD_TYPE; */ CV_WRAP void setInitialMethod(INITIAL_METHOD_TYPE initial_method_type); /** @brief set MaxCount @param max_count used in MinProblemSolver-DownhillSolver;\n Terminal criteria to the algorithm;\n - type: int; default: 5000; */ CV_WRAP void setMaxCount(int max_count); /** @brief set Epsilon @param epsilon used in MinProblemSolver-DownhillSolver;\n Terminal criteria to the algorithm;\n - type: double; default: 1e-4; */ CV_WRAP void setEpsilon(double epsilon); @@ -471,11 +452,11 @@ class CV_EXPORTS_W ColorCorrectionModel CV_WRAP Mat getCCM() const; - // /** @brief Infer using fitting ccm. - // @param img the input image, type of cv::Mat. - // @param islinear default false. - // @return the output array, type of cv::Mat. - // */ + /** @brief Infer using fitting ccm. + @param img the input image. + @param islinear default false. + @return the output array. + */ CV_WRAP Mat infer(const Mat& img, bool islinear = false); private: CV_WRAP class Impl; diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index 8b78025450a..a5ec4eb7dc6 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -35,24 +35,20 @@ Here are the parameters for ColorCorrectionModel src : detected colors of ColorChecker patches; NOTICE: the color type is RGB not BGR, and the color values are in [0, 1]; - type: cv::Mat; constcolor : the Built-in color card; Supported list: Macbeth: Macbeth ColorChecker ; Vinyl: DKK ColorChecker ; DigitalSG: DigitalSG ColorChecker with 140 squares; - type: enum CONST_COLOR; Mat colors_ : the reference color values and corresponding color space NOTICE: the color values are in [0, 1] - type: cv::Mat ref_cs_ : the corresponding color space NOTICE: For the list of color spaces supported, see the notes below; If the color type is some RGB, the format is RGB not BGR; - type:enum COLOR_SPACE; Supported Color Space: Supported list of RGB color spaces: sRGB; From 31d1ea2f04221e9c083b2bddcad30cf8bcfd693b Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Tue, 17 Nov 2020 11:25:49 +0800 Subject: [PATCH 55/71] move underscores _ in public headers --- modules/mcc/include/opencv2/mcc/ccm.hpp | 6 +++--- modules/mcc/src/color.hpp | 8 ++++---- modules/mcc/src/colorspace.hpp | 2 +- modules/mcc/src/io.hpp | 2 +- modules/mcc/src/linearize.hpp | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 451d4b6b83a..725433465c0 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -357,7 +357,7 @@ class CV_EXPORTS_W ColorCorrectionModel For the list of RGB color spaces supported, see the notes above;\n default: sRGB; */ - CV_WRAP void setColorSpace(COLOR_SPACE cs_); + CV_WRAP void setColorSpace(COLOR_SPACE cs); /** @brief set ccm_type @param ccm_type :the shape of color correction matrix(CCM);\n Supported list: "CCM_3x3"(3x3 matrix);"CCM_4x3"( 4x3 matrix);\n @@ -458,9 +458,9 @@ class CV_EXPORTS_W ColorCorrectionModel @return the output array. */ CV_WRAP Mat infer(const Mat& img, bool islinear = false); + class Impl; private: - CV_WRAP class Impl; - CV_WRAP Ptr p; + std::shared_ptr p; }; diff --git a/modules/mcc/src/color.hpp b/modules/mcc/src/color.hpp index d2c9263b2ce..75612a4325a 100644 --- a/modules/mcc/src/color.hpp +++ b/modules/mcc/src/color.hpp @@ -56,10 +56,10 @@ class Color Mat colored; std::map> history; Color(); - Color(Mat colors_, enum COLOR_SPACE cs_); - Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_); - Color(Mat colors_, const ColorSpace& cs_, Mat colored_); - Color(Mat colors_, const ColorSpace& cs_); + Color(Mat colors_, enum COLOR_SPACE cs); + Color(Mat colors_, enum COLOR_SPACE cs, Mat colored); + Color(Mat colors_, const ColorSpace& cs, Mat colored); + Color(Mat colors_, const ColorSpace& cs); virtual ~Color() {}; /** @brief Change to other color space. diff --git a/modules/mcc/src/colorspace.hpp b/modules/mcc/src/colorspace.hpp index 8f1739a5423..2005360fc07 100644 --- a/modules/mcc/src/colorspace.hpp +++ b/modules/mcc/src/colorspace.hpp @@ -339,7 +339,7 @@ class Lab :public ColorSpace { public: static std::map > lab_cs; - Lab(IO io_); + Lab(IO io); static std::shared_ptr get(IO io); private: diff --git a/modules/mcc/src/io.hpp b/modules/mcc/src/io.hpp index 2b4ce1601fa..ede704da2fc 100644 --- a/modules/mcc/src/io.hpp +++ b/modules/mcc/src/io.hpp @@ -47,7 +47,7 @@ class IO std::string illuminant; std::string observer; IO(){}; - IO(std::string illuminant_, std::string observer_) ; + IO(std::string illuminant, std::string observer) ; virtual ~IO(){}; bool operator<(const IO& other) const; bool operator==(const IO& other) const; diff --git a/modules/mcc/src/linearize.hpp b/modules/mcc/src/linearize.hpp index 82e82c2ce36..7da98643149 100644 --- a/modules/mcc/src/linearize.hpp +++ b/modules/mcc/src/linearize.hpp @@ -51,7 +51,7 @@ class Polyfit and deduct: Ax = y See linear.pdf for details */ - Polyfit(Mat x, Mat y, int deg_); + Polyfit(Mat x, Mat y, int deg); virtual ~Polyfit() {}; Mat operator()(const Mat& inp); @@ -73,7 +73,7 @@ class LogPolyfit /** @brief Logpolyfit method. */ - LogPolyfit(Mat x, Mat y, int deg_); + LogPolyfit(Mat x, Mat y, int deg); virtual ~LogPolyfit() {}; Mat operator()(const Mat& inp); From 2bb35fc260a00b22eeb8abbb31e85112e43ed4a3 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Tue, 17 Nov 2020 15:44:13 +0800 Subject: [PATCH 56/71] add @defgroup for ccm --- modules/mcc/include/opencv2/mcc.hpp | 2 +- modules/mcc/include/opencv2/mcc/ccm.hpp | 24 ++- .../mcc/samples/color_correction_model.cpp | 4 +- modules/mcc/src/ccm.cpp | 196 +++++++++--------- modules/mcc/src/color.hpp | 1 - modules/mcc/src/colorspace.hpp | 4 +- modules/mcc/src/io.hpp | 2 +- modules/mcc/src/linearize.hpp | 2 + modules/mcc/src/operations.hpp | 4 +- modules/mcc/src/utils.cpp | 26 +-- modules/mcc/test/test_precomp.hpp | 1 + .../basic_ccm/color_correction_model.markdown | 2 +- 12 files changed, 143 insertions(+), 125 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc.hpp b/modules/mcc/include/opencv2/mcc.hpp index 827af2abc68..c2595f86d31 100644 --- a/modules/mcc/include/opencv2/mcc.hpp +++ b/modules/mcc/include/opencv2/mcc.hpp @@ -32,7 +32,7 @@ #include "mcc/checker_detector.hpp" #include "mcc/checker_model.hpp" -#include "mcc/ccm.hpp" + /** @defgroup mcc Macbeth Chart module diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 725433465c0..22a4b5676c9 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -31,10 +31,30 @@ #include #include + +/** @defgroup ccm Color Correction Model + +Introduction +------------ + +The purpose of color correction is to adjust the color response of input +and output devices to a known state. The device being calibrated is sometimes +called the calibration source; the color space used as the standard is sometimes +called the calibration target. Color calibration has been used in many industries, +such as television production, games, photography, engineering, chemistry, +medicine, etc. Due to the manufacturing process of the input and output equipment, +the channel response has nonlinear distortion. In order to correct the picture output +of the equipment, it is nessary to calibrate the captured color and the actual color. + + +*/ + namespace cv { namespace ccm { +//! @addtogroup ccm +//! @{ /** @brief Enum of the possible types of ccm. */ @@ -352,7 +372,7 @@ class CV_EXPORTS_W ColorCorrectionModel ColorCorrectionModel(const Mat& src, Mat colors, COLOR_SPACE ref_cs, Mat colored); /** @brief set ColorSpace - @param cs_ the absolute color space that detected colors convert to;\n + @param cs the absolute color space that detected colors convert to;\n NOTICE: it should be some RGB color space;\n For the list of RGB color spaces supported, see the notes above;\n default: sRGB; @@ -463,7 +483,7 @@ class CV_EXPORTS_W ColorCorrectionModel std::shared_ptr p; }; - +//! @} ccm } // namespace ccm } // namespace cv diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp index 50062809abc..7b5225a07ba 100644 --- a/modules/mcc/samples/color_correction_model.cpp +++ b/modules/mcc/samples/color_correction_model.cpp @@ -67,13 +67,13 @@ int main(int argc, char *argv[]) //! [get_color_checker] for (Ptr checker : checkers) { - //! [creat] + //! [create] Ptr cdraw = CCheckerDraw::create(checker); cdraw->draw(image); Mat chartsRGB = checker->getChartsRGB(); Mat src = chartsRGB.col(1).clone().reshape(3, 18); src /= 255.0; - //! [creat] + //! [create] //compte color correction matrix //! [get_ccm_Matrix] diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 36e970b0134..20d81f0bb9e 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -32,112 +32,112 @@ namespace cv { namespace ccm { - class ColorCorrectionModel::Impl{ +class ColorCorrectionModel::Impl{ +public: + Mat src; + std::shared_ptr dst =std::make_shared(); + Mat dist; + RGBBase_& cs; + Mat mask; + + // RGBl of detected data and the reference + Mat src_rgbl; + Mat dst_rgbl; + + // ccm type and shape + CCM_TYPE ccm_type; + int shape; + + // linear method and distance + std::shared_ptr linear=std::make_shared(); + DISTANCE_TYPE distance; + LINEAR_TYPE linear_type; + + Mat weights; + Mat ccm; + Mat ccm0; + double gamma; + int deg; + std::vector saturated_threshold; + INITIAL_METHOD_TYPE initial_method_type; + double weights_coeff; + int masked_len; + double loss; + int max_count; + double epsilon; + Impl(); + + /** @brief Make no change for CCM_3x3. + convert cv::Mat A to [A, 1] in CCM_4x3. + @param inp the input array, type of cv::Mat. + @return the output array, type of cv::Mat + */ + Mat prepare(const Mat& inp); + + /** @brief Calculate weights and mask. + @param weights_list the input array, type of cv::Mat. + @param weights_coeff type of double. + @param saturate_mask the input array, type of cv::Mat. + */ + void calWeightsMasks(Mat weights_list, double weights_coeff, Mat saturate_mask); + + /** @brief Fitting nonlinear - optimization initial value by white balance. + see CCM.pdf for details. + @return the output array, type of Mat + */ + void initialWhiteBalance(void); + + /** @brief Fitting nonlinear-optimization initial value by least square. + see CCM.pdf for details + @param fit if fit is True, return optimalization for rgbl distance function. + */ + void initialLeastSquare(bool fit = false); + + double calc_loss_(Color color); + double calc_loss(const Mat ccm_); + + /** @brief Fitting ccm if distance function is associated with CIE Lab color space. + see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp + Set terminal criteria for solver is possible. + */ + void fitting(void); + + + void get_color(Mat& img_, bool islinear = false); + void get_color(CONST_COLOR constcolor); + void get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_); + void get_color(Mat colors_, COLOR_SPACE ref_cs_); + + + /** @brief Loss function base on cv::MinProblemSolver::Function. + see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp + */ + class LossFunction : public MinProblemSolver::Function + { public: - Mat src; - std::shared_ptr dst =std::make_shared(); - Mat dist; - RGBBase_& cs; - Mat mask; - - // RGBl of detected data and the reference - Mat src_rgbl; - Mat dst_rgbl; - - // ccm type and shape - CCM_TYPE ccm_type; - int shape; - - // linear method and distance - std::shared_ptr linear=std::make_shared(); - DISTANCE_TYPE distance; - LINEAR_TYPE linear_type; - - Mat weights; - Mat ccm; - Mat ccm0; - double gamma; - int deg; - std::vector saturated_threshold; - INITIAL_METHOD_TYPE initial_method_type; - double weights_coeff; - int masked_len; - double loss; - int max_count; - double epsilon; - Impl(); - - /** @brief Make no change for CCM_3x3. - convert cv::Mat A to [A, 1] in CCM_4x3. - @param inp the input array, type of cv::Mat. - @return the output array, type of cv::Mat - */ - Mat prepare(const Mat& inp); - - /** @brief Calculate weights and mask. - @param weights_list the input array, type of cv::Mat. - @param weights_coeff type of double. - @param saturate_mask the input array, type of cv::Mat. - */ - void calWeightsMasks(Mat weights_list, double weights_coeff, Mat saturate_mask); - - /** @brief Fitting nonlinear - optimization initial value by white balance. - see CCM.pdf for details. - @return the output array, type of Mat - */ - void initialWhiteBalance(void); + ColorCorrectionModel::Impl * ccm_loss; + LossFunction(ColorCorrectionModel::Impl* ccm) : ccm_loss(ccm) {}; - /** @brief Fitting nonlinear-optimization initial value by least square. - see CCM.pdf for details - @param fit if fit is True, return optimalization for rgbl distance function. + /** @brief Reset dims to ccm->shape. */ - void initialLeastSquare(bool fit = false); - - double calc_loss_(Color color); - double calc_loss(const Mat ccm_); - - /** @brief Fitting ccm if distance function is associated with CIE Lab color space. - see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp - Set terminal criteria for solver is possible. - */ - void fitting(void); - - - void get_color(Mat& img_, bool islinear = false); - void get_color(CONST_COLOR constcolor); - void get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_); - void get_color(Mat colors_, COLOR_SPACE ref_cs_); - + int getDims() const CV_OVERRIDE + { + return ccm_loss->shape; + } - /** @brief Loss function base on cv::MinProblemSolver::Function. - see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp + /** @brief Reset calculation. */ - class LossFunction : public MinProblemSolver::Function + double calc(const double* x) const CV_OVERRIDE { - public: - ColorCorrectionModel::Impl * ccm_loss; - LossFunction(ColorCorrectionModel::Impl* ccm) : ccm_loss(ccm) {}; - - /** @brief Reset dims to ccm->shape. - */ - int getDims() const CV_OVERRIDE + Mat ccm_(ccm_loss->shape, 1, CV_64F); + for (int i = 0; i < ccm_loss->shape; i++) { - return ccm_loss->shape; + ccm_.at(i, 0) = x[i]; } - - /** @brief Reset calculation. - */ - double calc(const double* x) const CV_OVERRIDE - { - Mat ccm_(ccm_loss->shape, 1, CV_64F); - for (int i = 0; i < ccm_loss->shape; i++) - { - ccm_.at(i, 0) = x[i]; - } - ccm_ = ccm_.reshape(0, ccm_loss->shape / 3); - return ccm_loss->calc_loss(ccm_); - } - }; + ccm_ = ccm_.reshape(0, ccm_loss->shape / 3); + return ccm_loss->calc_loss(ccm_); + } +}; }; ColorCorrectionModel::Impl::Impl():cs(*GetCS::get_rgb(sRGB)),ccm_type(CCM_3x3), distance(CIE2000),linear_type(GAMMA), weights(Mat()),gamma(2.2),deg(3),saturated_threshold({ 0, 0.98 }), diff --git a/modules/mcc/src/color.hpp b/modules/mcc/src/color.hpp index 75612a4325a..a1802be70cb 100644 --- a/modules/mcc/src/color.hpp +++ b/modules/mcc/src/color.hpp @@ -28,7 +28,6 @@ #ifndef __OPENCV_MCC_COLOR_HPP__ #define __OPENCV_MCC_COLOR_HPP__ -#include #include "distance.hpp" #include "colorspace.hpp" #include "opencv2/mcc/ccm.hpp" diff --git a/modules/mcc/src/colorspace.hpp b/modules/mcc/src/colorspace.hpp index 2005360fc07..6de21566b3c 100644 --- a/modules/mcc/src/colorspace.hpp +++ b/modules/mcc/src/colorspace.hpp @@ -29,9 +29,7 @@ #ifndef __OPENCV_MCC_COLORSPACE_HPP__ #define __OPENCV_MCC_COLORSPACE_HPP__ -#include -#include -#include + #include "operations.hpp" #include "io.hpp" #include "opencv2/mcc/ccm.hpp" diff --git a/modules/mcc/src/io.hpp b/modules/mcc/src/io.hpp index ede704da2fc..872e160c830 100644 --- a/modules/mcc/src/io.hpp +++ b/modules/mcc/src/io.hpp @@ -32,7 +32,7 @@ #include #include - +#include namespace cv { diff --git a/modules/mcc/src/linearize.hpp b/modules/mcc/src/linearize.hpp index 7da98643149..26472b030f4 100644 --- a/modules/mcc/src/linearize.hpp +++ b/modules/mcc/src/linearize.hpp @@ -29,6 +29,8 @@ #ifndef __OPENCV_MCC_LINEARIZE_HPP__ #define __OPENCV_MCC_LINEARIZE_HPP__ +#include +#include #include "color.hpp" #include "opencv2/mcc/ccm.hpp" namespace cv diff --git a/modules/mcc/src/operations.hpp b/modules/mcc/src/operations.hpp index d005b71e377..2738c073f30 100644 --- a/modules/mcc/src/operations.hpp +++ b/modules/mcc/src/operations.hpp @@ -29,8 +29,6 @@ #ifndef __OPENCV_MCC_OPERATIONS_HPP__ #define __OPENCV_MCC_OPERATIONS_HPP__ -#include -#include #include "utils.hpp" namespace cv @@ -64,7 +62,7 @@ class Operation void add(const Operation& other); void clear(); - static Operation get_IDENTITY_OP(){ + static Operation& get_IDENTITY_OP(){ static Operation identity_op([](Mat x) {return x; }); return identity_op; } diff --git a/modules/mcc/src/utils.cpp b/modules/mcc/src/utils.cpp index e338cc1f1c4..afc8c01261c 100644 --- a/modules/mcc/src/utils.cpp +++ b/modules/mcc/src/utils.cpp @@ -37,14 +37,14 @@ double gammaCorrection_(const double& element, const double& gamma) return (element >= 0 ? pow(element, gamma) : -pow((-element), gamma)); } -cv::Mat gammaCorrection(const cv::Mat& src, const double& gamma) +Mat gammaCorrection(const Mat& src, const double& gamma) { return elementWise(src, [gamma](double element)->double {return gammaCorrection_(element, gamma); }); } -cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) +Mat maskCopyTo(const Mat& src, const Mat& mask) { - cv::Mat dst(countNonZero(mask), 1, src.type()); + Mat dst(countNonZero(mask), 1, src.type()); const int channel = src.channels(); auto it_mask = mask.begin(); switch (channel) @@ -65,8 +65,8 @@ cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) } case 3: { - auto it_src = src.begin(), end_src = src.end(); - auto it_dst = dst.begin(); + auto it_src = src.begin(), end_src = src.end(); + auto it_dst = dst.begin(); for (; it_src != end_src; ++it_src, ++it_mask) { if (*it_mask) @@ -84,19 +84,19 @@ cv::Mat maskCopyTo(const cv::Mat& src, const cv::Mat& mask) return dst; } -cv::Mat multiple(const cv::Mat& xyz, const cv::Mat& ccm) +Mat multiple(const Mat& xyz, const Mat& ccm) { - cv::Mat tmp = xyz.reshape(1, xyz.rows * xyz.cols); - cv::Mat res = tmp * ccm; + Mat tmp = xyz.reshape(1, xyz.rows * xyz.cols); + Mat res = tmp * ccm; res = res.reshape(res.cols, xyz.rows); return res; } -cv::Mat saturate(cv::Mat& src, const double& low, const double& up) +Mat saturate(Mat& src, const double& low, const double& up) { - cv::Mat dst = cv::Mat::ones(src.size(), CV_8UC1); - cv::MatIterator_ it_src = src.begin(), end_src = src.end(); - cv::MatIterator_ it_dst = dst.begin(); + Mat dst = Mat::ones(src.size(), CV_8UC1); + MatIterator_ it_src = src.begin(), end_src = src.end(); + MatIterator_ it_dst = dst.begin(); for (; it_src != end_src; ++it_src, ++it_dst) { for (int i = 0; i < 3; ++i) @@ -111,7 +111,7 @@ cv::Mat saturate(cv::Mat& src, const double& low, const double& up) return dst; } -cv::Mat rgb2gray(cv::Mat rgb) +Mat rgb2gray(Mat rgb) { return multiple(rgb, m_gray); } diff --git a/modules/mcc/test/test_precomp.hpp b/modules/mcc/test/test_precomp.hpp index 258c86f217c..c4d81a348c5 100644 --- a/modules/mcc/test/test_precomp.hpp +++ b/modules/mcc/test/test_precomp.hpp @@ -8,6 +8,7 @@ #include "opencv2/ts.hpp" #include "opencv2/ts/cuda_test.hpp" #include "opencv2/mcc.hpp" +#include "opencv2/mcc/ccm.hpp" namespace opencv_test { diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index a5ec4eb7dc6..9e019491cb3 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -107,7 +107,7 @@ The first part is to detect the ColorChecker position. @snippet samples/color_correction_model.cpp get_messages_of_image Preparation for ColorChecker detection to get messages for the image. -@snippet samples/color_correction_model.cpp creat +@snippet samples/color_correction_model.cpp create The CCheckerDetectorobject is created and uses getListColorChecker function to get ColorChecker message. @snippet samples/color_correction_model.cpp get_ccm_Matrix From a29e97ad31e32ac6b5f88261e7e2f19a115725b5 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Tue, 17 Nov 2020 16:51:26 +0800 Subject: [PATCH 57/71] move and add getloss() method for class ColorCorrection Model --- modules/mcc/include/opencv2/mcc.hpp | 2 +- modules/mcc/include/opencv2/mcc/ccm.hpp | 1 + modules/mcc/samples/color_correction_model.cpp | 4 ++++ modules/mcc/src/ccm.cpp | 6 +++--- modules/mcc/src/io.hpp | 1 - 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc.hpp b/modules/mcc/include/opencv2/mcc.hpp index c2595f86d31..827af2abc68 100644 --- a/modules/mcc/include/opencv2/mcc.hpp +++ b/modules/mcc/include/opencv2/mcc.hpp @@ -32,7 +32,7 @@ #include "mcc/checker_detector.hpp" #include "mcc/checker_model.hpp" - +#include "mcc/ccm.hpp" /** @defgroup mcc Macbeth Chart module diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 22a4b5676c9..5b43b09b546 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -471,6 +471,7 @@ class CV_EXPORTS_W ColorCorrectionModel CV_WRAP void run(); CV_WRAP Mat getCCM() const; + CV_WRAP double getLoss() const; /** @brief Infer using fitting ccm. @param img the input image. diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp index 7b5225a07ba..39865ce42d1 100644 --- a/modules/mcc/samples/color_correction_model.cpp +++ b/modules/mcc/samples/color_correction_model.cpp @@ -78,6 +78,10 @@ int main(int argc, char *argv[]) //compte color correction matrix //! [get_ccm_Matrix] ColorCorrectionModel model1(src, Vinyl); + model1.run(); + Mat ccm = model1.getCCM(); + std::cout<<"ccm "<minimize(reshapeccm); ccm = reshapeccm.reshape(0, shape/3); loss = pow((res / masked_len), 0.5); - std::cout << " ccm " << ccm << std::endl; - std::cout << " loss " << loss << std::endl; } Mat ColorCorrectionModel::infer(const Mat& img, bool islinear) @@ -390,6 +388,8 @@ void ColorCorrectionModel::run(){ Mat ColorCorrectionModel::getCCM() const{ return p->ccm; } - +double ColorCorrectionModel::getLoss() const{ + return p->loss; +} } // namespace ccm } // namespace cv diff --git a/modules/mcc/src/io.hpp b/modules/mcc/src/io.hpp index 872e160c830..eeb308352ac 100644 --- a/modules/mcc/src/io.hpp +++ b/modules/mcc/src/io.hpp @@ -32,7 +32,6 @@ #include #include -#include namespace cv { From a11b1155600b72545e3a553219117c9bc1d3d695 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Tue, 17 Nov 2020 22:43:17 +0800 Subject: [PATCH 58/71] update sample/color_correction_model.cpp --- modules/mcc/samples/color_correction_model.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp index 39865ce42d1..c2b18113add 100644 --- a/modules/mcc/samples/color_correction_model.cpp +++ b/modules/mcc/samples/color_correction_model.cpp @@ -82,6 +82,7 @@ int main(int argc, char *argv[]) Mat ccm = model1.getCCM(); std::cout<<"ccm "< Date: Wed, 18 Nov 2020 11:13:56 +0800 Subject: [PATCH 59/71] add getIOs() function for minimize initialization of IO variables --- modules/mcc/src/colorspace.cpp | 73 +++++++++++++++---------------- modules/mcc/src/colorspace.hpp | 24 +++++------ modules/mcc/src/io.cpp | 79 ++++++++++++++++++++++++++++++++++ modules/mcc/src/io.hpp | 25 +++++++---- 4 files changed, 144 insertions(+), 57 deletions(-) diff --git a/modules/mcc/src/colorspace.cpp b/modules/mcc/src/colorspace.cpp index 1fe2155bbfb..e41327198c5 100644 --- a/modules/mcc/src/colorspace.cpp +++ b/modules/mcc/src/colorspace.cpp @@ -34,18 +34,18 @@ namespace ccm { static std::map> getilluminants() { static std::map> illuminants = { - {A_2, { 1.098466069456375, 1, 0.3558228003436005 }}, - {A_10, { 1.111420406956693, 1, 0.3519978321919493 }}, - {D50_2, { 0.9642119944211994, 1, 0.8251882845188288 }}, - {D50_10, { 0.9672062750333777, 1, 0.8142801513128616 }}, - {D55_2, { 0.956797052643698, 1, 0.9214805860173273 }}, - {D55_10, { 0.9579665682254781, 1, 0.9092525159847462 }}, - {D65_2, { 0.95047, 1., 1.08883 }}, - {D65_10, { 0.94811, 1., 1.07304 }}, - {D75_2, { 0.9497220898840717, 1, 1.226393520724154 }}, - {D75_10, { 0.9441713925645873, 1, 1.2064272211720228 }}, - {E_2, { 1., 1., 1. }}, - {E_10, { 1., 1., 1. }}, + {IO::getIOs(A_2), { 1.098466069456375, 1, 0.3558228003436005 }}, + {IO::getIOs(A_10), { 1.111420406956693, 1, 0.3519978321919493 }}, + {IO::getIOs(D50_2), { 0.9642119944211994, 1, 0.8251882845188288 }}, + {IO::getIOs(D50_10), { 0.9672062750333777, 1, 0.8142801513128616 }}, + {IO::getIOs(D55_2), { 0.956797052643698, 1, 0.9214805860173273 }}, + {IO::getIOs(D55_10), { 0.9579665682254781, 1, 0.9092525159847462 }}, + {IO::getIOs(D65_2), { 0.95047, 1., 1.08883 }}, + {IO::getIOs(D65_10), { 0.94811, 1., 1.07304 }}, + {IO::getIOs(D75_2), { 0.9497220898840717, 1, 1.226393520724154 }}, + {IO::getIOs(D75_10), { 0.9441713925645873, 1, 1.2064272211720228 }}, + {IO::getIOs(E_2), { 1., 1., 1. }}, + {IO::getIOs(E_10), { 1., 1., 1. }}, }; return illuminants; }; @@ -621,81 +621,82 @@ std::shared_ptr GetCS::get_cs(enum COLOR_SPACE cs_name) { break; } case cv::ccm::XYZ_D65_2: - return XYZ::get(D65_2); + return XYZ::get(IO::getIOs(D65_2)); break; case cv::ccm::XYZ_D50_2: - return XYZ::get(D50_2); + return XYZ::get(IO::getIOs(D50_2)); break; case cv::ccm::XYZ_D65_10: - return XYZ::get(D65_10); + return XYZ::get(IO::getIOs(D65_10)); break; case cv::ccm::XYZ_D50_10: - return XYZ::get(D50_10); + return XYZ::get(IO::getIOs(D50_10)); break; case cv::ccm::XYZ_A_2: - return XYZ::get(A_2); + return XYZ::get(IO::getIOs(A_2)); break; case cv::ccm::XYZ_A_10: - return XYZ::get(A_10); + return XYZ::get(IO::getIOs(A_10)); break; case cv::ccm::XYZ_D55_2: - return XYZ::get(D55_2); + return XYZ::get(IO::getIOs(D55_2)); break; case cv::ccm::XYZ_D55_10: - return XYZ::get(D55_10); + return XYZ::get(IO::getIOs(D55_10)); break; case cv::ccm::XYZ_D75_2: - return XYZ::get(D75_2); + return XYZ::get(IO::getIOs(D75_2)); break; case cv::ccm::XYZ_D75_10: - return XYZ::get(D75_10); + return XYZ::get(IO::getIOs(D75_10)); break; case cv::ccm::XYZ_E_2: - return XYZ::get(E_2); + return XYZ::get(IO::getIOs(E_2)); break; case cv::ccm::XYZ_E_10: - return XYZ::get(E_10); + return XYZ::get(IO::getIOs(E_10)); break; case cv::ccm::Lab_D65_2: - return Lab::get(D65_2); + return Lab::get(IO::getIOs(D65_2)); break; case cv::ccm::Lab_D50_2: - return Lab::get(D50_2); + return Lab::get(IO::getIOs(D50_2)); break; case cv::ccm::Lab_D65_10: - return Lab::get(D65_10); + return Lab::get(IO::getIOs(D65_10)); break; case cv::ccm::Lab_D50_10: - return Lab::get(D50_10); + return Lab::get(IO::getIOs(D50_10)); break; case cv::ccm::Lab_A_2: - return Lab::get(A_2); + return Lab::get(IO::getIOs(A_2)); break; case cv::ccm::Lab_A_10: - return Lab::get(A_10); + return Lab::get(IO::getIOs(A_10)); break; case cv::ccm::Lab_D55_2: - return Lab::get(D55_2); + return Lab::get(IO::getIOs(D55_2)); break; case cv::ccm::Lab_D55_10: - return Lab::get(D55_10); + return Lab::get(IO::getIOs(D55_10)); break; case cv::ccm::Lab_D75_2: - return Lab::get(D75_2); + return Lab::get(IO::getIOs(D75_2)); break; case cv::ccm::Lab_D75_10: - return Lab::get(D75_10); + return Lab::get(IO::getIOs(D75_10)); break; case cv::ccm::Lab_E_2: - return Lab::get(E_2); + return Lab::get(IO::getIOs(E_2)); break; case cv::ccm::Lab_E_10: - return Lab::get(E_10); + return Lab::get(IO::getIOs(E_10)); break; default: break; } + return map_cs[cs_name]; } diff --git a/modules/mcc/src/colorspace.hpp b/modules/mcc/src/colorspace.hpp index 6de21566b3c..0bc86e318d4 100644 --- a/modules/mcc/src/colorspace.hpp +++ b/modules/mcc/src/colorspace.hpp @@ -195,7 +195,7 @@ class sRGB_ :public sRGBBase_ { public: - sRGB_(bool linear_) :sRGBBase_(D65_2, "sRGB", linear_) {}; + sRGB_(bool linear_) :sRGBBase_(IO::getIOs(D65_2), "sRGB", linear_) {}; private: void setParameter() CV_OVERRIDE; @@ -206,7 +206,7 @@ class sRGB_ :public sRGBBase_ class AdobeRGB_ : public AdobeRGBBase_ { public: - AdobeRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AdobeRGB", linear_) {}; + AdobeRGB_(bool linear_ = false) :AdobeRGBBase_(IO::getIOs(D65_2), "AdobeRGB", linear_) {}; private: void setParameter() CV_OVERRIDE; @@ -219,7 +219,7 @@ class AdobeRGB_ : public AdobeRGBBase_ class WideGamutRGB_ : public AdobeRGBBase_ { public: - WideGamutRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "WideGamutRGB", linear_) {}; + WideGamutRGB_(bool linear_ = false) :AdobeRGBBase_(IO::getIOs(D50_2), "WideGamutRGB", linear_) {}; private: void setParameter() CV_OVERRIDE; @@ -232,7 +232,7 @@ class WideGamutRGB_ : public AdobeRGBBase_ class ProPhotoRGB_ : public AdobeRGBBase_ { public: - ProPhotoRGB_(bool linear_ = false) :AdobeRGBBase_(D50_2, "ProPhotoRGB", linear_) {}; + ProPhotoRGB_(bool linear_ = false) :AdobeRGBBase_(IO::getIOs(D50_2), "ProPhotoRGB", linear_) {}; private: void setParameter() CV_OVERRIDE; @@ -244,7 +244,7 @@ class ProPhotoRGB_ : public AdobeRGBBase_ class DCI_P3_RGB_ : public AdobeRGBBase_ { public: - DCI_P3_RGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "DCI_P3_RGB", linear_) {}; + DCI_P3_RGB_(bool linear_ = false) :AdobeRGBBase_(IO::getIOs(D65_2), "DCI_P3_RGB", linear_) {}; private: void setParameter() CV_OVERRIDE; @@ -256,7 +256,7 @@ class DCI_P3_RGB_ : public AdobeRGBBase_ class AppleRGB_ : public AdobeRGBBase_ { public: - AppleRGB_(bool linear_ = false) :AdobeRGBBase_(D65_2, "AppleRGB", linear_) {}; + AppleRGB_(bool linear_ = false) :AdobeRGBBase_(IO::getIOs(D65_2), "AppleRGB", linear_) {}; private: void setParameter() CV_OVERRIDE; @@ -268,7 +268,7 @@ class AppleRGB_ : public AdobeRGBBase_ class REC_709_RGB_ : public sRGBBase_ { public: - REC_709_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_709_RGB", linear_) {}; + REC_709_RGB_(bool linear_) :sRGBBase_(IO::getIOs(D65_2), "REC_709_RGB", linear_) {}; private: void setParameter() CV_OVERRIDE; @@ -280,7 +280,7 @@ class REC_709_RGB_ : public sRGBBase_ class REC_2020_RGB_ : public sRGBBase_ { public: - REC_2020_RGB_(bool linear_) :sRGBBase_(D65_2, "REC_2020_RGB", linear_) {}; + REC_2020_RGB_(bool linear_) :sRGBBase_(IO::getIOs(D65_2), "REC_2020_RGB", linear_) {}; private: void setParameter() CV_OVERRIDE; @@ -328,8 +328,8 @@ class XYZ :public ColorSpace /** @brief Define XYZ_D65_2 and XYZ_D50_2. */ -const XYZ XYZ_D65_2_CS(D65_2); -const XYZ XYZ_D50_2_CS(D50_2); +const XYZ XYZ_D65_2_CS(IO::getIOs(D65_2)); +const XYZ XYZ_D50_2_CS(IO::getIOs(D50_2)); /** @brief Lab color space. */ @@ -366,8 +366,8 @@ class Lab :public ColorSpace /** @brief Define Lab_D65_2 and Lab_D50_2. */ -const Lab Lab_D65_2_CS(D65_2); -const Lab Lab_D50_2_CS(D50_2); +const Lab Lab_D65_2_CS(IO::getIOs(D65_2)); +const Lab Lab_D50_2_CS(IO::getIOs(D50_2)); class GetCS { diff --git a/modules/mcc/src/io.cpp b/modules/mcc/src/io.cpp index d2fe9dbfe4d..8643b058c1c 100644 --- a/modules/mcc/src/io.cpp +++ b/modules/mcc/src/io.cpp @@ -42,6 +42,85 @@ bool IO::operator==(const IO& other) const return illuminant == other.illuminant && observer == other.observer; }; +IO IO::getIOs(IO_TYPE io) { + switch (io) + { + case cv::ccm::A_2: + { + IO A_2_IO("A", "2"); + return A_2_IO; + break; + } + case cv::ccm::A_10: + { + IO A_1O_IO("A", "10"); + return A_1O_IO; + break; + } + case cv::ccm::D50_2: + { + IO D50_2_IO("D50", "2"); + return D50_2_IO; + break; + } + case cv::ccm::D50_10: + { + IO D50_10_IO("D50", "10"); + return D50_10_IO; + break; + } + case cv::ccm::D55_2: + { + IO D55_2_IO("D55", "2"); + return D55_2_IO; + break; + } + case cv::ccm::D55_10: + { + IO D55_10_IO("D55", "10"); + return D55_10_IO; + break; + } + case cv::ccm::D65_2: + { + IO D65_2_IO("D65", "2"); + return D65_2_IO; + } + case cv::ccm::D65_10: + { + IO D65_10_IO("D65", "10"); + return D65_10_IO; + break; + } + case cv::ccm::D75_2: + { + IO D75_2_IO("D75", "2"); + return D75_2_IO; + break; + } + case cv::ccm::D75_10: + { + IO D75_10_IO("D75", "10"); + return D75_10_IO; + break; + } + case cv::ccm::E_2: + { + IO E_2_IO("E", "2"); + return E_2_IO; + break; + } + case cv::ccm::E_10: + { + IO E_10_IO("E", "10"); + return E_10_IO; + break; + } + default: + return IO(); + break; + } +} // data from https://en.wikipedia.org/wiki/Standard_illuminant. std::vector xyY2XYZ(const std::vector& xyY) { diff --git a/modules/mcc/src/io.hpp b/modules/mcc/src/io.hpp index eeb308352ac..65e7d23680f 100644 --- a/modules/mcc/src/io.hpp +++ b/modules/mcc/src/io.hpp @@ -38,6 +38,21 @@ namespace cv namespace ccm { +enum IO_TYPE { + A_2, + A_10, + D50_2, + D50_10, + D55_2, + D55_10, + D65_2, + D65_10, + D75_2, + D75_10, + E_2, + E_10 + }; + /** @brief Io is the meaning of illuminant and observer. See notes of ccm.hpp for supported list for illuminant and observer*/ class IO @@ -50,17 +65,9 @@ class IO virtual ~IO(){}; bool operator<(const IO& other) const; bool operator==(const IO& other) const; + static IO getIOs(IO_TYPE io); }; - -const IO A_2("A", "2"), A_10("A", "10"), - D50_2("D50", "2"), D50_10("D50", "10"), - D55_2("D55", "2"), D55_10("D55", "10"), - D65_2("D65", "2"), D65_10("D65", "10"), - D75_2("D75", "2"), D75_10("D75", "10"), - E_2("E", "2"), E_10("E", "10"); - - std::vector xyY2XYZ(const std::vector& xyY); From f97f92742878eeb94136dab5a93979c9b0e488c7 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 19 Nov 2020 19:45:14 +0000 Subject: [PATCH 60/71] mcc(ccm): apply clang-format --- modules/mcc/src/ccm.cpp | 130 +++++--- modules/mcc/src/color.cpp | 476 ++++++++++++++-------------- modules/mcc/src/color.hpp | 26 +- modules/mcc/src/colorspace.cpp | 552 ++++++++++++++++++--------------- modules/mcc/src/colorspace.hpp | 82 ++--- modules/mcc/src/distance.cpp | 56 ++-- modules/mcc/src/distance.hpp | 20 +- modules/mcc/src/io.cpp | 17 +- modules/mcc/src/io.hpp | 50 ++- modules/mcc/src/linearize.cpp | 22 +- modules/mcc/src/linearize.hpp | 34 +- modules/mcc/src/operations.cpp | 10 +- modules/mcc/src/operations.hpp | 41 +-- modules/mcc/src/utils.cpp | 12 +- modules/mcc/src/utils.hpp | 12 +- 15 files changed, 807 insertions(+), 733 deletions(-) diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 00987bbde59..42bc370aefc 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -25,17 +25,15 @@ // Jinheng Zhang // Chenqi Shan - #include "opencv2/mcc/ccm.hpp" #include "linearize.hpp" -namespace cv -{ -namespace ccm +namespace cv { +namespace ccm { +class ColorCorrectionModel::Impl { -class ColorCorrectionModel::Impl{ public: Mat src; - std::shared_ptr dst =std::make_shared(); + std::shared_ptr dst = std::make_shared(); Mat dist; RGBBase_& cs; Mat mask; @@ -49,7 +47,7 @@ class ColorCorrectionModel::Impl{ int shape; // linear method and distance - std::shared_ptr linear=std::make_shared(); + std::shared_ptr linear = std::make_shared(); DISTANCE_TYPE distance; LINEAR_TYPE linear_type; @@ -102,21 +100,20 @@ class ColorCorrectionModel::Impl{ */ void fitting(void); - void get_color(Mat& img_, bool islinear = false); void get_color(CONST_COLOR constcolor); void get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_); void get_color(Mat colors_, COLOR_SPACE ref_cs_); - /** @brief Loss function base on cv::MinProblemSolver::Function. see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp */ class LossFunction : public MinProblemSolver::Function { public: - ColorCorrectionModel::Impl * ccm_loss; - LossFunction(ColorCorrectionModel::Impl* ccm) : ccm_loss(ccm) {}; + ColorCorrectionModel::Impl* ccm_loss; + LossFunction(ColorCorrectionModel::Impl* ccm) + : ccm_loss(ccm) {}; /** @brief Reset dims to ccm->shape. */ @@ -137,11 +134,23 @@ class ColorCorrectionModel::Impl{ ccm_ = ccm_.reshape(0, ccm_loss->shape / 3); return ccm_loss->calc_loss(ccm_); } -}; + }; }; -ColorCorrectionModel::Impl::Impl():cs(*GetCS::get_rgb(sRGB)),ccm_type(CCM_3x3), distance(CIE2000),linear_type(GAMMA), weights(Mat()),gamma(2.2),deg(3),saturated_threshold({ 0, 0.98 }), - initial_method_type(LEAST_SQUARE),weights_coeff(0),max_count(5000),epsilon(1.e-4){} +ColorCorrectionModel::Impl::Impl() + : cs(*GetCS::get_rgb(sRGB)) + , ccm_type(CCM_3x3) + , distance(CIE2000) + , linear_type(GAMMA) + , weights(Mat()) + , gamma(2.2) + , deg(3) + , saturated_threshold({ 0, 0.98 }) + , initial_method_type(LEAST_SQUARE) + , weights_coeff(0) + , max_count(5000) + , epsilon(1.e-4) +{} Mat ColorCorrectionModel::Impl::prepare(const Mat& inp) { @@ -157,11 +166,11 @@ Mat ColorCorrectionModel::Impl::prepare(const Mat& inp) Mat arr_out(inp.size(), CV_64FC4); Mat arr_channels[3]; split(inp, arr_channels); - merge(std::vector{arr_channels[0], arr_channels[1], arr_channels[2], arr1}, arr_out); + merge(std::vector { arr_channels[0], arr_channels[1], arr_channels[2], arr1 }, arr_out); return arr_out; } default: - throw std::invalid_argument{ "Wrong ccm_type!" }; + throw std::invalid_argument { "Wrong ccm_type!" }; break; } } @@ -202,8 +211,8 @@ void ColorCorrectionModel::Impl::initialWhiteBalance(void) Mat dchannels[4]; split(dst_rgbl, dchannels); std::vector initial_vec = { sum(dchannels[0])[0] / sum(schannels[0])[0], 0, 0, 0, - sum(dchannels[1])[0] / sum(schannels[1])[0], 0, 0, 0, - sum(dchannels[2])[0] / sum(schannels[2])[0], 0, 0, 0 }; + sum(dchannels[1])[0] / sum(schannels[1])[0], 0, 0, 0, + sum(dchannels[2])[0] / sum(schannels[2])[0], 0, 0, 0 }; std::vector initial_vec_(initial_vec.begin(), initial_vec.begin() + shape); Mat initial_white_balance = Mat(initial_vec_, true).reshape(0, shape / 3); ccm0 = initial_white_balance; @@ -221,7 +230,7 @@ void ColorCorrectionModel::Impl::initialLeastSquare(bool fit) { pow(weights, 0.5, w); Mat w_; - merge(std::vector{w, w, w}, w_); + merge(std::vector { w, w, w }, w_); A = w_.mul(src_rgbl); B = w_.mul(dst_rgbl); } @@ -270,7 +279,7 @@ void ColorCorrectionModel::Impl::fitting(void) TermCriteria termcrit = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, max_count, epsilon); solver->setTermCriteria(termcrit); double res = solver->minimize(reshapeccm); - ccm = reshapeccm.reshape(0, shape/3); + ccm = reshapeccm.reshape(0, shape / 3); loss = pow((res / masked_len), 0.5); } @@ -291,66 +300,87 @@ Mat ColorCorrectionModel::infer(const Mat& img, bool islinear) return p->cs.fromL(img_ccm); } -void ColorCorrectionModel::Impl::get_color(CONST_COLOR constcolor){ - dst =(GetColor::get_color(constcolor)); +void ColorCorrectionModel::Impl::get_color(CONST_COLOR constcolor) +{ + dst = (GetColor::get_color(constcolor)); } -void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE ref_cs_){ - dst.reset( new Color(colors_, *GetCS::get_cs(ref_cs_))); +void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE ref_cs_) +{ + dst.reset(new Color(colors_, *GetCS::get_cs(ref_cs_))); } -void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_){ - dst.reset( new Color(colors_, *GetCS::get_cs(cs_),colored_)); +void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_) +{ + dst.reset(new Color(colors_, *GetCS::get_cs(cs_), colored_)); } -ColorCorrectionModel::ColorCorrectionModel(const Mat& src_, CONST_COLOR constcolor): p(new Impl){ +ColorCorrectionModel::ColorCorrectionModel(const Mat& src_, CONST_COLOR constcolor) + : p(new Impl) +{ p->src = src_; p->get_color(constcolor); } -ColorCorrectionModel:: ColorCorrectionModel(const Mat& src_, Mat colors_, COLOR_SPACE ref_cs_): p(new Impl){ +ColorCorrectionModel::ColorCorrectionModel(const Mat& src_, Mat colors_, COLOR_SPACE ref_cs_) + : p(new Impl) +{ p->src = src_; p->get_color(colors_, ref_cs_); } -ColorCorrectionModel::ColorCorrectionModel(const Mat& src_, Mat colors_, COLOR_SPACE cs_, Mat colored_): p(new Impl){ +ColorCorrectionModel::ColorCorrectionModel(const Mat& src_, Mat colors_, COLOR_SPACE cs_, Mat colored_) + : p(new Impl) +{ p->src = src_; p->get_color(colors_, cs_, colored_); } -void ColorCorrectionModel::setColorSpace(COLOR_SPACE cs_){ +void ColorCorrectionModel::setColorSpace(COLOR_SPACE cs_) +{ p->cs = *GetCS::get_rgb(cs_); } -void ColorCorrectionModel::setCCM_TYPE(CCM_TYPE ccm_type_){ +void ColorCorrectionModel::setCCM_TYPE(CCM_TYPE ccm_type_) +{ p->ccm_type = ccm_type_; } -void ColorCorrectionModel::setDistance(DISTANCE_TYPE distance_){ +void ColorCorrectionModel::setDistance(DISTANCE_TYPE distance_) +{ p->distance = distance_; } -void ColorCorrectionModel::setLinear(LINEAR_TYPE linear_type){ +void ColorCorrectionModel::setLinear(LINEAR_TYPE linear_type) +{ p->linear_type = linear_type; } -void ColorCorrectionModel::setLinearGamma(double gamma){ +void ColorCorrectionModel::setLinearGamma(double gamma) +{ p->gamma = gamma; } -void ColorCorrectionModel::setLinearDegree(int deg){ +void ColorCorrectionModel::setLinearDegree(int deg) +{ p->deg = deg; } -void ColorCorrectionModel::setSaturatedThreshold(double lower, double upper){//std::vector saturated_threshold - p->saturated_threshold = {lower, upper}; +void ColorCorrectionModel::setSaturatedThreshold(double lower, double upper) +{ //std::vector saturated_threshold + p->saturated_threshold = { lower, upper }; } -void ColorCorrectionModel::setWeightsList(Mat weights_list){ +void ColorCorrectionModel::setWeightsList(Mat weights_list) +{ p->weights = weights_list; } -void ColorCorrectionModel::setWeightCoeff(double weights_coeff){ +void ColorCorrectionModel::setWeightCoeff(double weights_coeff) +{ p->weights_coeff = weights_coeff; - } -void ColorCorrectionModel::setInitialMethod(INITIAL_METHOD_TYPE initial_method_type){ +void ColorCorrectionModel::setInitialMethod(INITIAL_METHOD_TYPE initial_method_type) +{ p->initial_method_type = initial_method_type; } -void ColorCorrectionModel::setMaxCount(int max_count_){ +void ColorCorrectionModel::setMaxCount(int max_count_) +{ p->max_count = max_count_; } -void ColorCorrectionModel::setEpsilon(double epsilon_){ +void ColorCorrectionModel::setEpsilon(double epsilon_) +{ p->epsilon = epsilon_; } -void ColorCorrectionModel::run(){ +void ColorCorrectionModel::run() +{ Mat saturate_mask = saturate(p->src, p->saturated_threshold[0], p->saturated_threshold[1]); p->linear = getLinear(p->gamma, p->deg, p->src, *(p->dst), saturate_mask, (p->cs), p->linear_type); @@ -378,18 +408,20 @@ void ColorCorrectionModel::run(){ p->initialLeastSquare(); break; default: - throw std::invalid_argument{ "Wrong initial_methoddistance_type!" }; + throw std::invalid_argument { "Wrong initial_methoddistance_type!" }; break; } break; } p->fitting(); } -Mat ColorCorrectionModel::getCCM() const{ +Mat ColorCorrectionModel::getCCM() const +{ return p->ccm; } -double ColorCorrectionModel::getLoss() const{ +double ColorCorrectionModel::getLoss() const +{ return p->loss; } -} // namespace ccm -} // namespace cv +} +} // namespace cv::ccm diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index a83591fa0a1..6bb387ea43e 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -27,23 +27,37 @@ #include "color.hpp" -namespace cv -{ -namespace ccm -{ -Color::Color():colors(Mat()), cs(*new ColorSpace()) {}; -Color::Color(Mat colors_, enum COLOR_SPACE cs_) :colors(colors_), cs(*GetCS::get_cs(cs_)) {}; +namespace cv { +namespace ccm { +Color::Color() + : colors(Mat()) + , cs(*new ColorSpace()) +{} +Color::Color(Mat colors_, enum COLOR_SPACE cs_) + : colors(colors_) + , cs(*GetCS::get_cs(cs_)) +{} -Color::Color(Mat colors_, const ColorSpace& cs_, Mat colored_) : colors(colors_), cs(cs_), colored(colored_) +Color::Color(Mat colors_, const ColorSpace& cs_, Mat colored_) + : colors(colors_) + , cs(cs_) + , colored(colored_) { grays = ~colored; } -Color::Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_) : colors(colors_), cs(*GetCS::get_cs(cs_)), colored(colored_) { +Color::Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_) + : colors(colors_) + , cs(*GetCS::get_cs(cs_)) + , colored(colored_) +{ grays = ~colored; } -Color::Color(Mat colors_, const ColorSpace& cs_) : colors(colors_), cs(cs_) {}; +Color::Color(Mat colors_, const ColorSpace& cs_) + : colors(colors_) + , cs(cs_) +{} -Color Color::to(const ColorSpace& other, CAM method , bool save) +Color Color::to(const ColorSpace& other, CAM method, bool save) { if (history.count(other) == 1) { @@ -63,7 +77,7 @@ Color Color::to(const ColorSpace& other, CAM method , bool save) } return *color; } -Color Color::to( COLOR_SPACE other, CAM method, bool save) +Color Color::to(COLOR_SPACE other, CAM method, bool save) { return to(*GetCS::get_cs(other), method, save); } @@ -83,7 +97,7 @@ Mat Color::toGray(IO io, CAM method, bool save) Mat Color::toLuminant(IO io, CAM method, bool save) { - Lab lab= *Lab::get(io); + Lab lab = *Lab::get(io); return channel(this->to(lab, method, save).colors, 0); } @@ -109,7 +123,7 @@ Mat Color::diff(Color& other, IO io, DISTANCE_TYPE method) case cv::ccm::RGBL: return distance(to(*cs.l).colors, other.to(*cs.l).colors, method); default: - throw std::invalid_argument{ "Wrong method!" }; + throw std::invalid_argument { "Wrong method!" }; break; } } @@ -122,7 +136,7 @@ void Color::getGray(double JDN) } Mat lab = to(Lab_D65_2).colors; Mat gray(colors.size(), colors.type()); - int fromto[] = { 0,0, -1,1, -1,2 }; + int fromto[] = { 0, 0, -1, 1, -1, 2 }; mixChannels(&lab, 1, &gray, 1, fromto, 3); Mat d = distance(lab, gray, CIE2000); this->grays = d < JDN; @@ -134,248 +148,246 @@ Color Color::operator[](Mat mask) return Color(maskCopyTo(colors, mask), cs); } - - - -Mat GetColor::get_ColorChecker(const double *checker,int row){ - Mat res(row,1, CV_64FC3); - for(int i = 0;i< row;++i) +Mat GetColor::get_ColorChecker(const double* checker, int row) +{ + Mat res(row, 1, CV_64FC3); + for (int i = 0; i < row; ++i) { - res.at(i,0)=Vec3d(checker[3*i],checker[3*i+1],checker[3*i+2]); - } + res.at(i, 0) = Vec3d(checker[3 * i], checker[3 * i + 1], checker[3 * i + 2]); + } return res; } -Mat GetColor::get_ColorChecker_MASK(const uchar *checker,int row){ - Mat res(row,1, CV_8U); - for(int i = 0;i< row;++i){ - res.at(i,0)=checker[i]; - } +Mat GetColor::get_ColorChecker_MASK(const uchar* checker, int row) +{ + Mat res(row, 1, CV_8U); + for (int i = 0; i < row; ++i) + { + res.at(i, 0) = checker[i]; + } return res; } -std::shared_ptr GetColor::get_color(CONST_COLOR const_color) { +std::shared_ptr GetColor::get_color(CONST_COLOR const_color) +{ /** @brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls see Miscellaneous.md for details. */ -static const double ColorChecker2005_LAB_D50_2 [24][3] = - { {37.986, 13.555, 14.059}, - {65.711, 18.13, 17.81}, - {49.927, -4.88, -21.925}, - {43.139, -13.095, 21.905}, - {55.112, 8.844, -25.399}, - {70.719, -33.397, -0.199}, - {62.661, 36.067, 57.096}, - {40.02, 10.41, -45.964}, - {51.124, 48.239, 16.248}, - {30.325, 22.976, -21.587}, - {72.532, -23.709, 57.255}, - {71.941, 19.363, 67.857}, - {28.778, 14.179, -50.297}, - {55.261, -38.342, 31.37}, - {42.101, 53.378, 28.19}, - {81.733, 4.039, 79.819}, - {51.935, 49.986, -14.574}, - {51.038, -28.631, -28.638}, - {96.539, -0.425, 1.186}, - {81.257, -0.638, -0.335}, - {66.766, -0.734, -0.504}, - {50.867, -0.153, -0.27}, - {35.656, -0.421, -1.231}, - {20.461, -0.079, -0.973}}; + static const double ColorChecker2005_LAB_D50_2[24][3] = { { 37.986, 13.555, 14.059 }, + { 65.711, 18.13, 17.81 }, + { 49.927, -4.88, -21.925 }, + { 43.139, -13.095, 21.905 }, + { 55.112, 8.844, -25.399 }, + { 70.719, -33.397, -0.199 }, + { 62.661, 36.067, 57.096 }, + { 40.02, 10.41, -45.964 }, + { 51.124, 48.239, 16.248 }, + { 30.325, 22.976, -21.587 }, + { 72.532, -23.709, 57.255 }, + { 71.941, 19.363, 67.857 }, + { 28.778, 14.179, -50.297 }, + { 55.261, -38.342, 31.37 }, + { 42.101, 53.378, 28.19 }, + { 81.733, 4.039, 79.819 }, + { 51.935, 49.986, -14.574 }, + { 51.038, -28.631, -28.638 }, + { 96.539, -0.425, 1.186 }, + { 81.257, -0.638, -0.335 }, + { 66.766, -0.734, -0.504 }, + { 50.867, -0.153, -0.27 }, + { 35.656, -0.421, -1.231 }, + { 20.461, -0.079, -0.973 } }; -static const uchar ColorChecker2005_COLORED_MASK[24] = - {1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0}; -static const double Vinyl_LAB_D50_2[18][3] = - { {100, 0.00520000001, -0.0104}, - {73.0833969, -0.819999993, -2.02099991}, - {62.493, 0.425999999, -2.23099995}, - {50.4640007, 0.446999997, -2.32399988}, - {37.7970009, 0.0359999985, -1.29700005}, - {0, 0, 0}, - {51.5880013, 73.5179977, 51.5690002}, - {93.6989975, -15.7340002, 91.9420013}, - {69.4079971, -46.5940018, 50.4869995}, - {66.61000060000001, -13.6789999, -43.1720009}, - {11.7110004, 16.9799995, -37.1759987}, - {51.973999, 81.9440002, -8.40699959}, - {40.5489998, 50.4399986, 24.8490009}, - {60.8160019, 26.0690002, 49.4420013}, - {52.2529984, -19.9500008, -23.9960003}, - {51.2859993, 48.4700012, -15.0579996}, - {68.70700069999999, 12.2959995, 16.2129993}, - {63.6839981, 10.2930002, 16.7639999}}; -static const uchar Vinyl_COLORED_MASK[18]= - { 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1}; -static const double DigitalSG_LAB_D50_2[140][3] = - { {96.55,-0.91,0.57}, - {6.43,-0.06,-0.41}, - {49.7,-0.18,0.03}, - {96.5,-0.89,0.59}, - {6.5,-0.06,-0.44}, - {49.66,-0.2,0.01}, - {96.52,-0.91,0.58}, - {6.49,-0.02,-0.28}, - {49.72,-0.2,0.04}, - {96.43,-0.91,0.67}, - {49.72,-0.19,0}, - {32.6,51.58,-10.85}, - {60.75,26.22,-18.6}, - {28.69,48.28,-39}, - {49.38,-15.43,-48.48}, - {60.63,-30.77,-26.23}, - {19.29,-26.37,-6.15}, - {60.15,-41.77,-12.6}, - {21.42,1.67,8.79}, - {49.69,-0.2,0.01}, - {6.5,-0.03,-0.67}, - {21.82,17.33,-18.35}, - {41.53,18.48,-37.26}, - {19.99,-0.16,-36.29}, - {60.16,-18.45,-31.42}, - {19.94,-17.92,-20.96}, - {60.68,-6.05,-32.81}, - {50.81,-49.8,-9.63}, - {60.65,-39.77,20.76}, - {6.53,-0.03,-0.43}, - {96.56,-0.91,0.59}, - {84.19,-1.95,-8.23}, - {84.75,14.55,0.23}, - {84.87,-19.07,-0.82}, - {85.15,13.48,6.82}, - {84.17,-10.45,26.78}, - {61.74,31.06,36.42}, - {64.37,20.82,18.92}, - {50.4,-53.22,14.62}, - {96.51,-0.89,0.65}, - {49.74,-0.19,0.03}, - {31.91,18.62,21.99}, - {60.74,38.66,70.97}, - {19.35,22.23,-58.86}, - {96.52,-0.91,0.62}, - {6.66,0,-0.3}, - {76.51,20.81,22.72}, - {72.79,29.15,24.18}, - {22.33,-20.7,5.75}, - {49.7,-0.19,0.01}, - {6.53,-0.05,-0.61}, - {63.42,20.19,19.22}, - {34.94,11.64,-50.7}, - {52.03,-44.15,39.04}, - {79.43,0.29,-0.17}, - {30.67,-0.14,-0.53}, - {63.6,14.44,26.07}, - {64.37,14.5,17.05}, - {60.01,-44.33,8.49}, - {6.63,-0.01,-0.47}, - {96.56,-0.93,0.59}, - {46.37,-5.09,-24.46}, - {47.08,52.97,20.49}, - {36.04,64.92,38.51}, - {65.05,0,-0.32}, - {40.14,-0.19,-0.38}, - {43.77,16.46,27.12}, - {64.39,17,16.59}, - {60.79,-29.74,41.5}, - {96.48,-0.89,0.64}, - {49.75,-0.21,0.01}, - {38.18,-16.99,30.87}, - {21.31,29.14,-27.51}, - {80.57,3.85,89.61}, - {49.71,-0.2,0.03}, - {60.27,0.08,-0.41}, - {67.34,14.45,16.9}, - {64.69,16.95,18.57}, - {51.12,-49.31,44.41}, - {49.7,-0.2,0.02}, - {6.67,-0.05,-0.64}, - {51.56,9.16,-26.88}, - {70.83,-24.26,64.77}, - {48.06,55.33,-15.61}, - {35.26,-0.09,-0.24}, - {75.16,0.25,-0.2}, - {44.54,26.27,38.93}, - {35.91,16.59,26.46}, - {61.49,-52.73,47.3}, - {6.59,-0.05,-0.5}, - {96.58,-0.9,0.61}, - {68.93,-34.58,-0.34}, - {69.65,20.09,78.57}, - {47.79,-33.18,-30.21}, - {15.94,-0.42,-1.2}, - {89.02,-0.36,-0.48}, - {63.43,25.44,26.25}, - {65.75,22.06,27.82}, - {61.47,17.1,50.72}, - {96.53,-0.89,0.66}, - {49.79,-0.2,0.03}, - {85.17,10.89,17.26}, - {89.74,-16.52,6.19}, - {84.55,5.07,-6.12}, - {84.02,-13.87,-8.72}, - {70.76,0.07,-0.35}, - {45.59,-0.05,0.23}, - {20.3,0.07,-0.32}, - {61.79,-13.41,55.42}, - {49.72,-0.19,0.02}, - {6.77,-0.05,-0.44}, - {21.85,34.37,7.83}, - {42.66,67.43,48.42}, - {60.33,36.56,3.56}, - {61.22,36.61,17.32}, - {62.07,52.8,77.14}, - {72.42,-9.82,89.66}, - {62.03,3.53,57.01}, - {71.95,-27.34,73.69}, - {6.59,-0.04,-0.45}, - {49.77,-0.19,0.04}, - {41.84,62.05,10.01}, - {19.78,29.16,-7.85}, - {39.56,65.98,33.71}, - {52.39,68.33,47.84}, - {81.23,24.12,87.51}, - {81.8,6.78,95.75}, - {71.72,-16.23,76.28}, - {20.31,14.45,16.74}, - {49.68,-0.19,0.05}, - {96.48,-0.88,0.68}, - {49.69,-0.18,0.03}, - {6.39,-0.04,-0.33}, - {96.54,-0.9,0.67}, - {49.72,-0.18,0.05}, - {6.49,-0.03,-0.41}, - {96.51,-0.9,0.69}, - {49.7,-0.19,0.07}, - {6.47,0,-0.38}, - {96.46,-0.89,0.7}}; + static const uchar ColorChecker2005_COLORED_MASK[24] = { 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0 }; + static const double Vinyl_LAB_D50_2[18][3] = { { 100, 0.00520000001, -0.0104 }, + { 73.0833969, -0.819999993, -2.02099991 }, + { 62.493, 0.425999999, -2.23099995 }, + { 50.4640007, 0.446999997, -2.32399988 }, + { 37.7970009, 0.0359999985, -1.29700005 }, + { 0, 0, 0 }, + { 51.5880013, 73.5179977, 51.5690002 }, + { 93.6989975, -15.7340002, 91.9420013 }, + { 69.4079971, -46.5940018, 50.4869995 }, + { 66.61000060000001, -13.6789999, -43.1720009 }, + { 11.7110004, 16.9799995, -37.1759987 }, + { 51.973999, 81.9440002, -8.40699959 }, + { 40.5489998, 50.4399986, 24.8490009 }, + { 60.8160019, 26.0690002, 49.4420013 }, + { 52.2529984, -19.9500008, -23.9960003 }, + { 51.2859993, 48.4700012, -15.0579996 }, + { 68.70700069999999, 12.2959995, 16.2129993 }, + { 63.6839981, 10.2930002, 16.7639999 } }; + static const uchar Vinyl_COLORED_MASK[18] = { 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1 }; + static const double DigitalSG_LAB_D50_2[140][3] = { { 96.55, -0.91, 0.57 }, + { 6.43, -0.06, -0.41 }, + { 49.7, -0.18, 0.03 }, + { 96.5, -0.89, 0.59 }, + { 6.5, -0.06, -0.44 }, + { 49.66, -0.2, 0.01 }, + { 96.52, -0.91, 0.58 }, + { 6.49, -0.02, -0.28 }, + { 49.72, -0.2, 0.04 }, + { 96.43, -0.91, 0.67 }, + { 49.72, -0.19, 0 }, + { 32.6, 51.58, -10.85 }, + { 60.75, 26.22, -18.6 }, + { 28.69, 48.28, -39 }, + { 49.38, -15.43, -48.48 }, + { 60.63, -30.77, -26.23 }, + { 19.29, -26.37, -6.15 }, + { 60.15, -41.77, -12.6 }, + { 21.42, 1.67, 8.79 }, + { 49.69, -0.2, 0.01 }, + { 6.5, -0.03, -0.67 }, + { 21.82, 17.33, -18.35 }, + { 41.53, 18.48, -37.26 }, + { 19.99, -0.16, -36.29 }, + { 60.16, -18.45, -31.42 }, + { 19.94, -17.92, -20.96 }, + { 60.68, -6.05, -32.81 }, + { 50.81, -49.8, -9.63 }, + { 60.65, -39.77, 20.76 }, + { 6.53, -0.03, -0.43 }, + { 96.56, -0.91, 0.59 }, + { 84.19, -1.95, -8.23 }, + { 84.75, 14.55, 0.23 }, + { 84.87, -19.07, -0.82 }, + { 85.15, 13.48, 6.82 }, + { 84.17, -10.45, 26.78 }, + { 61.74, 31.06, 36.42 }, + { 64.37, 20.82, 18.92 }, + { 50.4, -53.22, 14.62 }, + { 96.51, -0.89, 0.65 }, + { 49.74, -0.19, 0.03 }, + { 31.91, 18.62, 21.99 }, + { 60.74, 38.66, 70.97 }, + { 19.35, 22.23, -58.86 }, + { 96.52, -0.91, 0.62 }, + { 6.66, 0, -0.3 }, + { 76.51, 20.81, 22.72 }, + { 72.79, 29.15, 24.18 }, + { 22.33, -20.7, 5.75 }, + { 49.7, -0.19, 0.01 }, + { 6.53, -0.05, -0.61 }, + { 63.42, 20.19, 19.22 }, + { 34.94, 11.64, -50.7 }, + { 52.03, -44.15, 39.04 }, + { 79.43, 0.29, -0.17 }, + { 30.67, -0.14, -0.53 }, + { 63.6, 14.44, 26.07 }, + { 64.37, 14.5, 17.05 }, + { 60.01, -44.33, 8.49 }, + { 6.63, -0.01, -0.47 }, + { 96.56, -0.93, 0.59 }, + { 46.37, -5.09, -24.46 }, + { 47.08, 52.97, 20.49 }, + { 36.04, 64.92, 38.51 }, + { 65.05, 0, -0.32 }, + { 40.14, -0.19, -0.38 }, + { 43.77, 16.46, 27.12 }, + { 64.39, 17, 16.59 }, + { 60.79, -29.74, 41.5 }, + { 96.48, -0.89, 0.64 }, + { 49.75, -0.21, 0.01 }, + { 38.18, -16.99, 30.87 }, + { 21.31, 29.14, -27.51 }, + { 80.57, 3.85, 89.61 }, + { 49.71, -0.2, 0.03 }, + { 60.27, 0.08, -0.41 }, + { 67.34, 14.45, 16.9 }, + { 64.69, 16.95, 18.57 }, + { 51.12, -49.31, 44.41 }, + { 49.7, -0.2, 0.02 }, + { 6.67, -0.05, -0.64 }, + { 51.56, 9.16, -26.88 }, + { 70.83, -24.26, 64.77 }, + { 48.06, 55.33, -15.61 }, + { 35.26, -0.09, -0.24 }, + { 75.16, 0.25, -0.2 }, + { 44.54, 26.27, 38.93 }, + { 35.91, 16.59, 26.46 }, + { 61.49, -52.73, 47.3 }, + { 6.59, -0.05, -0.5 }, + { 96.58, -0.9, 0.61 }, + { 68.93, -34.58, -0.34 }, + { 69.65, 20.09, 78.57 }, + { 47.79, -33.18, -30.21 }, + { 15.94, -0.42, -1.2 }, + { 89.02, -0.36, -0.48 }, + { 63.43, 25.44, 26.25 }, + { 65.75, 22.06, 27.82 }, + { 61.47, 17.1, 50.72 }, + { 96.53, -0.89, 0.66 }, + { 49.79, -0.2, 0.03 }, + { 85.17, 10.89, 17.26 }, + { 89.74, -16.52, 6.19 }, + { 84.55, 5.07, -6.12 }, + { 84.02, -13.87, -8.72 }, + { 70.76, 0.07, -0.35 }, + { 45.59, -0.05, 0.23 }, + { 20.3, 0.07, -0.32 }, + { 61.79, -13.41, 55.42 }, + { 49.72, -0.19, 0.02 }, + { 6.77, -0.05, -0.44 }, + { 21.85, 34.37, 7.83 }, + { 42.66, 67.43, 48.42 }, + { 60.33, 36.56, 3.56 }, + { 61.22, 36.61, 17.32 }, + { 62.07, 52.8, 77.14 }, + { 72.42, -9.82, 89.66 }, + { 62.03, 3.53, 57.01 }, + { 71.95, -27.34, 73.69 }, + { 6.59, -0.04, -0.45 }, + { 49.77, -0.19, 0.04 }, + { 41.84, 62.05, 10.01 }, + { 19.78, 29.16, -7.85 }, + { 39.56, 65.98, 33.71 }, + { 52.39, 68.33, 47.84 }, + { 81.23, 24.12, 87.51 }, + { 81.8, 6.78, 95.75 }, + { 71.72, -16.23, 76.28 }, + { 20.31, 14.45, 16.74 }, + { 49.68, -0.19, 0.05 }, + { 96.48, -0.88, 0.68 }, + { 49.69, -0.18, 0.03 }, + { 6.39, -0.04, -0.33 }, + { 96.54, -0.9, 0.67 }, + { 49.72, -0.18, 0.05 }, + { 6.49, -0.03, -0.41 }, + { 96.51, -0.9, 0.69 }, + { 49.7, -0.19, 0.07 }, + { 6.47, 0, -0.38 }, + { 96.46, -0.89, 0.7 } }; switch (const_color) { case cv::ccm::Macbeth: { - Mat ColorChecker2005_LAB_D50_2_ = GetColor::get_ColorChecker(*ColorChecker2005_LAB_D50_2,24); - Mat ColorChecker2005_COLORED_MASK_ = GetColor::get_ColorChecker_MASK(ColorChecker2005_COLORED_MASK,24); + Mat ColorChecker2005_LAB_D50_2_ = GetColor::get_ColorChecker(*ColorChecker2005_LAB_D50_2, 24); + Mat ColorChecker2005_COLORED_MASK_ = GetColor::get_ColorChecker_MASK(ColorChecker2005_COLORED_MASK, 24); std::shared_ptr Macbeth_D50_2(new Color(ColorChecker2005_LAB_D50_2_, Lab_D50_2, ColorChecker2005_COLORED_MASK_)); return Macbeth_D50_2; break; } - case cv::ccm::Vinyl: { - Mat Vinyl_LAB_D50_2__=GetColor::get_ColorChecker(*Vinyl_LAB_D50_2,18); - Mat Vinyl_COLORED_MASK__= GetColor::get_ColorChecker_MASK(Vinyl_COLORED_MASK,18); + case cv::ccm::Vinyl: + { + Mat Vinyl_LAB_D50_2__ = GetColor::get_ColorChecker(*Vinyl_LAB_D50_2, 18); + Mat Vinyl_COLORED_MASK__ = GetColor::get_ColorChecker_MASK(Vinyl_COLORED_MASK, 18); std::shared_ptr Vinyl_D50_2(new Color(Vinyl_LAB_D50_2__, Lab_D50_2, Vinyl_COLORED_MASK__)); return Vinyl_D50_2; break; } - case cv::ccm::DigitalSG: { - Mat DigitalSG_LAB_D50_2__= GetColor::get_ColorChecker(*DigitalSG_LAB_D50_2,140); - std::shared_ptr DigitalSG_D50_2(new Color( DigitalSG_LAB_D50_2__, Lab_D50_2)); + case cv::ccm::DigitalSG: + { + Mat DigitalSG_LAB_D50_2__ = GetColor::get_ColorChecker(*DigitalSG_LAB_D50_2, 140); + std::shared_ptr DigitalSG_D50_2(new Color(DigitalSG_LAB_D50_2__, Lab_D50_2)); return DigitalSG_D50_2; break; } @@ -386,5 +398,5 @@ static const double DigitalSG_LAB_D50_2[140][3] = } } -} // namespace ccm -} // namespace cv \ No newline at end of file +} +} // namespace cv::ccm \ No newline at end of file diff --git a/modules/mcc/src/color.hpp b/modules/mcc/src/color.hpp index a1802be70cb..710bc5bfac4 100644 --- a/modules/mcc/src/color.hpp +++ b/modules/mcc/src/color.hpp @@ -32,11 +32,8 @@ #include "colorspace.hpp" #include "opencv2/mcc/ccm.hpp" - -namespace cv -{ -namespace ccm -{ +namespace cv { +namespace ccm { /** @brief Color defined by color_values and color space */ @@ -44,13 +41,12 @@ namespace ccm class Color { public: - /** @param grays mask of grayscale color @param colored mask of colored color @param history storage of historical conversion */ Mat colors; - const ColorSpace& cs ; + const ColorSpace& cs; Mat grays; Mat colored; std::map> history; @@ -106,21 +102,17 @@ class Color /** @brief Operator for mask copy. */ Color operator[](Mat mask); - }; - -class GetColor { +class GetColor +{ public: static std::shared_ptr get_color(CONST_COLOR const_color); - static Mat get_ColorChecker(const double *checker,int row); - static Mat get_ColorChecker_MASK(const uchar *checker,int row); + static Mat get_ColorChecker(const double* checker, int row); + static Mat get_ColorChecker_MASK(const uchar* checker, int row); }; - - -} // namespace ccm -} // namespace cv - +} +} // namespace cv::ccm #endif \ No newline at end of file diff --git a/modules/mcc/src/colorspace.cpp b/modules/mcc/src/colorspace.cpp index e41327198c5..1aba598d498 100644 --- a/modules/mcc/src/colorspace.cpp +++ b/modules/mcc/src/colorspace.cpp @@ -33,108 +33,120 @@ namespace cv { namespace ccm { static std::map> getilluminants() { - static std::map> illuminants = { - {IO::getIOs(A_2), { 1.098466069456375, 1, 0.3558228003436005 }}, - {IO::getIOs(A_10), { 1.111420406956693, 1, 0.3519978321919493 }}, - {IO::getIOs(D50_2), { 0.9642119944211994, 1, 0.8251882845188288 }}, - {IO::getIOs(D50_10), { 0.9672062750333777, 1, 0.8142801513128616 }}, - {IO::getIOs(D55_2), { 0.956797052643698, 1, 0.9214805860173273 }}, - {IO::getIOs(D55_10), { 0.9579665682254781, 1, 0.9092525159847462 }}, - {IO::getIOs(D65_2), { 0.95047, 1., 1.08883 }}, - {IO::getIOs(D65_10), { 0.94811, 1., 1.07304 }}, - {IO::getIOs(D75_2), { 0.9497220898840717, 1, 1.226393520724154 }}, - {IO::getIOs(D75_10), { 0.9441713925645873, 1, 1.2064272211720228 }}, - {IO::getIOs(E_2), { 1., 1., 1. }}, - {IO::getIOs(E_10), { 1., 1., 1. }}, + static std::map> illuminants = { + { IO::getIOs(A_2), { 1.098466069456375, 1, 0.3558228003436005 } }, + { IO::getIOs(A_10), { 1.111420406956693, 1, 0.3519978321919493 } }, + { IO::getIOs(D50_2), { 0.9642119944211994, 1, 0.8251882845188288 } }, + { IO::getIOs(D50_10), { 0.9672062750333777, 1, 0.8142801513128616 } }, + { IO::getIOs(D55_2), { 0.956797052643698, 1, 0.9214805860173273 } }, + { IO::getIOs(D55_10), { 0.9579665682254781, 1, 0.9092525159847462 } }, + { IO::getIOs(D65_2), { 0.95047, 1., 1.08883 } }, + { IO::getIOs(D65_10), { 0.94811, 1., 1.07304 } }, + { IO::getIOs(D75_2), { 0.9497220898840717, 1, 1.226393520724154 } }, + { IO::getIOs(D75_10), { 0.9441713925645873, 1, 1.2064272211720228 } }, + { IO::getIOs(E_2), { 1., 1., 1. } }, + { IO::getIOs(E_10), { 1., 1., 1. } }, + }; + return illuminants; }; - return illuminants; -}; -static std::map> illuminants =getilluminants(); +static std::map> illuminants = getilluminants(); /* *\ brief Basic class for ColorSpace. */ -bool ColorSpace::relate(const ColorSpace& other) const { - return (type == other.type) && (io == other.io); +bool ColorSpace::relate(const ColorSpace& other) const +{ + return (type == other.type) && (io == other.io); }; -Operations ColorSpace::relation(const ColorSpace& /*other*/) const { - return Operations::get_IDENTITY_OPS(); +Operations ColorSpace::relation(const ColorSpace& /*other*/) const +{ + return Operations::get_IDENTITY_OPS(); }; -bool ColorSpace::operator<(const ColorSpace& other) const { - return (io < other.io || (io == other.io && type < other.type) || - (io == other.io && type == other.type && linear < other.linear)); +bool ColorSpace::operator<(const ColorSpace& other) const +{ + return (io < other.io || (io == other.io && type < other.type) || (io == other.io && type == other.type && linear < other.linear)); } /* *\ brief Base of RGB color space; * the argument values are from AdobeRGB; * Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space */ -Operations RGBBase_::relation(const ColorSpace& other) const { - if (linear == other.linear) { - return Operations::get_IDENTITY_OPS(); - } - if (linear) { - return Operations({Operation(fromL)}); - } - return Operations({Operation(toL)}); +Operations RGBBase_::relation(const ColorSpace& other) const +{ + if (linear == other.linear) + { + return Operations::get_IDENTITY_OPS(); + } + if (linear) + { + return Operations({ Operation(fromL) }); + } + return Operations({ Operation(toL) }); }; /* *\ brief Initial operations. */ -void RGBBase_::init() { - setParameter(); - calLinear(); - calM(); - calOperations(); +void RGBBase_::init() +{ + setParameter(); + calLinear(); + calM(); + calOperations(); } /* *\ brief Produce color space instance with linear and non-linear versions. *\ param rgbl type of RGBBase_. */ -void RGBBase_::bind(RGBBase_& rgbl) { - init(); - rgbl.init(); - l = &rgbl; - rgbl.l = &rgbl; - nl = this; - rgbl.nl = this; +void RGBBase_::bind(RGBBase_& rgbl) +{ + init(); + rgbl.init(); + l = &rgbl; + rgbl.l = &rgbl; + nl = this; + rgbl.nl = this; } /* *\ brief Calculation of M_RGBL2XYZ_base. * see ColorSpace.pdf for details. */ -void RGBBase_::calM() { - Mat XYZr, XYZg, XYZb, XYZ_rgbl, Srgb; - XYZr = Mat(xyY2XYZ({xr, yr}), true); - XYZg = Mat(xyY2XYZ({xg, yg}), true); - XYZb = Mat(xyY2XYZ({xb, yb}), true); - merge(std::vector{XYZr, XYZg, XYZb}, XYZ_rgbl); - XYZ_rgbl = XYZ_rgbl.reshape(1, XYZ_rgbl.rows); - Mat XYZw = Mat(illuminants.find(io)->second, true); - solve(XYZ_rgbl, XYZw, Srgb); - merge(std::vector{Srgb.at(0) * XYZr, Srgb.at(1) * XYZg, - Srgb.at(2) * XYZb}, - M_to); - M_to = M_to.reshape(1, M_to.rows); - M_from = M_to.inv(); +void RGBBase_::calM() +{ + Mat XYZr, XYZg, XYZb, XYZ_rgbl, Srgb; + XYZr = Mat(xyY2XYZ({ xr, yr }), true); + XYZg = Mat(xyY2XYZ({ xg, yg }), true); + XYZb = Mat(xyY2XYZ({ xb, yb }), true); + merge(std::vector { XYZr, XYZg, XYZb }, XYZ_rgbl); + XYZ_rgbl = XYZ_rgbl.reshape(1, XYZ_rgbl.rows); + Mat XYZw = Mat(illuminants.find(io)->second, true); + solve(XYZ_rgbl, XYZw, Srgb); + merge(std::vector { Srgb.at(0) * XYZr, Srgb.at(1) * XYZg, + Srgb.at(2) * XYZb }, + M_to); + M_to = M_to.reshape(1, M_to.rows); + M_from = M_to.inv(); }; /* *\ brief operations to or from XYZ. */ -void RGBBase_::calOperations() { - // rgb -> rgbl - toL = [this](Mat rgb) -> Mat { return toLFunc(rgb); }; - - // rgbl -> rgb - fromL = [this](Mat rgbl) -> Mat { return fromLFunc(rgbl); }; - - if (linear) { - to = Operations({Operation(M_to.t())}); - from = Operations({Operation(M_from.t())}); - } else { - to = Operations({Operation(toL), Operation(M_to.t())}); - from = Operations({Operation(M_from.t()), Operation(fromL)}); - } +void RGBBase_::calOperations() +{ + // rgb -> rgbl + toL = [this](Mat rgb) -> Mat { return toLFunc(rgb); }; + + // rgbl -> rgb + fromL = [this](Mat rgbl) -> Mat { return fromLFunc(rgbl); }; + + if (linear) + { + to = Operations({ Operation(M_to.t()) }); + from = Operations({ Operation(M_from.t()) }); + } + else + { + to = Operations({ Operation(toL), Operation(M_to.t()) }); + from = Operations({ Operation(M_from.t()), Operation(fromL) }); + } } Mat RGBBase_::toLFunc(Mat& /*rgb*/) { return Mat(); } @@ -146,31 +158,38 @@ Mat RGBBase_::fromLFunc(Mat& /*rgbl*/) { return Mat(); } Mat AdobeRGBBase_::toLFunc(Mat& rgb) { return gammaCorrection(rgb, gamma); } -Mat AdobeRGBBase_::fromLFunc(Mat& rgbl) { - return gammaCorrection(rgbl, 1. / gamma); +Mat AdobeRGBBase_::fromLFunc(Mat& rgbl) +{ + return gammaCorrection(rgbl, 1. / gamma); } /* *\ brief Base of sRGB color space; */ -void sRGBBase_::calLinear() { - alpha = a + 1; - K0 = a / (gamma - 1); - phi = (pow(alpha, gamma) * pow(gamma - 1, gamma - 1)) / - (pow(a, gamma - 1) * pow(gamma, gamma)); - beta = K0 / phi; +void sRGBBase_::calLinear() +{ + alpha = a + 1; + K0 = a / (gamma - 1); + phi = (pow(alpha, gamma) * pow(gamma - 1, gamma - 1)) / (pow(a, gamma - 1) * pow(gamma, gamma)); + beta = K0 / phi; } /* *\ brief Used by toLFunc. */ -double sRGBBase_::toLFuncEW(double& x) { - if (x > K0) { - return pow(((x + alpha - 1) / alpha), gamma); - } else if (x >= -K0) { - return x / phi; - } else { - return -(pow(((-x + alpha - 1) / alpha), gamma)); - } +double sRGBBase_::toLFuncEW(double& x) +{ + if (x > K0) + { + return pow(((x + alpha - 1) / alpha), gamma); + } + else if (x >= -K0) + { + return x / phi; + } + else + { + return -(pow(((-x + alpha - 1) / alpha), gamma)); + } } /* *\ brief Linearization. @@ -178,21 +197,28 @@ double sRGBBase_::toLFuncEW(double& x) { *\ param rgb the input array, type of cv::Mat. *\ return the output array, type of cv::Mat. */ -Mat sRGBBase_::toLFunc(Mat& rgb) { - return elementWise(rgb, - [this](double a_) -> double { return toLFuncEW(a_); }); +Mat sRGBBase_::toLFunc(Mat& rgb) +{ + return elementWise(rgb, + [this](double a_) -> double { return toLFuncEW(a_); }); } /* *\ brief Used by fromLFunc. */ -double sRGBBase_::fromLFuncEW(double& x) { - if (x > beta) { - return alpha * pow(x, 1 / gamma) - (alpha - 1); - } else if (x >= -beta) { - return x * phi; - } else { - return -(alpha * pow(-x, 1 / gamma) - (alpha - 1)); - } +double sRGBBase_::fromLFuncEW(double& x) +{ + if (x > beta) + { + return alpha * pow(x, 1 / gamma) - (alpha - 1); + } + else if (x >= -beta) + { + return x * phi; + } + else + { + return -(alpha * pow(-x, 1 / gamma) - (alpha - 1)); + } } /* *\ brief Delinearization. @@ -200,154 +226,168 @@ double sRGBBase_::fromLFuncEW(double& x) { *\ param rgbl the input array, type of cv::Mat. *\ return the output array, type of cv::Mat. */ -Mat sRGBBase_::fromLFunc(Mat& rgbl) { - return elementWise(rgbl, - [this](double a_) -> double { return fromLFuncEW(a_); }); +Mat sRGBBase_::fromLFunc(Mat& rgbl) +{ + return elementWise(rgbl, + [this](double a_) -> double { return fromLFuncEW(a_); }); } /* *\ brief sRGB color space. * data from https://en.wikipedia.org/wiki/SRGB. */ -void sRGB_::setParameter() { - xr = 0.64; - yr = 0.33; - xg = 0.3; - yg = 0.6; - xb = 0.15; - yb = 0.06; - a = 0.055; - gamma = 2.4; +void sRGB_::setParameter() +{ + xr = 0.64; + yr = 0.33; + xg = 0.3; + yg = 0.6; + xb = 0.15; + yb = 0.06; + a = 0.055; + gamma = 2.4; } /* *\ brief Adobe RGB color space. */ -void AdobeRGB_::setParameter() { - xr = 0.64; - yr = 0.33; - xg = 0.21; - yg = 0.71; - xb = 0.15; - yb = 0.06; - gamma = 2.2; +void AdobeRGB_::setParameter() +{ + xr = 0.64; + yr = 0.33; + xg = 0.21; + yg = 0.71; + xb = 0.15; + yb = 0.06; + gamma = 2.2; } /* *\ brief Wide-gamut RGB color space. * data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. */ -void WideGamutRGB_::setParameter() { - xr = 0.7347; - yr = 0.2653; - xg = 0.1152; - yg = 0.8264; - xb = 0.1566; - yb = 0.0177; - gamma = 2.2; +void WideGamutRGB_::setParameter() +{ + xr = 0.7347; + yr = 0.2653; + xg = 0.1152; + yg = 0.8264; + xb = 0.1566; + yb = 0.0177; + gamma = 2.2; } /* *\ brief ProPhoto RGB color space. * data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. */ -void ProPhotoRGB_::setParameter() { - xr = 0.734699; - yr = 0.265301; - xg = 0.159597; - yg = 0.840403; - xb = 0.036598; - yb = 0.000105; - gamma = 1.8; +void ProPhotoRGB_::setParameter() +{ + xr = 0.734699; + yr = 0.265301; + xg = 0.159597; + yg = 0.840403; + xb = 0.036598; + yb = 0.000105; + gamma = 1.8; } /* *\ brief DCI-P3 RGB color space. * data from https://en.wikipedia.org/wiki/DCI-P3. */ -void DCI_P3_RGB_::setParameter() { - xr = 0.68; - yr = 0.32; - xg = 0.265; - yg = 0.69; - xb = 0.15; - yb = 0.06; - gamma = 2.2; +void DCI_P3_RGB_::setParameter() +{ + xr = 0.68; + yr = 0.32; + xg = 0.265; + yg = 0.69; + xb = 0.15; + yb = 0.06; + gamma = 2.2; } /* *\ brief Apple RGB color space. * data from * http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. */ -void AppleRGB_::setParameter() { - xr = 0.625; - yr = 0.34; - xg = 0.28; - yg = 0.595; - xb = 0.155; - yb = 0.07; - gamma = 1.8; +void AppleRGB_::setParameter() +{ + xr = 0.625; + yr = 0.34; + xg = 0.28; + yg = 0.595; + xb = 0.155; + yb = 0.07; + gamma = 1.8; } /* *\ brief REC_709 RGB color space. * data from https://en.wikipedia.org/wiki/Rec._709. */ -void REC_709_RGB_::setParameter() { - xr = 0.64; - yr = 0.33; - xg = 0.3; - yg = 0.6; - xb = 0.15; - yb = 0.06; - a = 0.099; - gamma = 1 / 0.45; +void REC_709_RGB_::setParameter() +{ + xr = 0.64; + yr = 0.33; + xg = 0.3; + yg = 0.6; + xb = 0.15; + yb = 0.06; + a = 0.099; + gamma = 1 / 0.45; } /* *\ brief REC_2020 RGB color space. * data from https://en.wikipedia.org/wiki/Rec._2020. */ -void REC_2020_RGB_::setParameter() { - xr = 0.708; - yr = 0.292; - xg = 0.17; - yg = 0.797; - xb = 0.131; - yb = 0.046; - a = 0.09929682680944; - gamma = 1 / 0.45; +void REC_2020_RGB_::setParameter() +{ + xr = 0.708; + yr = 0.292; + xg = 0.17; + yg = 0.797; + xb = 0.131; + yb = 0.046; + a = 0.09929682680944; + gamma = 1 / 0.45; } - /* *\ brief Enum of the possible types of CAMs. */ /* *\ brief XYZ color space. * Chromatic adaption matrices. */ -Operations XYZ::cam(IO dio, CAM method) { - return (io == dio) ? Operations() - : Operations({Operation(cam_(io, dio, method).t())}); +Operations XYZ::cam(IO dio, CAM method) +{ + return (io == dio) ? Operations() + : Operations({ Operation(cam_(io, dio, method).t()) }); } -Mat XYZ::cam_(IO sio, IO dio, CAM method) const { - if (sio == dio) { - return Mat::eye(cv::Size(3, 3), CV_64FC1); - } - if (cams.count(std::make_tuple(dio, sio, method)) == 1) { - return cams[std::make_tuple(dio, sio, method)]; - } - - // Function from http://www.brucelindbloom.com/index.html?ColorCheckerRGB.html. - Mat XYZws = Mat(illuminants.find(dio)->second); - Mat XYZWd = Mat(illuminants.find(sio)->second); - Mat MA = MAs.at(method)[0]; - Mat MA_inv = MAs.at(method)[1]; - Mat M = MA_inv * Mat::diag((MA * XYZws) / (MA * XYZWd)) * MA; - cams[std::make_tuple(dio, sio, method)] = M; - cams[std::make_tuple(sio, dio, method)] = M.inv(); - return M; +Mat XYZ::cam_(IO sio, IO dio, CAM method) const +{ + if (sio == dio) + { + return Mat::eye(cv::Size(3, 3), CV_64FC1); + } + if (cams.count(std::make_tuple(dio, sio, method)) == 1) + { + return cams[std::make_tuple(dio, sio, method)]; + } + + // Function from http://www.brucelindbloom.com/index.html?ColorCheckerRGB.html. + Mat XYZws = Mat(illuminants.find(dio)->second); + Mat XYZWd = Mat(illuminants.find(sio)->second); + Mat MA = MAs.at(method)[0]; + Mat MA_inv = MAs.at(method)[1]; + Mat M = MA_inv * Mat::diag((MA * XYZws) / (MA * XYZWd)) * MA; + cams[std::make_tuple(dio, sio, method)] = M; + cams[std::make_tuple(sio, dio, method)] = M.inv(); + return M; } -std::map > XYZ::xyz_cs = {}; +std::map> XYZ::xyz_cs = {}; -std::shared_ptr XYZ::get(IO io) { - if (xyz_cs.count(io) == 1) { +std::shared_ptr XYZ::get(IO io) +{ + if (xyz_cs.count(io) == 1) + { return xyz_cs[io]; } std::shared_ptr XYZ_CS(new XYZ(io)); @@ -357,52 +397,60 @@ std::shared_ptr XYZ::get(IO io) { /* *\ brief Lab color space. */ -Lab::Lab(IO io_) : ColorSpace(io_, "Lab", true) { - to = {Operation([this](Mat src) -> Mat { return tosrc(src); })}; - from = {Operation([this](Mat src) -> Mat { return fromsrc(src); })}; +Lab::Lab(IO io_) + : ColorSpace(io_, "Lab", true) +{ + to = { Operation([this](Mat src) -> Mat { return tosrc(src); }) }; + from = { Operation([this](Mat src) -> Mat { return fromsrc(src); }) }; } -Vec3d Lab::fromxyz(cv::Vec3d& xyz) { - double x = xyz[0] / illuminants.find(io)->second[0], - y = xyz[1] / illuminants.find(io)->second[1], - z = xyz[2] / illuminants.find(io)->second[2]; - auto f = [](double t) -> double { - return t > t0 ? std::cbrt(t) : (m * t + c); - }; - double fx = f(x), fy = f(y), fz = f(z); - return {116. * fy - 16., 500 * (fx - fy), 200 * (fy - fz)}; +Vec3d Lab::fromxyz(cv::Vec3d& xyz) +{ + double x = xyz[0] / illuminants.find(io)->second[0], + y = xyz[1] / illuminants.find(io)->second[1], + z = xyz[2] / illuminants.find(io)->second[2]; + auto f = [](double t) -> double { + return t > t0 ? std::cbrt(t) : (m * t + c); + }; + double fx = f(x), fy = f(y), fz = f(z); + return { 116. * fy - 16., 500 * (fx - fy), 200 * (fy - fz) }; } /* *\ brief Calculate From. *\ param src the input array, type of cv::Mat. *\ return the output array, type of cv::Mat */ -Mat Lab::fromsrc(Mat& src) { - return channelWise(src, - [this](cv::Vec3d a) -> cv::Vec3d { return fromxyz(a); }); +Mat Lab::fromsrc(Mat& src) +{ + return channelWise(src, + [this](cv::Vec3d a) -> cv::Vec3d { return fromxyz(a); }); } -Vec3d Lab::tolab(cv::Vec3d& lab) { - auto f_inv = [](double t) -> double { - return t > delta ? pow(t, 3.0) : (t - c) / m; - }; - double L = (lab[0] + 16.) / 116., a = lab[1] / 500., b = lab[2] / 200.; - return {illuminants.find(io)->second[0] * f_inv(L + a), - illuminants.find(io)->second[1] * f_inv(L), - illuminants.find(io)->second[2] * f_inv(L - b)}; +Vec3d Lab::tolab(cv::Vec3d& lab) +{ + auto f_inv = [](double t) -> double { + return t > delta ? pow(t, 3.0) : (t - c) / m; + }; + double L = (lab[0] + 16.) / 116., a = lab[1] / 500., b = lab[2] / 200.; + return { illuminants.find(io)->second[0] * f_inv(L + a), + illuminants.find(io)->second[1] * f_inv(L), + illuminants.find(io)->second[2] * f_inv(L - b) }; } /* *\ brief Calculate To. *\ param src the input array, type of cv::Mat. *\ return the output array, type of cv::Mat */ -Mat Lab::tosrc(Mat& src) { - return channelWise(src, - [this](cv::Vec3d a) -> cv::Vec3d { return tolab(a); }); +Mat Lab::tosrc(Mat& src) +{ + return channelWise(src, + [this](cv::Vec3d a) -> cv::Vec3d { return tolab(a); }); } -std::map > Lab::lab_cs = {}; -std::shared_ptr Lab::get(IO io) { - if (lab_cs.count(io) == 1) { +std::map> Lab::lab_cs = {}; +std::shared_ptr Lab::get(IO io) +{ + if (lab_cs.count(io) == 1) + { return lab_cs[io]; } std::shared_ptr Lab_CS(new Lab(io)); @@ -410,14 +458,16 @@ std::shared_ptr Lab::get(IO io) { return lab_cs[io]; } -std::map > GetCS::map_cs = {}; +std::map> GetCS::map_cs = {}; -std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) { +std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) +{ switch (cs_name) { case cv::ccm::sRGB: { - if (map_cs.count(cs_name) < 1) { + if (map_cs.count(cs_name) < 1) + { std::shared_ptr sRGB_CS(new sRGB_(false)); std::shared_ptr sRGBL_CS(new sRGB_(true)); (*sRGB_CS).bind(*sRGBL_CS); @@ -428,7 +478,8 @@ std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) { } case cv::ccm::AdobeRGB: { - if (map_cs.count(cs_name) < 1) { + if (map_cs.count(cs_name) < 1) + { std::shared_ptr AdobeRGB_CS(new AdobeRGB_(false)); std::shared_ptr AdobeRGBL_CS(new AdobeRGB_(true)); (*AdobeRGB_CS).bind(*AdobeRGBL_CS); @@ -439,7 +490,8 @@ std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) { } case cv::ccm::WideGamutRGB: { - if (map_cs.count(cs_name) < 1) { + if (map_cs.count(cs_name) < 1) + { std::shared_ptr WideGamutRGB_CS(new WideGamutRGB_(false)); std::shared_ptr WideGamutRGBL_CS(new WideGamutRGB_(true)); (*WideGamutRGB_CS).bind(*WideGamutRGBL_CS); @@ -450,7 +502,8 @@ std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) { } case cv::ccm::ProPhotoRGB: { - if (map_cs.count(cs_name) < 1) { + if (map_cs.count(cs_name) < 1) + { std::shared_ptr ProPhotoRGB_CS(new ProPhotoRGB_(false)); std::shared_ptr ProPhotoRGBL_CS(new ProPhotoRGB_(true)); (*ProPhotoRGB_CS).bind(*ProPhotoRGBL_CS); @@ -461,7 +514,8 @@ std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) { } case cv::ccm::DCI_P3_RGB: { - if (map_cs.count(cs_name) < 1) { + if (map_cs.count(cs_name) < 1) + { std::shared_ptr DCI_P3_RGB_CS(new DCI_P3_RGB_(false)); std::shared_ptr DCI_P3_RGBL_CS(new DCI_P3_RGB_(true)); (*DCI_P3_RGB_CS).bind(*DCI_P3_RGBL_CS); @@ -472,7 +526,8 @@ std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) { } case cv::ccm::AppleRGB: { - if (map_cs.count(cs_name) < 1) { + if (map_cs.count(cs_name) < 1) + { std::shared_ptr AppleRGB_CS(new AppleRGB_(false)); std::shared_ptr AppleRGBL_CS(new AppleRGB_(true)); (*AppleRGB_CS).bind(*AppleRGBL_CS); @@ -483,7 +538,8 @@ std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) { } case cv::ccm::REC_709_RGB: { - if (map_cs.count(cs_name) < 1) { + if (map_cs.count(cs_name) < 1) + { std::shared_ptr REC_709_RGB_CS(new REC_709_RGB_(false)); std::shared_ptr REC_709_RGBL_CS(new REC_709_RGB_(true)); (*REC_709_RGB_CS).bind(*REC_709_RGBL_CS); @@ -494,7 +550,8 @@ std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) { } case cv::ccm::REC_2020_RGB: { - if (map_cs.count(cs_name) < 1) { + if (map_cs.count(cs_name) < 1) + { std::shared_ptr REC_2020_RGB_CS(new REC_2020_RGB_(false)); std::shared_ptr REC_2020_RGBL_CS(new REC_2020_RGB_(true)); (*REC_2020_RGB_CS).bind(*REC_2020_RGBL_CS); @@ -520,13 +577,15 @@ std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) { return (std::dynamic_pointer_cast)(map_cs[cs_name]); } -std::shared_ptr GetCS::get_cs(enum COLOR_SPACE cs_name) { +std::shared_ptr GetCS::get_cs(enum COLOR_SPACE cs_name) +{ switch (cs_name) { case cv::ccm::sRGB: case cv::ccm::sRGBL: { - if (map_cs.count(cs_name) < 1) { + if (map_cs.count(cs_name) < 1) + { std::shared_ptr sRGB_CS(new sRGB_(false)); std::shared_ptr sRGBL_CS(new sRGB_(true)); (*sRGB_CS).bind(*sRGBL_CS); @@ -538,7 +597,8 @@ std::shared_ptr GetCS::get_cs(enum COLOR_SPACE cs_name) { case cv::ccm::AdobeRGB: case cv::ccm::AdobeRGBL: { - if (map_cs.count(cs_name) < 1) { + if (map_cs.count(cs_name) < 1) + { std::shared_ptr AdobeRGB_CS(new AdobeRGB_(false)); std::shared_ptr AdobeRGBL_CS(new AdobeRGB_(true)); (*AdobeRGB_CS).bind(*AdobeRGBL_CS); @@ -550,20 +610,21 @@ std::shared_ptr GetCS::get_cs(enum COLOR_SPACE cs_name) { case cv::ccm::WideGamutRGB: case cv::ccm::WideGamutRGBL: { - if (map_cs.count(cs_name) < 1) { + if (map_cs.count(cs_name) < 1) + { std::shared_ptr WideGamutRGB_CS(new WideGamutRGB_(false)); std::shared_ptr WideGamutRGBL_CS(new WideGamutRGB_(true)); (*WideGamutRGB_CS).bind(*WideGamutRGBL_CS); map_cs[WideGamutRGB] = WideGamutRGB_CS; map_cs[WideGamutRGBL] = WideGamutRGBL_CS; - } break; } case cv::ccm::ProPhotoRGB: case cv::ccm::ProPhotoRGBL: { - if (map_cs.count(cs_name) < 1) { + if (map_cs.count(cs_name) < 1) + { std::shared_ptr ProPhotoRGB_CS(new ProPhotoRGB_(false)); std::shared_ptr ProPhotoRGBL_CS(new ProPhotoRGB_(true)); (*ProPhotoRGB_CS).bind(*ProPhotoRGBL_CS); @@ -575,7 +636,8 @@ std::shared_ptr GetCS::get_cs(enum COLOR_SPACE cs_name) { case cv::ccm::DCI_P3_RGB: case cv::ccm::DCI_P3_RGBL: { - if (map_cs.count(cs_name) < 1) { + if (map_cs.count(cs_name) < 1) + { std::shared_ptr DCI_P3_RGB_CS(new DCI_P3_RGB_(false)); std::shared_ptr DCI_P3_RGBL_CS(new DCI_P3_RGB_(true)); (*DCI_P3_RGB_CS).bind(*DCI_P3_RGBL_CS); @@ -587,7 +649,8 @@ std::shared_ptr GetCS::get_cs(enum COLOR_SPACE cs_name) { case cv::ccm::AppleRGB: case cv::ccm::AppleRGBL: { - if (map_cs.count(cs_name) < 1) { + if (map_cs.count(cs_name) < 1) + { std::shared_ptr AppleRGB_CS(new AppleRGB_(false)); std::shared_ptr AppleRGBL_CS(new AppleRGB_(true)); (*AppleRGB_CS).bind(*AppleRGBL_CS); @@ -599,7 +662,8 @@ std::shared_ptr GetCS::get_cs(enum COLOR_SPACE cs_name) { case cv::ccm::REC_709_RGB: case cv::ccm::REC_709_RGBL: { - if (map_cs.count(cs_name) < 1) { + if (map_cs.count(cs_name) < 1) + { std::shared_ptr REC_709_RGB_CS(new REC_709_RGB_(false)); std::shared_ptr REC_709_RGBL_CS(new REC_709_RGB_(true)); (*REC_709_RGB_CS).bind(*REC_709_RGBL_CS); @@ -611,7 +675,8 @@ std::shared_ptr GetCS::get_cs(enum COLOR_SPACE cs_name) { case cv::ccm::REC_2020_RGB: case cv::ccm::REC_2020_RGBL: { - if (map_cs.count(cs_name) < 1) { + if (map_cs.count(cs_name) < 1) + { std::shared_ptr REC_2020_RGB_CS(new REC_2020_RGB_(false)); std::shared_ptr REC_2020_RGBL_CS(new REC_2020_RGB_(true)); (*REC_2020_RGB_CS).bind(*REC_2020_RGBL_CS); @@ -696,9 +761,8 @@ std::shared_ptr GetCS::get_cs(enum COLOR_SPACE cs_name) { break; } - return map_cs[cs_name]; } -} // namespace ccm -} // namespace cv +} +} // namespace cv::ccm diff --git a/modules/mcc/src/colorspace.hpp b/modules/mcc/src/colorspace.hpp index 0bc86e318d4..c4859d97bed 100644 --- a/modules/mcc/src/colorspace.hpp +++ b/modules/mcc/src/colorspace.hpp @@ -25,19 +25,15 @@ // Jinheng Zhang // Chenqi Shan - #ifndef __OPENCV_MCC_COLORSPACE_HPP__ #define __OPENCV_MCC_COLORSPACE_HPP__ - #include "operations.hpp" #include "io.hpp" #include "opencv2/mcc/ccm.hpp" -namespace cv -{ -namespace ccm -{ +namespace cv { +namespace ccm { /** @brief Basic class for ColorSpace. */ @@ -55,7 +51,10 @@ class ColorSpace ColorSpace() {}; - ColorSpace(IO io_, std::string type_, bool linear_) :io(io_), type(type_), linear(linear_) {}; + ColorSpace(IO io_, std::string type_, bool linear_) + : io(io_) + , type(type_) + , linear(linear_) {}; virtual ~ColorSpace() { @@ -66,8 +65,7 @@ class ColorSpace virtual Operations relation(const ColorSpace& /*other*/) const; - bool operator<(const ColorSpace& other)const; - + bool operator<(const ColorSpace& other) const; }; /** @brief Base of RGB color space; @@ -127,8 +125,6 @@ class RGBBase_ : public ColorSpace virtual Mat toLFunc(Mat& /*rgb*/); virtual Mat fromLFunc(Mat& /*rgbl*/); - - }; /** @brief Base of Adobe RGB color space; @@ -185,17 +181,17 @@ class sRGBBase_ : public RGBBase_ @return the output array, type of cv::Mat. */ Mat fromLFunc(Mat& rgbl) CV_OVERRIDE; - }; /** @brief sRGB color space. data from https://en.wikipedia.org/wiki/SRGB. */ -class sRGB_ :public sRGBBase_ +class sRGB_ : public sRGBBase_ { public: - sRGB_(bool linear_) :sRGBBase_(IO::getIOs(D65_2), "sRGB", linear_) {}; + sRGB_(bool linear_) + : sRGBBase_(IO::getIOs(D65_2), "sRGB", linear_) {}; private: void setParameter() CV_OVERRIDE; @@ -206,11 +202,11 @@ class sRGB_ :public sRGBBase_ class AdobeRGB_ : public AdobeRGBBase_ { public: - AdobeRGB_(bool linear_ = false) :AdobeRGBBase_(IO::getIOs(D65_2), "AdobeRGB", linear_) {}; + AdobeRGB_(bool linear_ = false) + : AdobeRGBBase_(IO::getIOs(D65_2), "AdobeRGB", linear_) {}; private: void setParameter() CV_OVERRIDE; - }; /** @brief Wide-gamut RGB color space. @@ -219,7 +215,8 @@ class AdobeRGB_ : public AdobeRGBBase_ class WideGamutRGB_ : public AdobeRGBBase_ { public: - WideGamutRGB_(bool linear_ = false) :AdobeRGBBase_(IO::getIOs(D50_2), "WideGamutRGB", linear_) {}; + WideGamutRGB_(bool linear_ = false) + : AdobeRGBBase_(IO::getIOs(D50_2), "WideGamutRGB", linear_) {}; private: void setParameter() CV_OVERRIDE; @@ -232,7 +229,8 @@ class WideGamutRGB_ : public AdobeRGBBase_ class ProPhotoRGB_ : public AdobeRGBBase_ { public: - ProPhotoRGB_(bool linear_ = false) :AdobeRGBBase_(IO::getIOs(D50_2), "ProPhotoRGB", linear_) {}; + ProPhotoRGB_(bool linear_ = false) + : AdobeRGBBase_(IO::getIOs(D50_2), "ProPhotoRGB", linear_) {}; private: void setParameter() CV_OVERRIDE; @@ -244,7 +242,8 @@ class ProPhotoRGB_ : public AdobeRGBBase_ class DCI_P3_RGB_ : public AdobeRGBBase_ { public: - DCI_P3_RGB_(bool linear_ = false) :AdobeRGBBase_(IO::getIOs(D65_2), "DCI_P3_RGB", linear_) {}; + DCI_P3_RGB_(bool linear_ = false) + : AdobeRGBBase_(IO::getIOs(D65_2), "DCI_P3_RGB", linear_) {}; private: void setParameter() CV_OVERRIDE; @@ -256,7 +255,8 @@ class DCI_P3_RGB_ : public AdobeRGBBase_ class AppleRGB_ : public AdobeRGBBase_ { public: - AppleRGB_(bool linear_ = false) :AdobeRGBBase_(IO::getIOs(D65_2), "AppleRGB", linear_) {}; + AppleRGB_(bool linear_ = false) + : AdobeRGBBase_(IO::getIOs(D65_2), "AppleRGB", linear_) {}; private: void setParameter() CV_OVERRIDE; @@ -268,7 +268,8 @@ class AppleRGB_ : public AdobeRGBBase_ class REC_709_RGB_ : public sRGBBase_ { public: - REC_709_RGB_(bool linear_) :sRGBBase_(IO::getIOs(D65_2), "REC_709_RGB", linear_) {}; + REC_709_RGB_(bool linear_) + : sRGBBase_(IO::getIOs(D65_2), "REC_709_RGB", linear_) {}; private: void setParameter() CV_OVERRIDE; @@ -280,13 +281,13 @@ class REC_709_RGB_ : public sRGBBase_ class REC_2020_RGB_ : public sRGBBase_ { public: - REC_2020_RGB_(bool linear_) :sRGBBase_(IO::getIOs(D65_2), "REC_2020_RGB", linear_) {}; + REC_2020_RGB_(bool linear_) + : sRGBBase_(IO::getIOs(D65_2), "REC_2020_RGB", linear_) {}; private: void setParameter() CV_OVERRIDE; }; - /** @brief Enum of the possible types of CAMs. */ enum CAM @@ -296,24 +297,25 @@ enum CAM BRADFORD }; -static std::map , Mat > cams; +static std::map, Mat> cams; static const Mat Von_Kries = (Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); static const Mat Bradford = (Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); -static const std::map > MAs = { - {IDENTITY , { Mat::eye(Size(3,3),CV_64FC1) , Mat::eye(Size(3,3),CV_64FC1)} }, - {VON_KRIES, { Von_Kries ,Von_Kries.inv() }}, - {BRADFORD, { Bradford ,Bradford.inv() }} +static const std::map> MAs = { + { IDENTITY, { Mat::eye(Size(3, 3), CV_64FC1), Mat::eye(Size(3, 3), CV_64FC1) } }, + { VON_KRIES, { Von_Kries, Von_Kries.inv() } }, + { BRADFORD, { Bradford, Bradford.inv() } } }; /** @brief XYZ color space. Chromatic adaption matrices. */ -class XYZ :public ColorSpace +class XYZ : public ColorSpace { public: - XYZ(IO io_) : ColorSpace(io_, "XYZ", true) {}; + XYZ(IO io_) + : ColorSpace(io_, "XYZ", true) {}; Operations cam(IO dio, CAM method = BRADFORD); - static std::map > xyz_cs; + static std::map> xyz_cs; static std::shared_ptr get(IO io); private: @@ -333,12 +335,12 @@ const XYZ XYZ_D50_2_CS(IO::getIOs(D50_2)); /** @brief Lab color space. */ -class Lab :public ColorSpace +class Lab : public ColorSpace { public: - static std::map > lab_cs; + static std::map> lab_cs; Lab(IO io); - static std::shared_ptr get(IO io); + static std::shared_ptr get(IO io); private: static constexpr double delta = (6. / 29.); @@ -348,7 +350,6 @@ class Lab :public ColorSpace Vec3d fromxyz(Vec3d& xyz); - /** @brief Calculate From. @param src the input array, type of cv::Mat. @return the output array, type of cv::Mat @@ -369,16 +370,15 @@ class Lab :public ColorSpace const Lab Lab_D65_2_CS(IO::getIOs(D65_2)); const Lab Lab_D50_2_CS(IO::getIOs(D50_2)); - -class GetCS { +class GetCS +{ public: - static std::map > map_cs; + static std::map> map_cs; static std::shared_ptr get_rgb(enum COLOR_SPACE cs_name); static std::shared_ptr get_cs(enum COLOR_SPACE cs_name); }; - -} // namespace ccm -} // namespace cv +} +} // namespace cv::ccm #endif \ No newline at end of file diff --git a/modules/mcc/src/distance.cpp b/modules/mcc/src/distance.cpp index cebd00210b3..cd6738259b5 100644 --- a/modules/mcc/src/distance.cpp +++ b/modules/mcc/src/distance.cpp @@ -25,18 +25,15 @@ // Jinheng Zhang // Chenqi Shan - #include "distance.hpp" -namespace cv -{ -namespace ccm -{ +namespace cv { +namespace ccm { double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2) { return norm(lab1 - lab2); }; double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH, - double kC, double kL, double k1, double k2) + double kC, double kL, double k1, double k2) { double dl = lab1[0] - lab2[0]; double c1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); @@ -48,8 +45,7 @@ double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH, double sc = 1.0 + k1 * c1; double sh = 1.0 + k2 * c1; double sl = 1.0; - double res = - pow(dl / (kL * sl), 2) + pow(dc / (kC * sc), 2) + dh / pow(kH * sh, 2); + double res = pow(dl / (kL * sl), 2) + pow(dc / (kC * sc), 2) + dh / pow(kH * sh, 2); return res > 0 ? sqrt(res) : 0; } @@ -67,7 +63,7 @@ double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2) } double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL, - double kC, double kH) + double kC, double kH) { double delta_L_apo = lab2[0] - lab1[0]; double l_bar_apo = (lab1[0] + lab2[0]) / 2.0; @@ -90,7 +86,8 @@ double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL, else { h1_apo = atan2(lab1[2], a1_apo); - if (h1_apo < 0.0) h1_apo += 2. * CV_PI; + if (h1_apo < 0.0) + h1_apo += 2. * CV_PI; } double h2_apo; @@ -101,7 +98,8 @@ double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL, else { h2_apo = atan2(lab2[2], a2_apo); - if (h2_apo < 0.0) h2_apo += 2. * CV_PI; + if (h2_apo < 0.0) + h2_apo += 2. * CV_PI; } double delta_h_apo; @@ -137,21 +135,12 @@ double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL, } double delta_H_apo = 2.0 * sqrt(C1_apo * C2_apo) * sin(delta_h_apo / 2.0); - double T = 1.0 - 0.17 * cos(H_bar_apo - toRad(30.)) + - 0.24 * cos(2.0 * H_bar_apo) + - 0.32 * cos(3.0 * H_bar_apo + toRad(6.0)) - - 0.2 * cos(4.0 * H_bar_apo - toRad(63.0)); + double T = 1.0 - 0.17 * cos(H_bar_apo - toRad(30.)) + 0.24 * cos(2.0 * H_bar_apo) + 0.32 * cos(3.0 * H_bar_apo + toRad(6.0)) - 0.2 * cos(4.0 * H_bar_apo - toRad(63.0)); double sC = 1.0 + 0.045 * C_bar_apo; double sH = 1.0 + 0.015 * C_bar_apo * T; - double sL = 1.0 + ((0.015 * pow(l_bar_apo - 50.0, 2.0)) / - sqrt(20.0 + pow(l_bar_apo - 50.0, 2.0))); - double RT = -2.0 * G * - sin(toRad(60.0) * - exp(-pow((H_bar_apo - toRad(275.0)) / toRad(25.0), 2.0))); - double res = - (pow(delta_L_apo / (kL * sL), 2.0) + pow(delta_C_apo / (kC * sC), 2.0) + - pow(delta_H_apo / (kH * sH), 2.0) + - RT * (delta_C_apo / (kC * sC)) * (delta_H_apo / (kH * sH))); + double sL = 1.0 + ((0.015 * pow(l_bar_apo - 50.0, 2.0)) / sqrt(20.0 + pow(l_bar_apo - 50.0, 2.0))); + double RT = -2.0 * G * sin(toRad(60.0) * exp(-pow((H_bar_apo - toRad(275.0)) / toRad(25.0), 2.0))); + double res = (pow(delta_L_apo / (kL * sL), 2.0) + pow(delta_C_apo / (kC * sC), 2.0) + pow(delta_H_apo / (kH * sH), 2.0) + RT * (delta_C_apo / (kC * sC)) * (delta_H_apo / (kH * sH))); return res > 0 ? sqrt(res) : 0; } @@ -178,20 +167,19 @@ double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL, double kC) else { H1 = atan2(lab1[2], lab1[1]); - if (H1 < 0.0) H1 += 2. * CV_PI; + if (H1 < 0.0) + H1 += 2. * CV_PI; } double F = pow(C1, 2) / sqrt(pow(C1, 4) + 1900); double T = (H1 > toRad(164) && H1 <= toRad(345)) - ? 0.56 + abs(0.2 * cos(H1 + toRad(168))) - : 0.36 + abs(0.4 * cos(H1 + toRad(35))); - double sL = - lab1[0] < 16. ? 0.511 : (0.040975 * lab1[0]) / (1.0 + 0.01765 * lab1[0]); + ? 0.56 + abs(0.2 * cos(H1 + toRad(168))) + : 0.36 + abs(0.4 * cos(H1 + toRad(35))); + double sL = lab1[0] < 16. ? 0.511 : (0.040975 * lab1[0]) / (1.0 + 0.01765 * lab1[0]); double sC = (0.0638 * C1) / (1.0 + 0.0131 * C1) + 0.638; double sH = sC * (F * T + 1.0 - F); - return sqrt(pow(dL / (kL * sL), 2.0) + pow(dC / (kC * sC), 2.0) + - pow(dH / sH, 2.0)); + return sqrt(pow(dL / (kL * sL), 2.0) + pow(dC / (kC * sC), 2.0) + pow(dH / sH, 2.0)); } double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2) @@ -225,10 +213,10 @@ Mat distance(Mat src, Mat ref, DISTANCE_TYPE distance_type) case cv::ccm::RGBL: return distanceWise(src, ref, deltaCIE76); default: - throw std::invalid_argument{ "Wrong distance_type!" }; + throw std::invalid_argument { "Wrong distance_type!" }; break; } }; -} // namespace ccm -} // namespace cv \ No newline at end of file +} +} // namespace cv::ccm \ No newline at end of file diff --git a/modules/mcc/src/distance.hpp b/modules/mcc/src/distance.hpp index 27243929833..4fc63b115ff 100644 --- a/modules/mcc/src/distance.hpp +++ b/modules/mcc/src/distance.hpp @@ -31,14 +31,11 @@ #include "utils.hpp" #include "opencv2/mcc/ccm.hpp" -namespace cv -{ -namespace ccm -{ +namespace cv { +namespace ccm { /** possibale functions to calculate the distance between colors.see https://en.wikipedia.org/wiki/Color_difference for details;*/ - /** @brief distance between two points in formula CIE76 @param lab1 a 3D vector @param lab2 a 3D vector @@ -59,8 +56,8 @@ double deltaCIE76(Vec3d lab1, Vec3d lab2); */ double deltaCIE94(Vec3d lab1, Vec3d lab2, double kH = 1.0, - double kC = 1.0, double kL = 1.0, double k1 = 0.045, - double k2 = 0.015); + double kC = 1.0, double kL = 1.0, double k1 = 0.045, + double k2 = 0.015); double deltaCIE94GraphicArts(Vec3d lab1, Vec3d lab2); @@ -68,7 +65,6 @@ double toRad(double degree); double deltaCIE94Textiles(Vec3d lab1, Vec3d lab2); - /** @brief distance between two points in formula CIE2000 @param lab1 a 3D vector @param lab2 a 3D vector @@ -78,10 +74,9 @@ double deltaCIE94Textiles(Vec3d lab1, Vec3d lab2); @return distance between lab1 and lab2 */ double deltaCIEDE2000_(Vec3d lab1, Vec3d lab2, double kL = 1.0, - double kC = 1.0, double kH = 1.0); + double kC = 1.0, double kH = 1.0); double deltaCIEDE2000(Vec3d lab1, Vec3d lab2); - /** @brief distance between two points in formula CMC @param lab1 a 3D vector @param lab2 a 3D vector @@ -98,8 +93,7 @@ double deltaCMC2To1(Vec3d lab1, Vec3d lab2); Mat distance(Mat src, Mat ref, DISTANCE_TYPE distance_type); -} // namespace ccm -} // namespace cv - +} +} // namespace cv::ccm #endif \ No newline at end of file diff --git a/modules/mcc/src/io.cpp b/modules/mcc/src/io.cpp index 8643b058c1c..c9c5c2026aa 100644 --- a/modules/mcc/src/io.cpp +++ b/modules/mcc/src/io.cpp @@ -26,11 +26,11 @@ // Chenqi Shan #include "io.hpp" -namespace cv -{ -namespace ccm -{ -IO::IO(std::string illuminant_, std::string observer_) :illuminant(illuminant_), observer(observer_) {}; +namespace cv { +namespace ccm { +IO::IO(std::string illuminant_, std::string observer_) + : illuminant(illuminant_) + , observer(observer_) {}; bool IO::operator<(const IO& other) const { @@ -42,7 +42,8 @@ bool IO::operator==(const IO& other) const return illuminant == other.illuminant && observer == other.observer; }; -IO IO::getIOs(IO_TYPE io) { +IO IO::getIOs(IO_TYPE io) +{ switch (io) { case cv::ccm::A_2: @@ -128,5 +129,5 @@ std::vector xyY2XYZ(const std::vector& xyY) return { Y * xyY[0] / xyY[1], Y, Y / xyY[1] * (1 - xyY[0] - xyY[1]) }; } -} // namespace ccm -} // namespace cv +} +} // namespace cv::ccm diff --git a/modules/mcc/src/io.hpp b/modules/mcc/src/io.hpp index 65e7d23680f..c79864e3c41 100644 --- a/modules/mcc/src/io.hpp +++ b/modules/mcc/src/io.hpp @@ -25,33 +25,30 @@ // Jinheng Zhang // Chenqi Shan - #ifndef __OPENCV_MCC_IO_HPP__ #define __OPENCV_MCC_IO_HPP__ - #include #include -namespace cv -{ -namespace ccm -{ +namespace cv { +namespace ccm { -enum IO_TYPE { - A_2, - A_10, - D50_2, - D50_10, - D55_2, - D55_10, - D65_2, - D65_10, - D75_2, - D75_10, - E_2, - E_10 - }; +enum IO_TYPE +{ + A_2, + A_10, + D50_2, + D50_10, + D55_2, + D55_10, + D65_2, + D65_10, + D75_2, + D75_10, + E_2, + E_10 +}; /** @brief Io is the meaning of illuminant and observer. See notes of ccm.hpp for supported list for illuminant and observer*/ @@ -60,19 +57,16 @@ class IO public: std::string illuminant; std::string observer; - IO(){}; - IO(std::string illuminant, std::string observer) ; - virtual ~IO(){}; + IO() {}; + IO(std::string illuminant, std::string observer); + virtual ~IO() {}; bool operator<(const IO& other) const; bool operator==(const IO& other) const; static IO getIOs(IO_TYPE io); - }; std::vector xyY2XYZ(const std::vector& xyY); - -} // namespace ccm -} // namespace cv - +} +} // namespace cv::ccm #endif \ No newline at end of file diff --git a/modules/mcc/src/linearize.cpp b/modules/mcc/src/linearize.cpp index 9002aac3d89..02f221ef394 100644 --- a/modules/mcc/src/linearize.cpp +++ b/modules/mcc/src/linearize.cpp @@ -27,12 +27,11 @@ #include "linearize.hpp" -namespace cv -{ -namespace ccm -{ +namespace cv { +namespace ccm { -Polyfit::Polyfit(Mat x, Mat y, int deg_) :deg(deg_) +Polyfit::Polyfit(Mat x, Mat y, int deg_) + : deg(deg_) { int n = x.cols * x.rows * x.channels(); x = x.reshape(1, n); @@ -51,7 +50,7 @@ Polyfit::Polyfit(Mat x, Mat y, int deg_) :deg(deg_) Mat Polyfit::operator()(const Mat& inp) { - return elementWise(inp, [this](double x)->double {return fromEW(x); }); + return elementWise(inp, [this](double x) -> double { return fromEW(x); }); }; double Polyfit::fromEW(double x) @@ -64,7 +63,8 @@ double Polyfit::fromEW(double x) return res; }; -LogPolyfit::LogPolyfit(Mat x, Mat y, int deg_) :deg(deg_) +LogPolyfit::LogPolyfit(Mat x, Mat y, int deg_) + : deg(deg_) { Mat mask_ = (x > 0) & (y > 0); Mat src_, dst_, s_, d_; @@ -96,7 +96,7 @@ Mat LinearGamma::linearize(Mat inp) return gammaCorrection(inp, gamma); }; -std::shared_ptr getLinear(double gamma, int deg, Mat src, Color dst, Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type) +std::shared_ptr getLinear(double gamma, int deg, Mat src, Color dst, Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type) { std::shared_ptr p = std::make_shared(); switch (linear_type) @@ -120,11 +120,11 @@ std::shared_ptr getLinear(double gamma, int deg, Mat src, Color dst, Ma p.reset(new LinearGray(deg, src, dst, mask, cs)); break; default: - throw std::invalid_argument{ "Wrong linear_type!" }; + throw std::invalid_argument { "Wrong linear_type!" }; break; } return p; }; -} // namespace ccm -} // namespace cv \ No newline at end of file +} +} // namespace cv::ccm \ No newline at end of file diff --git a/modules/mcc/src/linearize.hpp b/modules/mcc/src/linearize.hpp index 26472b030f4..e762ee4b702 100644 --- a/modules/mcc/src/linearize.hpp +++ b/modules/mcc/src/linearize.hpp @@ -25,7 +25,6 @@ // Jinheng Zhang // Chenqi Shan - #ifndef __OPENCV_MCC_LINEARIZE_HPP__ #define __OPENCV_MCC_LINEARIZE_HPP__ @@ -33,10 +32,8 @@ #include #include "color.hpp" #include "opencv2/mcc/ccm.hpp" -namespace cv -{ -namespace ccm -{ +namespace cv { +namespace ccm { /** @brief Polyfit model. */ @@ -59,7 +56,6 @@ class Polyfit private: double fromEW(double x); - }; /** @brief Logpolyfit model. @@ -78,7 +74,6 @@ class LogPolyfit LogPolyfit(Mat x, Mat y, int deg); virtual ~LogPolyfit() {}; Mat operator()(const Mat& inp); - }; /** @brief Linearization base. @@ -99,11 +94,11 @@ class Linear virtual void value(void) {}; }; - /** @brief Linearization identity. make no change. */ -class LinearIdentity : public Linear {}; +class LinearIdentity : public Linear +{}; /** @brief Linearization gamma correction. */ @@ -112,7 +107,8 @@ class LinearGamma : public Linear public: double gamma; - LinearGamma(double gamma_) :gamma(gamma_) {}; + LinearGamma(double gamma_) + : gamma(gamma_) {}; Mat linearize(Mat inp) CV_OVERRIDE; }; @@ -121,12 +117,13 @@ class LinearGamma : public Linear Grayscale polynomial fitting. */ template -class LinearGray :public Linear +class LinearGray : public Linear { public: int deg; T p; - LinearGray(int deg_, Mat src, Color dst, Mat mask, RGBBase_ cs) :deg(deg_) + LinearGray(int deg_, Mat src, Color dst, Mat mask, RGBBase_ cs) + : deg(deg_) { dst.getGray(); Mat lear_gray_mask = mask & dst.grays; @@ -156,7 +153,7 @@ class LinearGray :public Linear Fitting channels respectively. */ template -class LinearColor :public Linear +class LinearColor : public Linear { public: int deg; @@ -164,7 +161,8 @@ class LinearColor :public Linear T pg; T pb; - LinearColor(int deg_, Mat src_, Color dst, Mat mask, RGBBase_ cs) :deg(deg_) + LinearColor(int deg_, Mat src_, Color dst, Mat mask, RGBBase_ cs) + : deg(deg_) { Mat src = maskCopyTo(src_, mask); Mat dst_ = maskCopyTo(dst.to(*cs.l).colors, mask); @@ -188,7 +186,7 @@ class LinearColor :public Linear split(inp, channels); std::vector channel; Mat res; - merge(std::vector{ pr(channels[0]), pg(channels[1]), pb(channels[2]) }, res); + merge(std::vector { pr(channels[0]), pg(channels[1]), pb(channels[2]) }, res); return res; }; }; @@ -206,9 +204,7 @@ class LinearColor :public Linear std::shared_ptr getLinear(double gamma, int deg, Mat src, Color dst, Mat mask, RGBBase_ cs, LINEAR_TYPE linear_type); - -} // namespace ccm -} // namespace cv - +} +} // namespace cv::ccm #endif diff --git a/modules/mcc/src/operations.cpp b/modules/mcc/src/operations.cpp index ccca1b67ee4..e4e76a2a270 100644 --- a/modules/mcc/src/operations.cpp +++ b/modules/mcc/src/operations.cpp @@ -27,10 +27,8 @@ #include "operations.hpp" #include "utils.hpp" -namespace cv -{ -namespace ccm -{ +namespace cv { +namespace ccm { Mat Operation::operator()(Mat& abc) { @@ -88,5 +86,5 @@ Mat Operations::run(Mat abc) return abc; }; -} // namespace ccm -} // namespace cv \ No newline at end of file +} +} // namespace cv::ccm \ No newline at end of file diff --git a/modules/mcc/src/operations.hpp b/modules/mcc/src/operations.hpp index 2738c073f30..db7bd7441de 100644 --- a/modules/mcc/src/operations.hpp +++ b/modules/mcc/src/operations.hpp @@ -25,16 +25,13 @@ // Jinheng Zhang // Chenqi Shan - #ifndef __OPENCV_MCC_OPERATIONS_HPP__ #define __OPENCV_MCC_OPERATIONS_HPP__ #include "utils.hpp" -namespace cv -{ -namespace ccm -{ +namespace cv { +namespace ccm { /** @brief Operation class contains some operarions used for color space conversion containing linear transformation and non-linear transformation @@ -47,9 +44,15 @@ class Operation Mat M; MatFunc f; - Operation() : linear(true), M(Mat()) {}; - Operation(Mat M_) :linear(true), M(M_) {}; - Operation(MatFunc f_) : linear(false), f(f_) {}; + Operation() + : linear(true) + , M(Mat()) {}; + Operation(Mat M_) + : linear(true) + , M(M_) {}; + Operation(MatFunc f_) + : linear(false) + , f(f_) {}; virtual ~Operation() {}; /** @brief operator function will run operation @@ -62,20 +65,22 @@ class Operation void add(const Operation& other); void clear(); - static Operation& get_IDENTITY_OP(){ - static Operation identity_op([](Mat x) {return x; }); + static Operation& get_IDENTITY_OP() + { + static Operation identity_op([](Mat x) { return x; }); return identity_op; } }; - class Operations { public: std::vector ops; - Operations() :ops{ } {}; - Operations(std::initializer_list op) :ops{ op } {}; + Operations() + : ops {} {}; + Operations(std::initializer_list op) + : ops { op } {}; virtual ~Operations() {}; /** @brief add function will conbine this operation with other transformation operations @@ -85,13 +90,13 @@ class Operations /** @brief run operations to make color conversion */ Mat run(Mat abc); - static Operations get_IDENTITY_OPS(){ - return Operations{Operation::get_IDENTITY_OP()}; + static Operations get_IDENTITY_OPS() + { + return Operations { Operation::get_IDENTITY_OP() }; } }; -} // namespace ccm -} // namespace cv - +} +} // namespace cv::ccm #endif \ No newline at end of file diff --git a/modules/mcc/src/utils.cpp b/modules/mcc/src/utils.cpp index afc8c01261c..c894be84f88 100644 --- a/modules/mcc/src/utils.cpp +++ b/modules/mcc/src/utils.cpp @@ -27,10 +27,8 @@ #include "utils.hpp" -namespace cv -{ -namespace ccm -{ +namespace cv { +namespace ccm { double gammaCorrection_(const double& element, const double& gamma) { @@ -39,7 +37,7 @@ double gammaCorrection_(const double& element, const double& gamma) Mat gammaCorrection(const Mat& src, const double& gamma) { - return elementWise(src, [gamma](double element)->double {return gammaCorrection_(element, gamma); }); + return elementWise(src, [gamma](double element) -> double { return gammaCorrection_(element, gamma); }); } Mat maskCopyTo(const Mat& src, const Mat& mask) @@ -116,5 +114,5 @@ Mat rgb2gray(Mat rgb) return multiple(rgb, m_gray); } -} // namespace ccm -} // namespace cv +} +} // namespace cv::ccm diff --git a/modules/mcc/src/utils.hpp b/modules/mcc/src/utils.hpp index 86f7cd62dc9..7883f818737 100644 --- a/modules/mcc/src/utils.hpp +++ b/modules/mcc/src/utils.hpp @@ -76,7 +76,7 @@ Mat rgb2gray(Mat rgb); @param src the input array, type of Mat @param lambda a for operation */ -template +template Mat elementWise(const Mat& src, F&& lambda) { Mat dst = src.clone(); @@ -116,7 +116,7 @@ Mat elementWise(const Mat& src, F&& lambda) @param src the input array, type of Mat @param lambda the function for operation */ -template +template Mat channelWise(const Mat& src, F&& lambda) { Mat dst = src.clone(); @@ -133,12 +133,12 @@ Mat channelWise(const Mat& src, F&& lambda) @param ref another input array, type of Mat. @param lambda the computing method for distance . */ -template +template Mat distanceWise(Mat& src, Mat& ref, F&& lambda) { Mat dst = Mat(src.size(), CV_64FC1); MatIterator_ it_src = src.begin(), end_src = src.end(), - it_ref = ref.begin(); + it_ref = ref.begin(); MatIterator_ it_dst = dst.begin(); for (; it_src != end_src; ++it_src, ++it_ref, ++it_dst) { @@ -151,7 +151,7 @@ Mat multiple(const Mat& xyz, const Mat& ccm); static const Mat m_gray = (Mat_(3, 1) << 0.2126, 0.7152, 0.0722); -} // namespace ccm -} // namespace cv +} +} // namespace cv::ccm #endif \ No newline at end of file From 60c0be848db32f6a8d37aabf096d6f1a12db5419 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 19 Nov 2020 19:27:06 +0000 Subject: [PATCH 61/71] mcc(ccm): fix documentation, code style --- modules/mcc/CMakeLists.txt | 9 +- modules/mcc/include/opencv2/mcc.hpp | 7 +- modules/mcc/include/opencv2/mcc/ccm.hpp | 416 ++++++++++-------- modules/mcc/src/color.cpp | 20 +- modules/mcc/src/colorspace.cpp | 112 ++--- modules/mcc/src/utils.cpp | 5 +- modules/mcc/src/utils.hpp | 4 +- .../basic_ccm/color_correction_model.markdown | 12 +- 8 files changed, 322 insertions(+), 263 deletions(-) diff --git a/modules/mcc/CMakeLists.txt b/modules/mcc/CMakeLists.txt index 208f9d529ad..2b7fadbaa14 100644 --- a/modules/mcc/CMakeLists.txt +++ b/modules/mcc/CMakeLists.txt @@ -1,2 +1,9 @@ set(the_description "Macbeth Chart Detection") -ocv_define_module(mcc opencv_core opencv_imgproc opencv_calib3d opencv_photo opencv_dnn WRAP python) \ No newline at end of file +ocv_define_module(mcc + opencv_core + opencv_imgproc + opencv_calib3d + opencv_dnn + WRAP + python +) diff --git a/modules/mcc/include/opencv2/mcc.hpp b/modules/mcc/include/opencv2/mcc.hpp index 827af2abc68..e49f3053ffa 100644 --- a/modules/mcc/include/opencv2/mcc.hpp +++ b/modules/mcc/include/opencv2/mcc.hpp @@ -35,6 +35,12 @@ #include "mcc/ccm.hpp" /** @defgroup mcc Macbeth Chart module +@{ + @defgroup color_correction Color Correction Model +@} + + +@addtogroup mcc Introduction ------------ @@ -48,7 +54,6 @@ colors that are present in the image, based on this information we can apply any suitable algorithm to find the actual color of all the objects present in the image. - */ #endif diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 5b43b09b546..ca2fb304642 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -31,8 +31,12 @@ #include #include - -/** @defgroup ccm Color Correction Model +namespace cv +{ +namespace ccm +{ +/** @addtogroup color_correction +@{ Introduction ------------ @@ -46,15 +50,9 @@ medicine, etc. Due to the manufacturing process of the input and output equipmen the channel response has nonlinear distortion. In order to correct the picture output of the equipment, it is nessary to calibrate the captured color and the actual color. - */ -namespace cv -{ -namespace ccm -{ -//! @addtogroup ccm -//! @{ + /** @brief Enum of the possible types of ccm. */ @@ -62,14 +60,13 @@ enum CCM_TYPE { CCM_3x3, /// p; - }; + //! @} ccm } // namespace ccm } // namespace cv diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index 6bb387ea43e..6c2bf536080 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -52,6 +52,7 @@ Color::Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_) { grays = ~colored; } + Color::Color(Mat colors_, const ColorSpace& cs_) : colors(colors_) , cs(cs_) @@ -61,7 +62,6 @@ Color Color::to(const ColorSpace& other, CAM method, bool save) { if (history.count(other) == 1) { - return *history[other]; } if (cs.relate(other)) @@ -367,36 +367,32 @@ std::shared_ptr GetColor::get_color(CONST_COLOR const_color) switch (const_color) { + case cv::ccm::Macbeth: { Mat ColorChecker2005_LAB_D50_2_ = GetColor::get_ColorChecker(*ColorChecker2005_LAB_D50_2, 24); Mat ColorChecker2005_COLORED_MASK_ = GetColor::get_ColorChecker_MASK(ColorChecker2005_COLORED_MASK, 24); - std::shared_ptr Macbeth_D50_2(new Color(ColorChecker2005_LAB_D50_2_, Lab_D50_2, ColorChecker2005_COLORED_MASK_)); + std::shared_ptr Macbeth_D50_2 = std::make_shared(ColorChecker2005_LAB_D50_2_, Lab_D50_2, ColorChecker2005_COLORED_MASK_); return Macbeth_D50_2; - break; } case cv::ccm::Vinyl: { Mat Vinyl_LAB_D50_2__ = GetColor::get_ColorChecker(*Vinyl_LAB_D50_2, 18); Mat Vinyl_COLORED_MASK__ = GetColor::get_ColorChecker_MASK(Vinyl_COLORED_MASK, 18); - std::shared_ptr Vinyl_D50_2(new Color(Vinyl_LAB_D50_2__, Lab_D50_2, Vinyl_COLORED_MASK__)); + std::shared_ptr Vinyl_D50_2 = std::make_shared(Vinyl_LAB_D50_2__, Lab_D50_2, Vinyl_COLORED_MASK__); return Vinyl_D50_2; - break; } + case cv::ccm::DigitalSG: { Mat DigitalSG_LAB_D50_2__ = GetColor::get_ColorChecker(*DigitalSG_LAB_D50_2, 140); - std::shared_ptr DigitalSG_D50_2(new Color(DigitalSG_LAB_D50_2__, Lab_D50_2)); + std::shared_ptr DigitalSG_D50_2 = std::make_shared(DigitalSG_LAB_D50_2__, Lab_D50_2); return DigitalSG_D50_2; - break; } - - default: - throw; - break; } + CV_Error(Error::StsNotImplemented, ""); } } -} // namespace cv::ccm \ No newline at end of file +} // namespace cv::ccm diff --git a/modules/mcc/src/colorspace.cpp b/modules/mcc/src/colorspace.cpp index 1aba598d498..9d613f333dd 100644 --- a/modules/mcc/src/colorspace.cpp +++ b/modules/mcc/src/colorspace.cpp @@ -1,6 +1,6 @@ // This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level -// directory of this distribution and at http://opencv.org/license.html. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. // // // License Agreement @@ -25,15 +25,17 @@ // Jinheng Zhang // Chenqi Shan +#include "precomp.hpp" + #include "colorspace.hpp" #include "operations.hpp" #include "io.hpp" namespace cv { namespace ccm { -static std::map> getilluminants() +static const std::vector& getIlluminants(const IO& io) { - static std::map> illuminants = { + static const std::map> illuminants = { { IO::getIOs(A_2), { 1.098466069456375, 1, 0.3558228003436005 } }, { IO::getIOs(A_10), { 1.111420406956693, 1, 0.3519978321919493 } }, { IO::getIOs(D50_2), { 0.9642119944211994, 1, 0.8251882845188288 } }, @@ -47,10 +49,12 @@ static std::map> getilluminants() { IO::getIOs(E_2), { 1., 1., 1. } }, { IO::getIOs(E_10), { 1., 1., 1. } }, }; - return illuminants; + auto it = illuminants.find(io); + CV_Assert(it != illuminants.end()); + return it->second; }; -static std::map> illuminants = getilluminants(); -/* *\ brief Basic class for ColorSpace. + +/* @brief Basic class for ColorSpace. */ bool ColorSpace::relate(const ColorSpace& other) const { @@ -60,14 +64,14 @@ bool ColorSpace::relate(const ColorSpace& other) const Operations ColorSpace::relation(const ColorSpace& /*other*/) const { return Operations::get_IDENTITY_OPS(); -}; +} bool ColorSpace::operator<(const ColorSpace& other) const { return (io < other.io || (io == other.io && type < other.type) || (io == other.io && type == other.type && linear < other.linear)); } -/* *\ brief Base of RGB color space; +/* @brief Base of RGB color space; * the argument values are from AdobeRGB; * Data from https://en.wikipedia.org/wiki/Adobe_RGB_color_space */ @@ -82,9 +86,9 @@ Operations RGBBase_::relation(const ColorSpace& other) const return Operations({ Operation(fromL) }); } return Operations({ Operation(toL) }); -}; +} -/* *\ brief Initial operations. +/* @brief Initial operations. */ void RGBBase_::init() { @@ -94,8 +98,8 @@ void RGBBase_::init() calOperations(); } -/* *\ brief Produce color space instance with linear and non-linear versions. - *\ param rgbl type of RGBBase_. +/* @brief Produce color space instance with linear and non-linear versions. + * @param rgbl type of RGBBase_. */ void RGBBase_::bind(RGBBase_& rgbl) { @@ -107,7 +111,7 @@ void RGBBase_::bind(RGBBase_& rgbl) rgbl.nl = this; } -/* *\ brief Calculation of M_RGBL2XYZ_base. +/* @brief Calculation of M_RGBL2XYZ_base. * see ColorSpace.pdf for details. */ void RGBBase_::calM() @@ -118,7 +122,7 @@ void RGBBase_::calM() XYZb = Mat(xyY2XYZ({ xb, yb }), true); merge(std::vector { XYZr, XYZg, XYZb }, XYZ_rgbl); XYZ_rgbl = XYZ_rgbl.reshape(1, XYZ_rgbl.rows); - Mat XYZw = Mat(illuminants.find(io)->second, true); + Mat XYZw = Mat(getIlluminants(io), true); solve(XYZ_rgbl, XYZw, Srgb); merge(std::vector { Srgb.at(0) * XYZr, Srgb.at(1) * XYZg, Srgb.at(2) * XYZb }, @@ -127,7 +131,7 @@ void RGBBase_::calM() M_from = M_to.inv(); }; -/* *\ brief operations to or from XYZ. +/* @brief operations to or from XYZ. */ void RGBBase_::calOperations() { @@ -153,7 +157,7 @@ Mat RGBBase_::toLFunc(Mat& /*rgb*/) { return Mat(); } Mat RGBBase_::fromLFunc(Mat& /*rgbl*/) { return Mat(); } -/* *\ brief Base of Adobe RGB color space; +/* @brief Base of Adobe RGB color space; */ Mat AdobeRGBBase_::toLFunc(Mat& rgb) { return gammaCorrection(rgb, gamma); } @@ -163,7 +167,7 @@ Mat AdobeRGBBase_::fromLFunc(Mat& rgbl) return gammaCorrection(rgbl, 1. / gamma); } -/* *\ brief Base of sRGB color space; +/* @brief Base of sRGB color space; */ void sRGBBase_::calLinear() @@ -174,7 +178,7 @@ void sRGBBase_::calLinear() beta = K0 / phi; } -/* *\ brief Used by toLFunc. +/* @brief Used by toLFunc. */ double sRGBBase_::toLFuncEW(double& x) { @@ -192,10 +196,10 @@ double sRGBBase_::toLFuncEW(double& x) } } -/* *\ brief Linearization. +/* @brief Linearization. * see ColorSpace.pdf for details. - *\ param rgb the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat. + * @param rgb the input array, type of cv::Mat. + * @return the output array, type of cv::Mat. */ Mat sRGBBase_::toLFunc(Mat& rgb) { @@ -203,7 +207,7 @@ Mat sRGBBase_::toLFunc(Mat& rgb) [this](double a_) -> double { return toLFuncEW(a_); }); } -/* *\ brief Used by fromLFunc. +/* @brief Used by fromLFunc. */ double sRGBBase_::fromLFuncEW(double& x) { @@ -221,10 +225,10 @@ double sRGBBase_::fromLFuncEW(double& x) } } -/* *\ brief Delinearization. +/* @brief Delinearization. * see ColorSpace.pdf for details. - *\ param rgbl the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat. + * @param rgbl the input array, type of cv::Mat. + * @return the output array, type of cv::Mat. */ Mat sRGBBase_::fromLFunc(Mat& rgbl) { @@ -232,7 +236,7 @@ Mat sRGBBase_::fromLFunc(Mat& rgbl) [this](double a_) -> double { return fromLFuncEW(a_); }); } -/* *\ brief sRGB color space. +/* @brief sRGB color space. * data from https://en.wikipedia.org/wiki/SRGB. */ void sRGB_::setParameter() @@ -247,7 +251,7 @@ void sRGB_::setParameter() gamma = 2.4; } -/* *\ brief Adobe RGB color space. +/* @brief Adobe RGB color space. */ void AdobeRGB_::setParameter() { @@ -260,7 +264,7 @@ void AdobeRGB_::setParameter() gamma = 2.2; } -/* *\ brief Wide-gamut RGB color space. +/* @brief Wide-gamut RGB color space. * data from https://en.wikipedia.org/wiki/Wide-gamut_RGB_color_space. */ void WideGamutRGB_::setParameter() @@ -274,7 +278,7 @@ void WideGamutRGB_::setParameter() gamma = 2.2; } -/* *\ brief ProPhoto RGB color space. +/* @brief ProPhoto RGB color space. * data from https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space. */ void ProPhotoRGB_::setParameter() @@ -288,7 +292,7 @@ void ProPhotoRGB_::setParameter() gamma = 1.8; } -/* *\ brief DCI-P3 RGB color space. +/* @brief DCI-P3 RGB color space. * data from https://en.wikipedia.org/wiki/DCI-P3. */ @@ -303,7 +307,7 @@ void DCI_P3_RGB_::setParameter() gamma = 2.2; } -/* *\ brief Apple RGB color space. +/* @brief Apple RGB color space. * data from * http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html. */ @@ -318,7 +322,7 @@ void AppleRGB_::setParameter() gamma = 1.8; } -/* *\ brief REC_709 RGB color space. +/* @brief REC_709 RGB color space. * data from https://en.wikipedia.org/wiki/Rec._709. */ void REC_709_RGB_::setParameter() @@ -333,7 +337,7 @@ void REC_709_RGB_::setParameter() gamma = 1 / 0.45; } -/* *\ brief REC_2020 RGB color space. +/* @brief REC_2020 RGB color space. * data from https://en.wikipedia.org/wiki/Rec._2020. */ @@ -349,10 +353,10 @@ void REC_2020_RGB_::setParameter() gamma = 1 / 0.45; } -/* *\ brief Enum of the possible types of CAMs. +/* @brief Enum of the possible types of CAMs. */ -/* *\ brief XYZ color space. +/* @brief XYZ color space. * Chromatic adaption matrices. */ Operations XYZ::cam(IO dio, CAM method) @@ -372,8 +376,8 @@ Mat XYZ::cam_(IO sio, IO dio, CAM method) const } // Function from http://www.brucelindbloom.com/index.html?ColorCheckerRGB.html. - Mat XYZws = Mat(illuminants.find(dio)->second); - Mat XYZWd = Mat(illuminants.find(sio)->second); + Mat XYZws = Mat(getIlluminants(dio)); + Mat XYZWd = Mat(getIlluminants(sio)); Mat MA = MAs.at(method)[0]; Mat MA_inv = MAs.at(method)[1]; Mat M = MA_inv * Mat::diag((MA * XYZws) / (MA * XYZWd)) * MA; @@ -395,7 +399,7 @@ std::shared_ptr XYZ::get(IO io) return xyz_cs[io]; } -/* *\ brief Lab color space. +/* @brief Lab color space. */ Lab::Lab(IO io_) : ColorSpace(io_, "Lab", true) @@ -406,9 +410,10 @@ Lab::Lab(IO io_) Vec3d Lab::fromxyz(cv::Vec3d& xyz) { - double x = xyz[0] / illuminants.find(io)->second[0], - y = xyz[1] / illuminants.find(io)->second[1], - z = xyz[2] / illuminants.find(io)->second[2]; + auto& il = getIlluminants(io); + double x = xyz[0] / il[0], + y = xyz[1] / il[1], + z = xyz[2] / il[2]; auto f = [](double t) -> double { return t > t0 ? std::cbrt(t) : (m * t + c); }; @@ -416,9 +421,9 @@ Vec3d Lab::fromxyz(cv::Vec3d& xyz) return { 116. * fy - 16., 500 * (fx - fy), 200 * (fy - fz) }; } -/* *\ brief Calculate From. - *\ param src the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat +/* @brief Calculate From. + * @param src the input array, type of cv::Mat. + * @return the output array, type of cv::Mat */ Mat Lab::fromsrc(Mat& src) { @@ -432,14 +437,15 @@ Vec3d Lab::tolab(cv::Vec3d& lab) return t > delta ? pow(t, 3.0) : (t - c) / m; }; double L = (lab[0] + 16.) / 116., a = lab[1] / 500., b = lab[2] / 200.; - return { illuminants.find(io)->second[0] * f_inv(L + a), - illuminants.find(io)->second[1] * f_inv(L), - illuminants.find(io)->second[2] * f_inv(L - b) }; + auto& il = getIlluminants(io); + return { il[0] * f_inv(L + a), + il[1] * f_inv(L), + il[2] * f_inv(L - b) }; } -/* *\ brief Calculate To. - *\ param src the input array, type of cv::Mat. - *\ return the output array, type of cv::Mat +/* @brief Calculate To. + * @param src the input array, type of cv::Mat. + * @return the output array, type of cv::Mat */ Mat Lab::tosrc(Mat& src) { @@ -568,11 +574,11 @@ std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) case cv::ccm::AppleRGBL: case cv::ccm::REC_709_RGBL: case cv::ccm::REC_2020_RGBL: - throw "linear RGB colorspaces are not supported, you should assigned as normal rgb color space"; + CV_Error(Error::StsBadArg, "linear RGB colorspaces are not supported, you should assigned as normal rgb color space"); break; default: - throw "Only RGB color spaces are supported"; + CV_Error(Error::StsBadArg, "Only RGB color spaces are supported"); } return (std::dynamic_pointer_cast)(map_cs[cs_name]); } diff --git a/modules/mcc/src/utils.cpp b/modules/mcc/src/utils.cpp index c894be84f88..1bfc4204598 100644 --- a/modules/mcc/src/utils.cpp +++ b/modules/mcc/src/utils.cpp @@ -109,9 +109,10 @@ Mat saturate(Mat& src, const double& low, const double& up) return dst; } -Mat rgb2gray(Mat rgb) +Mat rgb2gray(const Mat& rgb) { - return multiple(rgb, m_gray); + const Matx31d m_gray(0.2126, 0.7152, 0.0722); + return multiple(rgb, Mat(m_gray)); } } diff --git a/modules/mcc/src/utils.hpp b/modules/mcc/src/utils.hpp index 7883f818737..a9810a017df 100644 --- a/modules/mcc/src/utils.hpp +++ b/modules/mcc/src/utils.hpp @@ -70,7 +70,7 @@ Mat saturate(Mat& src, const double& low, const double& up); color space, see Miscellaneous.pdf for details; @param rgb the input array,type of Mat. */ -Mat rgb2gray(Mat rgb); +Mat rgb2gray(const Mat& rgb); /** @brief function for elementWise operation @param src the input array, type of Mat @@ -149,8 +149,6 @@ Mat distanceWise(Mat& src, Mat& ref, F&& lambda) Mat multiple(const Mat& xyz, const Mat& ccm); -static const Mat m_gray = (Mat_(3, 1) << 0.2126, 0.7152, 0.0722); - } } // namespace cv::ccm diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index 9e019491cb3..3b8ed663241 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -6,12 +6,12 @@ In this tutorial you will learn how to use the 'Color Correction Model' to do a Reference ---- -See details of ColorCorrection Algorithm at https://github.com/riskiest/color_calibration/tree/v4/doc/pdf/English/Algorithm. +See details of ColorCorrection Algorithm at https://github.com/riskiest/color_calibration/tree/v4/doc/pdf/English/Algorithm Building ---- -When building OpenCV, run the following command to build all the contrib module: +When building OpenCV, run the following command to build all the contrib modules: ```make cmake -D OPENCV_EXTRA_MODULES_PATH=/modules/ @@ -28,7 +28,7 @@ Or make sure you check the mcc module in the GUI version of CMake: cmake-gui. Source Code of the sample ----------- -The sample has two parts of code, the first is the color checker detector model, see details at[basic_chart_detection](https://github.com/opencv/opencv_contrib/tree/master/modules/mcc/tutorials/basic_chart_detection), the second part is to make collor calibration. +The sample has two parts of code, the first is the color checker detector model, see details at @ref tutorial_mcc_basic_chart_detection, the second part is to make collor calibration. ``` Here are the parameters for ColorCorrectionModel @@ -41,11 +41,11 @@ Here are the parameters for ColorCorrectionModel Macbeth: Macbeth ColorChecker ; Vinyl: DKK ColorChecker ; DigitalSG: DigitalSG ColorChecker with 140 squares; - Mat colors_ : + Mat colors : the reference color values and corresponding color space NOTICE: the color values are in [0, 1] - ref_cs_ : + ref_cs : the corresponding color space NOTICE: For the list of color spaces supported, see the notes below; If the color type is some RGB, the format is RGB not BGR; @@ -120,4 +120,4 @@ If you use a customized ColorChecker, you can use your own reference color value The member function infer_image is to make correction correction using ccm matrix. @snippet samples/color_correction_model.cpp Save_calibrated_image -Save the calibrated image. \ No newline at end of file +Save the calibrated image. From 592fea119be5d303cb5d6cd1928618968e7b0c6b Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Fri, 20 Nov 2020 12:43:07 +0800 Subject: [PATCH 62/71] remove duplicate enum values --- modules/mcc/include/opencv2/mcc/ccm.hpp | 74 +++++++++---------------- 1 file changed, 26 insertions(+), 48 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index ca2fb304642..de247412ed0 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -86,9 +86,9 @@ enum INITIAL_METHOD_TYPE /** @brief Macbeth and Vinyl ColorChecker with 2deg D50 */ enum CONST_COLOR { - Macbeth, - Vinyl, - DigitalSG, + Macbeth, /// Date: Fri, 20 Nov 2020 14:29:44 +0800 Subject: [PATCH 63/71] add prefixes for enum values --- modules/mcc/include/opencv2/mcc/ccm.hpp | 159 ++++++++-------- .../mcc/samples/color_correction_model.cpp | 6 +- modules/mcc/src/ccm.cpp | 16 +- modules/mcc/src/color.cpp | 32 ++-- modules/mcc/src/color.hpp | 4 +- modules/mcc/src/colorspace.cpp | 176 +++++++++--------- modules/mcc/src/colorspace.hpp | 5 - modules/mcc/src/distance.cpp | 16 +- modules/mcc/src/linearize.cpp | 12 +- .../basic_ccm/color_correction_model.markdown | 80 ++++---- 10 files changed, 252 insertions(+), 254 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index de247412ed0..37fbe962910 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -58,15 +58,15 @@ of the equipment, it is nessary to calibrate the captured color and the actual c */ enum CCM_TYPE { - CCM_3x3, ///0\\ C_{sl}=0, \qquad C_s=0 \f] -Because \f$exp(ln(0))\to\infin\f$, the channel whose component is 0 is directly mapped to 0 in the formula above. +Because \f$exp(ln(0))\to\infty \f$, the channel whose component is 0 is directly mapped to 0 in the formula above. For fitting channels respectively, we have: \f[ @@ -329,12 +329,12 @@ C_sl=0, \qquad C_s=0 enum LINEAR_TYPE { - IDENTITY_, ///distance) { - case cv::ccm::RGBL: + case cv::ccm::DISTANCE_RGBL: p->initialLeastSquare(true); break; default: switch (p->initial_method_type) { - case cv::ccm::WHITE_BALANCE: + case cv::ccm::INITIAL_METHOD_WHITE_BALANCE: p->initialWhiteBalance(); break; - case cv::ccm::LEAST_SQUARE: + case cv::ccm::INITIAL_METHOD_LEAST_SQUARE: p->initialLeastSquare(); break; default: diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index 6c2bf536080..76d35f65d4c 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -111,16 +111,16 @@ Mat Color::diff(Color& other, IO io, DISTANCE_TYPE method) Lab lab = *Lab::get(io); switch (method) { - case cv::ccm::CIE76: - case cv::ccm::CIE94_GRAPHIC_ARTS: - case cv::ccm::CIE94_TEXTILES: - case cv::ccm::CIE2000: - case cv::ccm::CMC_1TO1: - case cv::ccm::CMC_2TO1: + case cv::ccm::DISTANCE_CIE76: + case cv::ccm::DISTANCE_CIE94_GRAPHIC_ARTS: + case cv::ccm::DISTANCE_CIE94_TEXTILES: + case cv::ccm::DISTANCE_CIE2000: + case cv::ccm::DISTANCE_CMC_1TO1: + case cv::ccm::DISTANCE_CMC_2TO1: return distance(to(lab).colors, other.to(lab).colors, method); - case cv::ccm::RGB: + case cv::ccm::DISTANCE_RGB: return distance(to(*cs.nl).colors, other.to(*cs.nl).colors, method); - case cv::ccm::RGBL: + case cv::ccm::DISTANCE_RGBL: return distance(to(*cs.l).colors, other.to(*cs.l).colors, method); default: throw std::invalid_argument { "Wrong method!" }; @@ -134,11 +134,11 @@ void Color::getGray(double JDN) { return; } - Mat lab = to(Lab_D65_2).colors; + Mat lab = to(COLOR_SPACE_Lab_D65_2).colors; Mat gray(colors.size(), colors.type()); int fromto[] = { 0, 0, -1, 1, -1, 2 }; mixChannels(&lab, 1, &gray, 1, fromto, 3); - Mat d = distance(lab, gray, CIE2000); + Mat d = distance(lab, gray, DISTANCE_CIE2000); this->grays = d < JDN; this->colored = ~grays; } @@ -368,26 +368,26 @@ std::shared_ptr GetColor::get_color(CONST_COLOR const_color) switch (const_color) { - case cv::ccm::Macbeth: + case cv::ccm::COLORCHECKER_Macbeth: { Mat ColorChecker2005_LAB_D50_2_ = GetColor::get_ColorChecker(*ColorChecker2005_LAB_D50_2, 24); Mat ColorChecker2005_COLORED_MASK_ = GetColor::get_ColorChecker_MASK(ColorChecker2005_COLORED_MASK, 24); - std::shared_ptr Macbeth_D50_2 = std::make_shared(ColorChecker2005_LAB_D50_2_, Lab_D50_2, ColorChecker2005_COLORED_MASK_); + std::shared_ptr Macbeth_D50_2 = std::make_shared(ColorChecker2005_LAB_D50_2_, COLOR_SPACE_Lab_D50_2, ColorChecker2005_COLORED_MASK_); return Macbeth_D50_2; } - case cv::ccm::Vinyl: + case cv::ccm::COLORCHECKER_Vinyl: { Mat Vinyl_LAB_D50_2__ = GetColor::get_ColorChecker(*Vinyl_LAB_D50_2, 18); Mat Vinyl_COLORED_MASK__ = GetColor::get_ColorChecker_MASK(Vinyl_COLORED_MASK, 18); - std::shared_ptr Vinyl_D50_2 = std::make_shared(Vinyl_LAB_D50_2__, Lab_D50_2, Vinyl_COLORED_MASK__); + std::shared_ptr Vinyl_D50_2 = std::make_shared(Vinyl_LAB_D50_2__, COLOR_SPACE_Lab_D50_2, Vinyl_COLORED_MASK__); return Vinyl_D50_2; } - case cv::ccm::DigitalSG: + case cv::ccm::COLORCHECKER_DigitalSG: { Mat DigitalSG_LAB_D50_2__ = GetColor::get_ColorChecker(*DigitalSG_LAB_D50_2, 140); - std::shared_ptr DigitalSG_D50_2 = std::make_shared(DigitalSG_LAB_D50_2__, Lab_D50_2); + std::shared_ptr DigitalSG_D50_2 = std::make_shared(DigitalSG_LAB_D50_2__, COLOR_SPACE_Lab_D50_2); return DigitalSG_D50_2; } } diff --git a/modules/mcc/src/color.hpp b/modules/mcc/src/color.hpp index 710bc5bfac4..8be475ba065 100644 --- a/modules/mcc/src/color.hpp +++ b/modules/mcc/src/color.hpp @@ -85,7 +85,7 @@ class Color @param method type of distance. @return distance between self and other */ - Mat diff(Color& other, DISTANCE_TYPE method = CIE2000); + Mat diff(Color& other, DISTANCE_TYPE method = DISTANCE_CIE2000); /** @brief Diff with IO. @param other type of Color. @@ -93,7 +93,7 @@ class Color @param method type of distance. @return distance between self and other */ - Mat diff(Color& other, IO io, DISTANCE_TYPE method = CIE2000); + Mat diff(Color& other, IO io, DISTANCE_TYPE method = DISTANCE_CIE2000); /** @brief Calculate gray mask. */ diff --git a/modules/mcc/src/colorspace.cpp b/modules/mcc/src/colorspace.cpp index 9d613f333dd..dd5eda60520 100644 --- a/modules/mcc/src/colorspace.cpp +++ b/modules/mcc/src/colorspace.cpp @@ -470,110 +470,110 @@ std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) { switch (cs_name) { - case cv::ccm::sRGB: + case cv::ccm::COLOR_SPACE_sRGB: { if (map_cs.count(cs_name) < 1) { std::shared_ptr sRGB_CS(new sRGB_(false)); std::shared_ptr sRGBL_CS(new sRGB_(true)); (*sRGB_CS).bind(*sRGBL_CS); - map_cs[sRGB] = sRGB_CS; - map_cs[sRGBL] = sRGBL_CS; + map_cs[COLOR_SPACE_sRGB] = sRGB_CS; + map_cs[COLOR_SPACE_sRGBL] = sRGBL_CS; } break; } - case cv::ccm::AdobeRGB: + case cv::ccm::COLOR_SPACE_AdobeRGB: { if (map_cs.count(cs_name) < 1) { std::shared_ptr AdobeRGB_CS(new AdobeRGB_(false)); std::shared_ptr AdobeRGBL_CS(new AdobeRGB_(true)); (*AdobeRGB_CS).bind(*AdobeRGBL_CS); - map_cs[AdobeRGB] = AdobeRGB_CS; - map_cs[AdobeRGBL] = AdobeRGBL_CS; + map_cs[COLOR_SPACE_AdobeRGB] = AdobeRGB_CS; + map_cs[COLOR_SPACE_AdobeRGBL] = AdobeRGBL_CS; } break; } - case cv::ccm::WideGamutRGB: + case cv::ccm::COLOR_SPACE_WideGamutRGB: { if (map_cs.count(cs_name) < 1) { std::shared_ptr WideGamutRGB_CS(new WideGamutRGB_(false)); std::shared_ptr WideGamutRGBL_CS(new WideGamutRGB_(true)); (*WideGamutRGB_CS).bind(*WideGamutRGBL_CS); - map_cs[WideGamutRGB] = WideGamutRGB_CS; - map_cs[WideGamutRGBL] = WideGamutRGBL_CS; + map_cs[COLOR_SPACE_WideGamutRGB] = WideGamutRGB_CS; + map_cs[COLOR_SPACE_WideGamutRGBL] = WideGamutRGBL_CS; } break; } - case cv::ccm::ProPhotoRGB: + case cv::ccm::COLOR_SPACE_ProPhotoRGB: { if (map_cs.count(cs_name) < 1) { std::shared_ptr ProPhotoRGB_CS(new ProPhotoRGB_(false)); std::shared_ptr ProPhotoRGBL_CS(new ProPhotoRGB_(true)); (*ProPhotoRGB_CS).bind(*ProPhotoRGBL_CS); - map_cs[ProPhotoRGB] = ProPhotoRGB_CS; - map_cs[ProPhotoRGBL] = ProPhotoRGBL_CS; + map_cs[COLOR_SPACE_ProPhotoRGB] = ProPhotoRGB_CS; + map_cs[COLOR_SPACE_ProPhotoRGBL] = ProPhotoRGBL_CS; } break; } - case cv::ccm::DCI_P3_RGB: + case cv::ccm::COLOR_SPACE_DCI_P3_RGB: { if (map_cs.count(cs_name) < 1) { std::shared_ptr DCI_P3_RGB_CS(new DCI_P3_RGB_(false)); std::shared_ptr DCI_P3_RGBL_CS(new DCI_P3_RGB_(true)); (*DCI_P3_RGB_CS).bind(*DCI_P3_RGBL_CS); - map_cs[DCI_P3_RGB] = DCI_P3_RGB_CS; - map_cs[DCI_P3_RGBL] = DCI_P3_RGBL_CS; + map_cs[COLOR_SPACE_DCI_P3_RGB] = DCI_P3_RGB_CS; + map_cs[COLOR_SPACE_DCI_P3_RGBL] = DCI_P3_RGBL_CS; } break; } - case cv::ccm::AppleRGB: + case cv::ccm::COLOR_SPACE_AppleRGB: { if (map_cs.count(cs_name) < 1) { std::shared_ptr AppleRGB_CS(new AppleRGB_(false)); std::shared_ptr AppleRGBL_CS(new AppleRGB_(true)); (*AppleRGB_CS).bind(*AppleRGBL_CS); - map_cs[AppleRGB] = AppleRGB_CS; - map_cs[AppleRGBL] = AppleRGBL_CS; + map_cs[COLOR_SPACE_AppleRGB] = AppleRGB_CS; + map_cs[COLOR_SPACE_AppleRGBL] = AppleRGBL_CS; } break; } - case cv::ccm::REC_709_RGB: + case cv::ccm::COLOR_SPACE_REC_709_RGB: { if (map_cs.count(cs_name) < 1) { std::shared_ptr REC_709_RGB_CS(new REC_709_RGB_(false)); std::shared_ptr REC_709_RGBL_CS(new REC_709_RGB_(true)); (*REC_709_RGB_CS).bind(*REC_709_RGBL_CS); - map_cs[REC_709_RGB] = REC_709_RGB_CS; - map_cs[REC_709_RGBL] = REC_709_RGBL_CS; + map_cs[COLOR_SPACE_REC_709_RGB] = REC_709_RGB_CS; + map_cs[COLOR_SPACE_REC_709_RGBL] = REC_709_RGBL_CS; } break; } - case cv::ccm::REC_2020_RGB: + case cv::ccm::COLOR_SPACE_REC_2020_RGB: { if (map_cs.count(cs_name) < 1) { std::shared_ptr REC_2020_RGB_CS(new REC_2020_RGB_(false)); std::shared_ptr REC_2020_RGBL_CS(new REC_2020_RGB_(true)); (*REC_2020_RGB_CS).bind(*REC_2020_RGBL_CS); - map_cs[REC_2020_RGB] = REC_2020_RGB_CS; - map_cs[REC_2020_RGBL] = REC_2020_RGBL_CS; + map_cs[COLOR_SPACE_REC_2020_RGB] = REC_2020_RGB_CS; + map_cs[COLOR_SPACE_REC_2020_RGBL] = REC_2020_RGBL_CS; } break; } - case cv::ccm::sRGBL: - case cv::ccm::AdobeRGBL: - case cv::ccm::WideGamutRGBL: - case cv::ccm::ProPhotoRGBL: - case cv::ccm::DCI_P3_RGBL: - case cv::ccm::AppleRGBL: - case cv::ccm::REC_709_RGBL: - case cv::ccm::REC_2020_RGBL: + case cv::ccm::COLOR_SPACE_sRGBL: + case cv::ccm::COLOR_SPACE_AdobeRGBL: + case cv::ccm::COLOR_SPACE_WideGamutRGBL: + case cv::ccm::COLOR_SPACE_ProPhotoRGBL: + case cv::ccm::COLOR_SPACE_DCI_P3_RGBL: + case cv::ccm::COLOR_SPACE_AppleRGBL: + case cv::ccm::COLOR_SPACE_REC_709_RGBL: + case cv::ccm::COLOR_SPACE_REC_2020_RGBL: CV_Error(Error::StsBadArg, "linear RGB colorspaces are not supported, you should assigned as normal rgb color space"); break; @@ -587,180 +587,180 @@ std::shared_ptr GetCS::get_cs(enum COLOR_SPACE cs_name) { switch (cs_name) { - case cv::ccm::sRGB: - case cv::ccm::sRGBL: + case cv::ccm::COLOR_SPACE_sRGB: + case cv::ccm::COLOR_SPACE_sRGBL: { if (map_cs.count(cs_name) < 1) { std::shared_ptr sRGB_CS(new sRGB_(false)); std::shared_ptr sRGBL_CS(new sRGB_(true)); (*sRGB_CS).bind(*sRGBL_CS); - map_cs[sRGB] = sRGB_CS; - map_cs[sRGBL] = sRGBL_CS; + map_cs[COLOR_SPACE_sRGB] = sRGB_CS; + map_cs[COLOR_SPACE_sRGBL] = sRGBL_CS; } break; } - case cv::ccm::AdobeRGB: - case cv::ccm::AdobeRGBL: + case cv::ccm::COLOR_SPACE_AdobeRGB: + case cv::ccm::COLOR_SPACE_AdobeRGBL: { if (map_cs.count(cs_name) < 1) { std::shared_ptr AdobeRGB_CS(new AdobeRGB_(false)); std::shared_ptr AdobeRGBL_CS(new AdobeRGB_(true)); (*AdobeRGB_CS).bind(*AdobeRGBL_CS); - map_cs[AdobeRGB] = AdobeRGB_CS; - map_cs[AdobeRGBL] = AdobeRGBL_CS; + map_cs[COLOR_SPACE_AdobeRGB] = AdobeRGB_CS; + map_cs[COLOR_SPACE_AdobeRGBL] = AdobeRGBL_CS; } break; } - case cv::ccm::WideGamutRGB: - case cv::ccm::WideGamutRGBL: + case cv::ccm::COLOR_SPACE_WideGamutRGB: + case cv::ccm::COLOR_SPACE_WideGamutRGBL: { if (map_cs.count(cs_name) < 1) { std::shared_ptr WideGamutRGB_CS(new WideGamutRGB_(false)); std::shared_ptr WideGamutRGBL_CS(new WideGamutRGB_(true)); (*WideGamutRGB_CS).bind(*WideGamutRGBL_CS); - map_cs[WideGamutRGB] = WideGamutRGB_CS; - map_cs[WideGamutRGBL] = WideGamutRGBL_CS; + map_cs[COLOR_SPACE_WideGamutRGB] = WideGamutRGB_CS; + map_cs[COLOR_SPACE_WideGamutRGBL] = WideGamutRGBL_CS; } break; } - case cv::ccm::ProPhotoRGB: - case cv::ccm::ProPhotoRGBL: + case cv::ccm::COLOR_SPACE_ProPhotoRGB: + case cv::ccm::COLOR_SPACE_ProPhotoRGBL: { if (map_cs.count(cs_name) < 1) { std::shared_ptr ProPhotoRGB_CS(new ProPhotoRGB_(false)); std::shared_ptr ProPhotoRGBL_CS(new ProPhotoRGB_(true)); (*ProPhotoRGB_CS).bind(*ProPhotoRGBL_CS); - map_cs[ProPhotoRGB] = ProPhotoRGB_CS; - map_cs[ProPhotoRGBL] = ProPhotoRGBL_CS; + map_cs[COLOR_SPACE_ProPhotoRGB] = ProPhotoRGB_CS; + map_cs[COLOR_SPACE_ProPhotoRGBL] = ProPhotoRGBL_CS; } break; } - case cv::ccm::DCI_P3_RGB: - case cv::ccm::DCI_P3_RGBL: + case cv::ccm::COLOR_SPACE_DCI_P3_RGB: + case cv::ccm::COLOR_SPACE_DCI_P3_RGBL: { if (map_cs.count(cs_name) < 1) { std::shared_ptr DCI_P3_RGB_CS(new DCI_P3_RGB_(false)); std::shared_ptr DCI_P3_RGBL_CS(new DCI_P3_RGB_(true)); (*DCI_P3_RGB_CS).bind(*DCI_P3_RGBL_CS); - map_cs[DCI_P3_RGB] = DCI_P3_RGB_CS; - map_cs[DCI_P3_RGBL] = DCI_P3_RGBL_CS; + map_cs[COLOR_SPACE_DCI_P3_RGB] = DCI_P3_RGB_CS; + map_cs[COLOR_SPACE_DCI_P3_RGBL] = DCI_P3_RGBL_CS; } break; } - case cv::ccm::AppleRGB: - case cv::ccm::AppleRGBL: + case cv::ccm::COLOR_SPACE_AppleRGB: + case cv::ccm::COLOR_SPACE_AppleRGBL: { if (map_cs.count(cs_name) < 1) { std::shared_ptr AppleRGB_CS(new AppleRGB_(false)); std::shared_ptr AppleRGBL_CS(new AppleRGB_(true)); (*AppleRGB_CS).bind(*AppleRGBL_CS); - map_cs[AppleRGB] = AppleRGB_CS; - map_cs[AppleRGBL] = AppleRGBL_CS; + map_cs[COLOR_SPACE_AppleRGB] = AppleRGB_CS; + map_cs[COLOR_SPACE_AppleRGBL] = AppleRGBL_CS; } break; } - case cv::ccm::REC_709_RGB: - case cv::ccm::REC_709_RGBL: + case cv::ccm::COLOR_SPACE_REC_709_RGB: + case cv::ccm::COLOR_SPACE_REC_709_RGBL: { if (map_cs.count(cs_name) < 1) { std::shared_ptr REC_709_RGB_CS(new REC_709_RGB_(false)); std::shared_ptr REC_709_RGBL_CS(new REC_709_RGB_(true)); (*REC_709_RGB_CS).bind(*REC_709_RGBL_CS); - map_cs[REC_709_RGB] = REC_709_RGB_CS; - map_cs[REC_709_RGBL] = REC_709_RGBL_CS; + map_cs[COLOR_SPACE_REC_709_RGB] = REC_709_RGB_CS; + map_cs[COLOR_SPACE_REC_709_RGBL] = REC_709_RGBL_CS; } break; } - case cv::ccm::REC_2020_RGB: - case cv::ccm::REC_2020_RGBL: + case cv::ccm::COLOR_SPACE_REC_2020_RGB: + case cv::ccm::COLOR_SPACE_REC_2020_RGBL: { if (map_cs.count(cs_name) < 1) { std::shared_ptr REC_2020_RGB_CS(new REC_2020_RGB_(false)); std::shared_ptr REC_2020_RGBL_CS(new REC_2020_RGB_(true)); (*REC_2020_RGB_CS).bind(*REC_2020_RGBL_CS); - map_cs[REC_2020_RGB] = REC_2020_RGB_CS; - map_cs[REC_2020_RGBL] = REC_2020_RGBL_CS; + map_cs[COLOR_SPACE_REC_2020_RGB] = REC_2020_RGB_CS; + map_cs[COLOR_SPACE_REC_2020_RGBL] = REC_2020_RGBL_CS; } break; } - case cv::ccm::XYZ_D65_2: + case cv::ccm::COLOR_SPACE_XYZ_D65_2: return XYZ::get(IO::getIOs(D65_2)); break; - case cv::ccm::XYZ_D50_2: + case cv::ccm::COLOR_SPACE_XYZ_D50_2: return XYZ::get(IO::getIOs(D50_2)); break; - case cv::ccm::XYZ_D65_10: + case cv::ccm::COLOR_SPACE_XYZ_D65_10: return XYZ::get(IO::getIOs(D65_10)); break; - case cv::ccm::XYZ_D50_10: + case cv::ccm::COLOR_SPACE_XYZ_D50_10: return XYZ::get(IO::getIOs(D50_10)); break; - case cv::ccm::XYZ_A_2: + case cv::ccm::COLOR_SPACE_XYZ_A_2: return XYZ::get(IO::getIOs(A_2)); break; - case cv::ccm::XYZ_A_10: + case cv::ccm::COLOR_SPACE_XYZ_A_10: return XYZ::get(IO::getIOs(A_10)); break; - case cv::ccm::XYZ_D55_2: + case cv::ccm::COLOR_SPACE_XYZ_D55_2: return XYZ::get(IO::getIOs(D55_2)); break; - case cv::ccm::XYZ_D55_10: + case cv::ccm::COLOR_SPACE_XYZ_D55_10: return XYZ::get(IO::getIOs(D55_10)); break; - case cv::ccm::XYZ_D75_2: + case cv::ccm::COLOR_SPACE_XYZ_D75_2: return XYZ::get(IO::getIOs(D75_2)); break; - case cv::ccm::XYZ_D75_10: + case cv::ccm::COLOR_SPACE_XYZ_D75_10: return XYZ::get(IO::getIOs(D75_10)); break; - case cv::ccm::XYZ_E_2: + case cv::ccm::COLOR_SPACE_XYZ_E_2: return XYZ::get(IO::getIOs(E_2)); break; - case cv::ccm::XYZ_E_10: + case cv::ccm::COLOR_SPACE_XYZ_E_10: return XYZ::get(IO::getIOs(E_10)); break; - case cv::ccm::Lab_D65_2: + case cv::ccm::COLOR_SPACE_Lab_D65_2: return Lab::get(IO::getIOs(D65_2)); break; - case cv::ccm::Lab_D50_2: + case cv::ccm::COLOR_SPACE_Lab_D50_2: return Lab::get(IO::getIOs(D50_2)); break; - case cv::ccm::Lab_D65_10: + case cv::ccm::COLOR_SPACE_Lab_D65_10: return Lab::get(IO::getIOs(D65_10)); break; - case cv::ccm::Lab_D50_10: + case cv::ccm::COLOR_SPACE_Lab_D50_10: return Lab::get(IO::getIOs(D50_10)); break; - case cv::ccm::Lab_A_2: + case cv::ccm::COLOR_SPACE_Lab_A_2: return Lab::get(IO::getIOs(A_2)); break; - case cv::ccm::Lab_A_10: + case cv::ccm::COLOR_SPACE_Lab_A_10: return Lab::get(IO::getIOs(A_10)); break; - case cv::ccm::Lab_D55_2: + case cv::ccm::COLOR_SPACE_Lab_D55_2: return Lab::get(IO::getIOs(D55_2)); break; - case cv::ccm::Lab_D55_10: + case cv::ccm::COLOR_SPACE_Lab_D55_10: return Lab::get(IO::getIOs(D55_10)); break; - case cv::ccm::Lab_D75_2: + case cv::ccm::COLOR_SPACE_Lab_D75_2: return Lab::get(IO::getIOs(D75_2)); break; - case cv::ccm::Lab_D75_10: + case cv::ccm::COLOR_SPACE_Lab_D75_10: return Lab::get(IO::getIOs(D75_10)); break; - case cv::ccm::Lab_E_2: + case cv::ccm::COLOR_SPACE_Lab_E_2: return Lab::get(IO::getIOs(E_2)); break; - case cv::ccm::Lab_E_10: + case cv::ccm::COLOR_SPACE_Lab_E_10: return Lab::get(IO::getIOs(E_10)); break; default: diff --git a/modules/mcc/src/colorspace.hpp b/modules/mcc/src/colorspace.hpp index c4859d97bed..1983951c282 100644 --- a/modules/mcc/src/colorspace.hpp +++ b/modules/mcc/src/colorspace.hpp @@ -365,11 +365,6 @@ class Lab : public ColorSpace Mat tosrc(Mat& src); }; -/** @brief Define Lab_D65_2 and Lab_D50_2. -*/ -const Lab Lab_D65_2_CS(IO::getIOs(D65_2)); -const Lab Lab_D50_2_CS(IO::getIOs(D50_2)); - class GetCS { public: diff --git a/modules/mcc/src/distance.cpp b/modules/mcc/src/distance.cpp index cd6738259b5..24e2fdf1412 100644 --- a/modules/mcc/src/distance.cpp +++ b/modules/mcc/src/distance.cpp @@ -196,21 +196,21 @@ Mat distance(Mat src, Mat ref, DISTANCE_TYPE distance_type) { switch (distance_type) { - case cv::ccm::CIE76: + case cv::ccm::DISTANCE_CIE76: return distanceWise(src, ref, deltaCIE76); - case cv::ccm::CIE94_GRAPHIC_ARTS: + case cv::ccm::DISTANCE_CIE94_GRAPHIC_ARTS: return distanceWise(src, ref, deltaCIE94GraphicArts); - case cv::ccm::CIE94_TEXTILES: + case cv::ccm::DISTANCE_CIE94_TEXTILES: return distanceWise(src, ref, deltaCIE94Textiles); - case cv::ccm::CIE2000: + case cv::ccm::DISTANCE_CIE2000: return distanceWise(src, ref, deltaCIEDE2000); - case cv::ccm::CMC_1TO1: + case cv::ccm::DISTANCE_CMC_1TO1: return distanceWise(src, ref, deltaCMC1To1); - case cv::ccm::CMC_2TO1: + case cv::ccm::DISTANCE_CMC_2TO1: return distanceWise(src, ref, deltaCMC2To1); - case cv::ccm::RGB: + case cv::ccm::DISTANCE_RGB: return distanceWise(src, ref, deltaCIE76); - case cv::ccm::RGBL: + case cv::ccm::DISTANCE_RGBL: return distanceWise(src, ref, deltaCIE76); default: throw std::invalid_argument { "Wrong distance_type!" }; diff --git a/modules/mcc/src/linearize.cpp b/modules/mcc/src/linearize.cpp index 02f221ef394..79231eef887 100644 --- a/modules/mcc/src/linearize.cpp +++ b/modules/mcc/src/linearize.cpp @@ -101,22 +101,22 @@ std::shared_ptr getLinear(double gamma, int deg, Mat src, Color dst, Mat std::shared_ptr p = std::make_shared(); switch (linear_type) { - case cv::ccm::IDENTITY_: + case cv::ccm::LINEARIZATION_IDENTITY: p.reset(new LinearIdentity()); break; - case cv::ccm::GAMMA: + case cv::ccm::LINEARIZATION_GAMMA: p.reset(new LinearGamma(gamma)); break; - case cv::ccm::COLORPOLYFIT: + case cv::ccm::LINEARIZATION_COLORPOLYFIT: p.reset(new LinearColor(deg, src, dst, mask, cs)); break; - case cv::ccm::COLORLOGPOLYFIT: + case cv::ccm::LINEARIZATION_COLORLOGPOLYFIT: p.reset(new LinearColor(deg, src, dst, mask, cs)); break; - case cv::ccm::GRAYPOLYFIT: + case cv::ccm::LINEARIZATION_GRAYPOLYFIT: p.reset(new LinearGray(deg, src, dst, mask, cs)); break; - case cv::ccm::GRAYLOGPOLYFIT: + case cv::ccm::LINEARIZATION_GRAYLOGPOLYFIT: p.reset(new LinearGray(deg, src, dst, mask, cs)); break; default: diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index 3b8ed663241..ac510cf36ea 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -51,48 +51,48 @@ Here are the parameters for ColorCorrectionModel If the color type is some RGB, the format is RGB not BGR; Supported Color Space: Supported list of RGB color spaces: - sRGB; - AdobeRGB; - WideGamutRGB; - ProPhotoRGB; - DCI_P3_RGB; - AppleRGB; - REC_709_RGB; - REC_2020_RGB; + COLOR_SPACE_sRGB; + COLOR_SPACE_AdobeRGB; + COLOR_SPACE_WideGamutRGB; + COLOR_SPACE_ProPhotoRGB; + COLOR_SPACE_DCI_P3_RGB; + COLOR_SPACE_AppleRGB; + COLOR_SPACE_REC_709_RGB; + COLOR_SPACE_REC_2020_RGB; Supported list of linear RGB color spaces: - sRGBL; - AdobeRGBL; - WideGamutRGBL; - ProPhotoRGBL; - DCI_P3_RGBL; - AppleRGBL; - REC_709_RGBL; - REC_2020_RGBL; + COLOR_SPACE_sRGBL; + COLOR_SPACE_AdobeRGBL; + COLOR_SPACE_WideGamutRGBL; + COLOR_SPACE_ProPhotoRGBL; + COLOR_SPACE_DCI_P3_RGBL; + COLOR_SPACE_AppleRGBL; + COLOR_SPACE_REC_709_RGBL; + COLOR_SPACE_REC_2020_RGBL; Supported list of non-RGB color spaces: - Lab_D50_2; - Lab_D65_2; - XYZ_D50_2; - XYZ_D65_2; - XYZ_D65_10; - XYZ_D50_10; - XYZ_A_2; - XYZ_A_10; - XYZ_D55_2; - XYZ_D55_10; - XYZ_D75_2; - XYZ_D75_10; - XYZ_E_2; - XYZ_E_10; - Lab_D65_10; - Lab_D50_10; - Lab_A_2; - Lab_A_10; - Lab_D55_2; - Lab_D55_10; - Lab_D75_2; - Lab_D75_10; - Lab_E_2; - Lab_E_10; + COLOR_SPACE_Lab_D50_2; + COLOR_SPACE_Lab_D65_2; + COLOR_SPACE_XYZ_D50_2; + COLOR_SPACE_XYZ_D65_2; + COLOR_SPACE_XYZ_D65_10; + COLOR_SPACE_XYZ_D50_10; + COLOR_SPACE_XYZ_A_2; + COLOR_SPACE_XYZ_A_10; + COLOR_SPACE_XYZ_D55_2; + COLOR_SPACE_XYZ_D55_10; + COLOR_SPACE_XYZ_D75_2; + COLOR_SPACE_XYZ_D75_10; + COLOR_SPACE_XYZ_E_2; + COLOR_SPACE_XYZ_E_10; + COLOR_SPACE_Lab_D65_10; + COLOR_SPACE_Lab_D50_10; + COLOR_SPACE_Lab_A_2; + COLOR_SPACE_Lab_A_10; + COLOR_SPACE_Lab_D55_2; + COLOR_SPACE_Lab_D55_10; + COLOR_SPACE_Lab_D75_2; + COLOR_SPACE_Lab_D75_10; + COLOR_SPACE_Lab_E_2; + COLOR_SPACE_Lab_E_10; ``` From 5542747e261b3b49cd7b03d3598b325602222d84 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Fri, 20 Nov 2020 16:15:44 +0800 Subject: [PATCH 64/71] update codes using cv_Error --- modules/mcc/src/ccm.cpp | 8 +++----- modules/mcc/src/color.cpp | 4 ++-- modules/mcc/src/colorspace.cpp | 16 +++++++++------- modules/mcc/src/colorspace.hpp | 25 ++++++++----------------- modules/mcc/src/distance.cpp | 2 +- modules/mcc/src/linearize.cpp | 2 +- modules/mcc/src/linearize.hpp | 1 - modules/mcc/src/operations.hpp | 4 ++-- modules/mcc/src/utils.cpp | 2 +- modules/mcc/src/utils.hpp | 6 +++--- 10 files changed, 30 insertions(+), 40 deletions(-) diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 82a6a125efc..03bf06633f0 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -80,13 +80,11 @@ class ColorCorrectionModel::Impl void calWeightsMasks(Mat weights_list, double weights_coeff, Mat saturate_mask); /** @brief Fitting nonlinear - optimization initial value by white balance. - see CCM.pdf for details. @return the output array, type of Mat */ void initialWhiteBalance(void); /** @brief Fitting nonlinear-optimization initial value by least square. - see CCM.pdf for details @param fit if fit is True, return optimalization for rgbl distance function. */ void initialLeastSquare(bool fit = false); @@ -170,7 +168,7 @@ Mat ColorCorrectionModel::Impl::prepare(const Mat& inp) return arr_out; } default: - throw std::invalid_argument { "Wrong ccm_type!" }; + CV_Error(Error::StsBadArg, "Wrong ccm_type!"); break; } } @@ -287,7 +285,7 @@ Mat ColorCorrectionModel::infer(const Mat& img, bool islinear) { if (!p->ccm.data) { - throw "No CCM values!"; + CV_Error(Error::StsBadArg, "No CCM values!" ); } Mat img_lin = (p->linear)->linearize(img); Mat img_ccm(img_lin.size(), img_lin.type()); @@ -408,7 +406,7 @@ void ColorCorrectionModel::run() p->initialLeastSquare(); break; default: - throw std::invalid_argument { "Wrong initial_methoddistance_type!" }; + CV_Error(Error::StsBadArg, "Wrong initial_methoddistance_type!" ); break; } break; diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index 76d35f65d4c..08da07f2a24 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -31,7 +31,7 @@ namespace cv { namespace ccm { Color::Color() : colors(Mat()) - , cs(*new ColorSpace()) + , cs(*std::make_shared()) {} Color::Color(Mat colors_, enum COLOR_SPACE cs_) : colors(colors_) @@ -123,7 +123,7 @@ Mat Color::diff(Color& other, IO io, DISTANCE_TYPE method) case cv::ccm::DISTANCE_RGBL: return distance(to(*cs.l).colors, other.to(*cs.l).colors, method); default: - throw std::invalid_argument { "Wrong method!" }; + CV_Error(Error::StsBadArg, "Wrong method!" ); break; } } diff --git a/modules/mcc/src/colorspace.cpp b/modules/mcc/src/colorspace.cpp index dd5eda60520..499676c7974 100644 --- a/modules/mcc/src/colorspace.cpp +++ b/modules/mcc/src/colorspace.cpp @@ -112,7 +112,6 @@ void RGBBase_::bind(RGBBase_& rgbl) } /* @brief Calculation of M_RGBL2XYZ_base. - * see ColorSpace.pdf for details. */ void RGBBase_::calM() { @@ -197,7 +196,6 @@ double sRGBBase_::toLFuncEW(double& x) } /* @brief Linearization. - * see ColorSpace.pdf for details. * @param rgb the input array, type of cv::Mat. * @return the output array, type of cv::Mat. */ @@ -226,7 +224,6 @@ double sRGBBase_::fromLFuncEW(double& x) } /* @brief Delinearization. - * see ColorSpace.pdf for details. * @param rgbl the input array, type of cv::Mat. * @return the output array, type of cv::Mat. */ @@ -353,9 +350,14 @@ void REC_2020_RGB_::setParameter() gamma = 1 / 0.45; } -/* @brief Enum of the possible types of CAMs. - */ - +static std::map, Mat> cams; +static const Mat Von_Kries = (Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); +static const Mat Bradford = (Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); +static const std::map> MAs = { + { IDENTITY, { Mat::eye(Size(3, 3), CV_64FC1), Mat::eye(Size(3, 3), CV_64FC1) } }, + { VON_KRIES, { Von_Kries, Von_Kries.inv() } }, + { BRADFORD, { Bradford, Bradford.inv() } } +}; /* @brief XYZ color space. * Chromatic adaption matrices. */ @@ -574,7 +576,7 @@ std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) case cv::ccm::COLOR_SPACE_AppleRGBL: case cv::ccm::COLOR_SPACE_REC_709_RGBL: case cv::ccm::COLOR_SPACE_REC_2020_RGBL: - CV_Error(Error::StsBadArg, "linear RGB colorspaces are not supported, you should assigned as normal rgb color space"); + CV_Error(Error::StsBadArg, "linear RGB colorspaces are not supported, you should assigned as normal RGB color space"); break; default: diff --git a/modules/mcc/src/colorspace.hpp b/modules/mcc/src/colorspace.hpp index 1983951c282..38c2e255b6f 100644 --- a/modules/mcc/src/colorspace.hpp +++ b/modules/mcc/src/colorspace.hpp @@ -112,7 +112,6 @@ class RGBBase_ : public ColorSpace virtual void setParameter() {}; /** @brief Calculation of M_RGBL2XYZ_base. - see ColorSpace.pdf for details. */ virtual void calM(); @@ -157,7 +156,6 @@ class sRGBBase_ : public RGBBase_ private: /** @brief linearization parameters - see ColorSpace.pdf for details; */ virtual void calLinear() CV_OVERRIDE; /** @brief Used by toLFunc. @@ -165,7 +163,6 @@ class sRGBBase_ : public RGBBase_ double toLFuncEW(double& x); /** @brief Linearization. - see ColorSpace.pdf for details. @param rgb the input array, type of cv::Mat. @return the output array, type of cv::Mat. */ @@ -176,7 +173,6 @@ class sRGBBase_ : public RGBBase_ double fromLFuncEW(double& x); /** @brief Delinearization. - see ColorSpace.pdf for details. @param rgbl the input array, type of cv::Mat. @return the output array, type of cv::Mat. */ @@ -297,14 +293,14 @@ enum CAM BRADFORD }; -static std::map, Mat> cams; -static const Mat Von_Kries = (Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); -static const Mat Bradford = (Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); -static const std::map> MAs = { - { IDENTITY, { Mat::eye(Size(3, 3), CV_64FC1), Mat::eye(Size(3, 3), CV_64FC1) } }, - { VON_KRIES, { Von_Kries, Von_Kries.inv() } }, - { BRADFORD, { Bradford, Bradford.inv() } } -}; +// static std::map, Mat> cams; +// static const Mat Von_Kries = (Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); +// static const Mat Bradford = (Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); +// static const std::map> MAs = { +// { IDENTITY, { Mat::eye(Size(3, 3), CV_64FC1), Mat::eye(Size(3, 3), CV_64FC1) } }, +// { VON_KRIES, { Von_Kries, Von_Kries.inv() } }, +// { BRADFORD, { Bradford, Bradford.inv() } } +// }; /** @brief XYZ color space. Chromatic adaption matrices. @@ -328,11 +324,6 @@ class XYZ : public ColorSpace Mat cam_(IO sio, IO dio, CAM method = BRADFORD) const; }; -/** @brief Define XYZ_D65_2 and XYZ_D50_2. -*/ -const XYZ XYZ_D65_2_CS(IO::getIOs(D65_2)); -const XYZ XYZ_D50_2_CS(IO::getIOs(D50_2)); - /** @brief Lab color space. */ class Lab : public ColorSpace diff --git a/modules/mcc/src/distance.cpp b/modules/mcc/src/distance.cpp index 24e2fdf1412..fa535b88477 100644 --- a/modules/mcc/src/distance.cpp +++ b/modules/mcc/src/distance.cpp @@ -213,7 +213,7 @@ Mat distance(Mat src, Mat ref, DISTANCE_TYPE distance_type) case cv::ccm::DISTANCE_RGBL: return distanceWise(src, ref, deltaCIE76); default: - throw std::invalid_argument { "Wrong distance_type!" }; + CV_Error(Error::StsBadArg, "Wrong distance_type!" ); break; } }; diff --git a/modules/mcc/src/linearize.cpp b/modules/mcc/src/linearize.cpp index 79231eef887..3a48a560eb8 100644 --- a/modules/mcc/src/linearize.cpp +++ b/modules/mcc/src/linearize.cpp @@ -120,7 +120,7 @@ std::shared_ptr getLinear(double gamma, int deg, Mat src, Color dst, Mat p.reset(new LinearGray(deg, src, dst, mask, cs)); break; default: - throw std::invalid_argument { "Wrong linear_type!" }; + CV_Error(Error::StsBadArg, "Wrong linear_type!" ); break; } return p; diff --git a/modules/mcc/src/linearize.hpp b/modules/mcc/src/linearize.hpp index e762ee4b702..a703b5c5293 100644 --- a/modules/mcc/src/linearize.hpp +++ b/modules/mcc/src/linearize.hpp @@ -48,7 +48,6 @@ class Polyfit https://en.wikipedia.org/wiki/Polynomial_regression polynomial: yi = a0 + a1*xi + a2*xi^2 + ... + an*xi^deg (i = 1,2,...,n) and deduct: Ax = y - See linear.pdf for details */ Polyfit(Mat x, Mat y, int deg); virtual ~Polyfit() {}; diff --git a/modules/mcc/src/operations.hpp b/modules/mcc/src/operations.hpp index db7bd7441de..475ffcc9eeb 100644 --- a/modules/mcc/src/operations.hpp +++ b/modules/mcc/src/operations.hpp @@ -76,7 +76,6 @@ class Operations { public: std::vector ops; - Operations() : ops {} {}; Operations(std::initializer_list op) @@ -92,7 +91,8 @@ class Operations Mat run(Mat abc); static Operations get_IDENTITY_OPS() { - return Operations { Operation::get_IDENTITY_OP() }; + Operation Operation_op = Operation::get_IDENTITY_OP(); + return Operations { Operation_op }; } }; diff --git a/modules/mcc/src/utils.cpp b/modules/mcc/src/utils.cpp index 1bfc4204598..3a0128b6ef6 100644 --- a/modules/mcc/src/utils.cpp +++ b/modules/mcc/src/utils.cpp @@ -76,7 +76,7 @@ Mat maskCopyTo(const Mat& src, const Mat& mask) break; } default: - throw std::invalid_argument { "Wrong channel!" }; + CV_Error(Error::StsBadArg, "Wrong channel!" ); break; } return dst; diff --git a/modules/mcc/src/utils.hpp b/modules/mcc/src/utils.hpp index a9810a017df..02570ca0184 100644 --- a/modules/mcc/src/utils.hpp +++ b/modules/mcc/src/utils.hpp @@ -35,7 +35,7 @@ namespace ccm { double gammaCorrection_(const double& element, const double& gamma); -/** @brief gamma correction ,see ColorSpace.pdf for details. +/** @brief gamma correction. \f[ C_l=C_n^{\gamma},\qquad C_n\ge0\\ C_l=-(-C_n)^{\gamma},\qquad C_n<0\\\\ @@ -67,7 +67,7 @@ Mat multiple(const Mat& xyz, const Mat& ccm); Mat saturate(Mat& src, const double& low, const double& up); /** @brief rgb2gray it is an approximation grayscale function for relative RGB - color space, see Miscellaneous.pdf for details; + color space @param rgb the input array,type of Mat. */ Mat rgb2gray(const Mat& rgb); @@ -106,7 +106,7 @@ Mat elementWise(const Mat& src, F&& lambda) break; } default: - throw std::invalid_argument { "Wrong channel!" }; + CV_Error(Error::StsBadArg, "Wrong channel!" ); break; } return dst; From f7aabff4f2be5ac6a63e1dea9bb08fccad5a164b Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Fri, 20 Nov 2020 19:15:50 +0800 Subject: [PATCH 65/71] update test_ccm file --- modules/mcc/include/opencv2/mcc/ccm.hpp | 4 ++++ .../mcc/samples/color_correction_model.cpp | 6 ++--- modules/mcc/src/ccm.cpp | 23 +++++++++++++++---- modules/mcc/src/colorspace.cpp | 22 +++++++++--------- modules/mcc/src/colorspace.hpp | 10 ++------ 5 files changed, 38 insertions(+), 27 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 37fbe962910..7a6fa67b6fa 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -498,6 +498,10 @@ class CV_EXPORTS_W ColorCorrectionModel CV_WRAP Mat getCCM() const; CV_WRAP double getLoss() const; + CV_WRAP Mat get_src_rgbl() const; + CV_WRAP Mat get_dst_rgbl() const; + CV_WRAP Mat get_mask() const; + CV_WRAP Mat get_weights() const; /** @brief Infer using fitting ccm. @param img the input image. diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp index a44655649b3..b242bcaf6f9 100644 --- a/modules/mcc/samples/color_correction_model.cpp +++ b/modules/mcc/samples/color_correction_model.cpp @@ -24,6 +24,7 @@ const char *keys = int main(int argc, char *argv[]) { + // ---------------------------------------------------------- // Scroll down a bit (~40 lines) to find actual relevant code // ---------------------------------------------------------- @@ -77,7 +78,7 @@ int main(int argc, char *argv[]) //compte color correction matrix //! [get_ccm_Matrix] - ColorCorrectionModel model1(src, Vinyl); + ColorCorrectionModel model1(src, COLORCHECKER_Vinyl); model1.run(); Mat ccm = model1.getCCM(); std::cout<<"ccm "<infer(img_, islinear); Mat calibratedImage= model1.infer(img_); Mat out_ = calibratedImage * out_size; //! [make_color_correction] diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 03bf06633f0..81baf659d05 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -52,6 +52,7 @@ class ColorCorrectionModel::Impl LINEAR_TYPE linear_type; Mat weights; + Mat weights_list; Mat ccm; Mat ccm0; double gamma; @@ -173,12 +174,12 @@ Mat ColorCorrectionModel::Impl::prepare(const Mat& inp) } } -void ColorCorrectionModel::Impl::calWeightsMasks(Mat weights_list, double weights_coeff_, Mat saturate_mask) +void ColorCorrectionModel::Impl::calWeightsMasks(Mat weights_list_, double weights_coeff_, Mat saturate_mask) { // weights - if (!weights_list.empty()) + if (!weights_list_.empty()) { - weights = weights_list; + weights = weights_list_; } else if (weights_coeff_ != 0) { @@ -359,7 +360,7 @@ void ColorCorrectionModel::setSaturatedThreshold(double lower, double upper) } void ColorCorrectionModel::setWeightsList(Mat weights_list) { - p->weights = weights_list; + p->weights_list = weights_list; } void ColorCorrectionModel::setWeightCoeff(double weights_coeff) { @@ -382,7 +383,7 @@ void ColorCorrectionModel::run() Mat saturate_mask = saturate(p->src, p->saturated_threshold[0], p->saturated_threshold[1]); p->linear = getLinear(p->gamma, p->deg, p->src, *(p->dst), saturate_mask, (p->cs), p->linear_type); - p->calWeightsMasks(p->weights, p->weights_coeff, saturate_mask); + p->calWeightsMasks(p->weights_list, p->weights_coeff, saturate_mask); p->src_rgbl = p->linear->linearize(maskCopyTo(p->src, p->mask)); p->dst->colors = maskCopyTo(p->dst->colors, p->mask); p->dst_rgbl = p->dst->to(*(p->cs.l)).colors; @@ -421,5 +422,17 @@ double ColorCorrectionModel::getLoss() const { return p->loss; } +Mat ColorCorrectionModel::get_src_rgbl() const{ + return p->src_rgbl; +} +Mat ColorCorrectionModel::get_dst_rgbl() const{ + return p->dst_rgbl; +} +Mat ColorCorrectionModel::get_mask() const{ + return p->mask; +} +Mat ColorCorrectionModel::get_weights() const{ + return p->weights; +} } } // namespace cv::ccm diff --git a/modules/mcc/src/colorspace.cpp b/modules/mcc/src/colorspace.cpp index 499676c7974..f7a17846aa2 100644 --- a/modules/mcc/src/colorspace.cpp +++ b/modules/mcc/src/colorspace.cpp @@ -350,17 +350,6 @@ void REC_2020_RGB_::setParameter() gamma = 1 / 0.45; } -static std::map, Mat> cams; -static const Mat Von_Kries = (Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); -static const Mat Bradford = (Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); -static const std::map> MAs = { - { IDENTITY, { Mat::eye(Size(3, 3), CV_64FC1), Mat::eye(Size(3, 3), CV_64FC1) } }, - { VON_KRIES, { Von_Kries, Von_Kries.inv() } }, - { BRADFORD, { Bradford, Bradford.inv() } } -}; -/* @brief XYZ color space. - * Chromatic adaption matrices. - */ Operations XYZ::cam(IO dio, CAM method) { return (io == dio) ? Operations() @@ -376,6 +365,17 @@ Mat XYZ::cam_(IO sio, IO dio, CAM method) const { return cams[std::make_tuple(dio, sio, method)]; } + /* @brief XYZ color space. + * Chromatic adaption matrices. + */ + + static const Mat Von_Kries = (Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); + static const Mat Bradford = (Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); + static const std::map> MAs = { + { IDENTITY, { Mat::eye(Size(3, 3), CV_64FC1), Mat::eye(Size(3, 3), CV_64FC1) } }, + { VON_KRIES, { Von_Kries, Von_Kries.inv() } }, + { BRADFORD, { Bradford, Bradford.inv() } } + }; // Function from http://www.brucelindbloom.com/index.html?ColorCheckerRGB.html. Mat XYZws = Mat(getIlluminants(dio)); diff --git a/modules/mcc/src/colorspace.hpp b/modules/mcc/src/colorspace.hpp index 38c2e255b6f..1db3bd9044d 100644 --- a/modules/mcc/src/colorspace.hpp +++ b/modules/mcc/src/colorspace.hpp @@ -293,14 +293,8 @@ enum CAM BRADFORD }; -// static std::map, Mat> cams; -// static const Mat Von_Kries = (Mat_(3, 3) << 0.40024, 0.7076, -0.08081, -0.2263, 1.16532, 0.0457, 0., 0., 0.91822); -// static const Mat Bradford = (Mat_(3, 3) << 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); -// static const std::map> MAs = { -// { IDENTITY, { Mat::eye(Size(3, 3), CV_64FC1), Mat::eye(Size(3, 3), CV_64FC1) } }, -// { VON_KRIES, { Von_Kries, Von_Kries.inv() } }, -// { BRADFORD, { Bradford, Bradford.inv() } } -// }; +static std::map, Mat> cams; + /** @brief XYZ color space. Chromatic adaption matrices. From ca5c4d50b88ec62fc2db0deef4b1ff80ada8b257 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Fri, 20 Nov 2020 21:11:55 +0800 Subject: [PATCH 66/71] update test_ccm file --- modules/mcc/src/operations.hpp | 6 +- modules/mcc/test/test_ccm.cpp | 167 +++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+), 3 deletions(-) create mode 100644 modules/mcc/test/test_ccm.cpp diff --git a/modules/mcc/src/operations.hpp b/modules/mcc/src/operations.hpp index 475ffcc9eeb..ae3b39b6019 100644 --- a/modules/mcc/src/operations.hpp +++ b/modules/mcc/src/operations.hpp @@ -89,10 +89,10 @@ class Operations /** @brief run operations to make color conversion */ Mat run(Mat abc); - static Operations get_IDENTITY_OPS() + static const Operations& get_IDENTITY_OPS() { - Operation Operation_op = Operation::get_IDENTITY_OP(); - return Operations { Operation_op }; + static Operations Operation_op {Operation::get_IDENTITY_OP()}; + return Operation_op; } }; diff --git a/modules/mcc/test/test_ccm.cpp b/modules/mcc/test/test_ccm.cpp new file mode 100644 index 00000000000..4e156ff088b --- /dev/null +++ b/modules/mcc/test/test_ccm.cpp @@ -0,0 +1,167 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include "test_precomp.hpp" + +#include + +namespace opencv_test +{ +namespace +{ + +Mat s = (Mat_(24, 1) << + Vec3d(214.11, 98.67, 37.97), + Vec3d(231.94, 153.1, 85.27), + Vec3d(204.08, 143.71, 78.46), + Vec3d(190.58, 122.99, 30.84), + Vec3d(230.93, 148.46, 100.84), + Vec3d(228.64, 206.97, 97.5), + Vec3d(229.09, 137.07, 55.29), + Vec3d(189.21, 111.22, 92.66), + Vec3d(223.5, 96.42, 75.45), + Vec3d(201.82, 69.71, 50.9), + Vec3d(240.52, 196.47, 59.3), + Vec3d(235.73, 172.13, 54.), + Vec3d(131.6, 75.04, 68.86), + Vec3d(189.04, 170.43, 42.05), + Vec3d(222.23, 74., 71.95), + Vec3d(241.01, 199.1, 61.15), + Vec3d(224.99, 101.4, 100.24), + Vec3d(174.58, 152.63, 91.52), + Vec3d(248.06, 227.69, 140.5), + Vec3d(241.15, 201.38, 115.58), + Vec3d(236.49, 175.87, 88.86), + Vec3d(212.19, 133.49, 54.79), + Vec3d(181.17, 102.94, 36.18), + Vec3d(115.1, 53.77, 15.23)); + +TEST(CV_ccmRunColorCorrection, test_model) +{ + + ColorCorrectionModel model(s / 255, COLORCHECKER_Macbeth); + model.run(); + Mat src_rgbl = (Mat_(24, 1) << + Vec3d(0.68078957, 0.12382801, 0.01514889), + Vec3d(0.81177942, 0.32550452, 0.089818), + Vec3d(0.61259378, 0.2831933, 0.07478902), + Vec3d(0.52696493, 0.20105976, 0.00958657), + Vec3d(0.80402284, 0.30419523, 0.12989841), + Vec3d(0.78658646, 0.63184111, 0.12062068), + Vec3d(0.78999637, 0.25520249, 0.03462853), + Vec3d(0.51866697, 0.16114393, 0.1078387), + Vec3d(0.74820768, 0.11770076, 0.06862177), + Vec3d(0.59776825, 0.05765816, 0.02886627), + Vec3d(0.8793145, 0.56346033, 0.0403954), + Vec3d(0.84124847, 0.42120746, 0.03287592), + Vec3d(0.23333214, 0.06780408, 0.05612276), + Vec3d(0.5176423, 0.41210976, 0.01896255), + Vec3d(0.73888613, 0.06575388, 0.06181293), + Vec3d(0.88326036, 0.58018751, 0.04321991), + Vec3d(0.75922531, 0.13149072, 0.1282041), + Vec3d(0.4345097, 0.32331019, 0.10494139), + Vec3d(0.94110142, 0.77941419, 0.26946323), + Vec3d(0.88438952, 0.5949049 , 0.17536928), + Vec3d(0.84722687, 0.44160449, 0.09834799), + Vec3d(0.66743106, 0.24076803, 0.03394333), + Vec3d(0.47141286, 0.13592419, 0.01362205), + Vec3d(0.17377101, 0.03256864, 0.00203026)); + ASSERT_MAT_NEAR(src_rgbl, model.get_src_rgbl(), 1e-4); + + Mat dst_rgbl = (Mat_(24, 1) << + Vec3d(0.17303173, 0.08211037, 0.05672686), + Vec3d(0.56832031, 0.29269488, 0.21835529), + Vec3d(0.10365019, 0.19588357, 0.33140475), + Vec3d(0.10159676, 0.14892193, 0.05188294), + Vec3d(0.22159627, 0.21584476, 0.43461196), + Vec3d(0.10806379, 0.51437196, 0.41264213), + Vec3d(0.74736423, 0.20062878, 0.02807988), + Vec3d(0.05757947, 0.10516793, 0.40296109), + Vec3d(0.56676218, 0.08424805, 0.11969461), + Vec3d(0.11099515, 0.04230796, 0.14292554), + Vec3d(0.34546869, 0.50872001, 0.04944204), + Vec3d(0.79461323, 0.35942459, 0.02051968), + Vec3d(0.01710416, 0.05022043, 0.29220674), + Vec3d(0.05598012, 0.30021149, 0.06871162), + Vec3d(0.45585457, 0.03033727, 0.04085654), + Vec3d(0.85737614, 0.56757335, 0.0068503), + Vec3d(0.53348585, 0.08861148, 0.30750446), + Vec3d(-0.0374061, 0.24699498, 0.40041217), + Vec3d(0.91262695, 0.91493909, 0.89367049), + Vec3d(0.57981916, 0.59200418, 0.59328881), + Vec3d(0.35490581, 0.36544831, 0.36755375), + Vec3d(0.19007357, 0.19186587, 0.19308397), + Vec3d(0.08529188, 0.08887994, 0.09257601), + Vec3d(0.0303193, 0.03113818, 0.03274845)); + ASSERT_MAT_NEAR(dst_rgbl, model.get_dst_rgbl(), 1e-4); + + Mat mask = Mat::ones(24, 1, CV_8U); + ASSERT_MAT_NEAR(model.get_mask(), mask, 0.0); + + + Mat ccm = (Mat_(3, 3) << + 0.37408717, 0.02066172, 0.05796725, + 0.12684056, 0.77364991, -0.01566532, + -0.27464866, 0.00652140, 2.74593262); + ASSERT_MAT_NEAR(model.getCCM(), ccm, 1e-4); +} +TEST(CV_ccmRunColorCorrection, test_masks_weights_1) +{ + Mat weights_list_ = (Mat_(24, 1) << + 1.1, 0, 0, 1.2, 0, 0, + 1.3, 0, 0, 1.4, 0, 0, + 0.5, 0, 0, 0.6, 0, 0, + 0.7, 0, 0, 0.8, 0, 0); + ColorCorrectionModel model1(s / 255,COLORCHECKER_Macbeth); + model1.setColorSpace(COLOR_SPACE_sRGB); + model1.setCCM_TYPE(CCM_3x3); + model1.setDistance(DISTANCE_CIE2000); + model1.setLinear(LINEARIZATION_GAMMA); + model1.setLinearGamma(2.2); + model1.setLinearDegree(3); + model1.setSaturatedThreshold(0, 0.98); + model1.setWeightsList(weights_list_); + model1.setWeightCoeff(1.5); + model1.run(); + Mat weights = (Mat_(8, 1) << + 1.15789474, 1.26315789, 1.36842105, 1.47368421, + 0.52631579, 0.63157895, 0.73684211, 0.84210526); + ASSERT_MAT_NEAR(model1.get_weights(), weights, 1e-4); + + Mat mask = (Mat_(24, 1) << + true, false, false, true, false, false, + true, false, false, true, false, false, + true, false, false, true, false, false, + true, false, false, true, false, false); + ASSERT_MAT_NEAR(model1.get_mask(), mask, 0.0); +} + +TEST(CV_ccmRunColorCorrection, test_masks_weights_2) +{ + ColorCorrectionModel model2(s / 255, COLORCHECKER_Macbeth); + model2.setCCM_TYPE(CCM_3x3); + model2.setDistance(DISTANCE_CIE2000); + model2.setLinear(LINEARIZATION_GAMMA); + model2.setLinearGamma(2.2); + model2.setLinearDegree(3); + model2.setSaturatedThreshold(0.05, 0.93); + model2.setWeightsList(Mat()); + model2.setWeightCoeff(1.5); + model2.run(); + Mat weights = (Mat_(20, 1) << + 0.65554256, 1.49454705, 1.00499244, 0.79735434, 1.16327759, + 1.68623868, 1.37973155, 0.73213388, 1.0169629, 0.47430246, + 1.70312161, 0.45414218, 1.15910007, 0.7540434, 1.05049802, + 1.04551645, 1.54082353, 1.02453421, 0.6015915, 0.26154558); + ASSERT_MAT_NEAR(model2.get_weights(), weights, 1e-4); + + Mat mask = (Mat_(24, 1) << + true, true, true, true, true, true, + true, true, true, true, false, true, + true, true, true, false, true, true, + false, false, true, true, true, true); + ASSERT_MAT_NEAR(model2.get_mask(), mask, 0.0); +} +} // namespace +} // namespace opencv_test \ No newline at end of file From 92298dd32b7429a398efe911f1284ea9b465e450 Mon Sep 17 00:00:00 2001 From: shanchenqi <582533558@qq.com> Date: Sat, 21 Nov 2020 09:45:21 +0800 Subject: [PATCH 67/71] update sample --help --- modules/mcc/samples/color_correction_model.cpp | 8 ++++++-- modules/mcc/src/ccm.cpp | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp index b242bcaf6f9..c5772fae532 100644 --- a/modules/mcc/samples/color_correction_model.cpp +++ b/modules/mcc/samples/color_correction_model.cpp @@ -14,7 +14,7 @@ using namespace std; const char *about = "Basic chart detection"; const char *keys = - "{ help h usage ? | | show this message }" + "{ help h | | show this message }" "{t | | chartType: 0-Standard, 1-DigitalSG, 2-Vinyl }" "{v | | Input from video file, if ommited, input comes from camera }" "{ci | 0 | Camera id if input doesnt come from video (-v) }" @@ -31,6 +31,11 @@ int main(int argc, char *argv[]) //! [get_messages_of_image] CommandLineParser parser(argc, argv, keys); parser.about(about); + if (argc==1 || parser.has("help")) + { + parser.printMessage(); + return 0; + } int t = parser.get("t"); int nc = parser.get("nc"); @@ -39,7 +44,6 @@ int main(int argc, char *argv[]) CV_Assert(0 <= t && t <= 2); TYPECHART chartType = TYPECHART(t); - cout << "t: " << t << " , nc: " << nc << ", \nf: " << filepath << endl; if (!parser.check()) { diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 81baf659d05..fdf7fe642b7 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -312,19 +312,19 @@ void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE cs_, Mat col dst.reset(new Color(colors_, *GetCS::get_cs(cs_), colored_)); } ColorCorrectionModel::ColorCorrectionModel(const Mat& src_, CONST_COLOR constcolor) - : p(new Impl) + : p(std::make_shared()) { p->src = src_; p->get_color(constcolor); } ColorCorrectionModel::ColorCorrectionModel(const Mat& src_, Mat colors_, COLOR_SPACE ref_cs_) - : p(new Impl) + : p(std::make_shared()) { p->src = src_; p->get_color(colors_, ref_cs_); } ColorCorrectionModel::ColorCorrectionModel(const Mat& src_, Mat colors_, COLOR_SPACE cs_, Mat colored_) - : p(new Impl) + : p(std::make_shared()) { p->src = src_; p->get_color(colors_, cs_, colored_); From 2d96a306d91d9afa7c1c9fe9854a90af7488e411 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Sun, 22 Nov 2020 16:03:40 +0000 Subject: [PATCH 68/71] mcc: reduce global initializers --- modules/mcc/src/ccm.cpp | 8 ++++---- modules/mcc/src/color.cpp | 6 +++--- modules/mcc/src/colorspace.cpp | 23 ++++++++++++++++++----- modules/mcc/src/colorspace.hpp | 15 ++++++++------- modules/mcc/test/test_ccm.cpp | 5 ++--- 5 files changed, 35 insertions(+), 22 deletions(-) diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index fdf7fe642b7..52160a2ca9d 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -137,7 +137,7 @@ class ColorCorrectionModel::Impl }; ColorCorrectionModel::Impl::Impl() - : cs(*GetCS::get_rgb(COLOR_SPACE_sRGB)) + : cs(*GetCS::getInstance().get_rgb(COLOR_SPACE_sRGB)) , ccm_type(CCM_3x3) , distance(DISTANCE_CIE2000) , linear_type(LINEARIZATION_GAMMA) @@ -305,11 +305,11 @@ void ColorCorrectionModel::Impl::get_color(CONST_COLOR constcolor) } void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE ref_cs_) { - dst.reset(new Color(colors_, *GetCS::get_cs(ref_cs_))); + dst.reset(new Color(colors_, *GetCS::getInstance().get_cs(ref_cs_))); } void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_) { - dst.reset(new Color(colors_, *GetCS::get_cs(cs_), colored_)); + dst.reset(new Color(colors_, *GetCS::getInstance().get_cs(cs_), colored_)); } ColorCorrectionModel::ColorCorrectionModel(const Mat& src_, CONST_COLOR constcolor) : p(std::make_shared()) @@ -332,7 +332,7 @@ ColorCorrectionModel::ColorCorrectionModel(const Mat& src_, Mat colors_, COLOR_S void ColorCorrectionModel::setColorSpace(COLOR_SPACE cs_) { - p->cs = *GetCS::get_rgb(cs_); + p->cs = *GetCS::getInstance().get_rgb(cs_); } void ColorCorrectionModel::setCCM_TYPE(CCM_TYPE ccm_type_) { diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index 08da07f2a24..921d903f8cd 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -35,7 +35,7 @@ Color::Color() {} Color::Color(Mat colors_, enum COLOR_SPACE cs_) : colors(colors_) - , cs(*GetCS::get_cs(cs_)) + , cs(*GetCS::getInstance().get_cs(cs_)) {} Color::Color(Mat colors_, const ColorSpace& cs_, Mat colored_) @@ -47,7 +47,7 @@ Color::Color(Mat colors_, const ColorSpace& cs_, Mat colored_) } Color::Color(Mat colors_, enum COLOR_SPACE cs_, Mat colored_) : colors(colors_) - , cs(*GetCS::get_cs(cs_)) + , cs(*GetCS::getInstance().get_cs(cs_)) , colored(colored_) { grays = ~colored; @@ -79,7 +79,7 @@ Color Color::to(const ColorSpace& other, CAM method, bool save) } Color Color::to(COLOR_SPACE other, CAM method, bool save) { - return to(*GetCS::get_cs(other), method, save); + return to(*GetCS::getInstance().get_cs(other), method, save); } Mat Color::channel(Mat m, int i) diff --git a/modules/mcc/src/colorspace.cpp b/modules/mcc/src/colorspace.cpp index f7a17846aa2..9dfe3f6e125 100644 --- a/modules/mcc/src/colorspace.cpp +++ b/modules/mcc/src/colorspace.cpp @@ -357,6 +357,8 @@ Operations XYZ::cam(IO dio, CAM method) } Mat XYZ::cam_(IO sio, IO dio, CAM method) const { + static std::map, Mat> cams; + if (sio == dio) { return Mat::eye(cv::Size(3, 3), CV_64FC1); @@ -388,15 +390,15 @@ Mat XYZ::cam_(IO sio, IO dio, CAM method) const return M; } -std::map> XYZ::xyz_cs = {}; - std::shared_ptr XYZ::get(IO io) { + static std::map> xyz_cs; + if (xyz_cs.count(io) == 1) { return xyz_cs[io]; } - std::shared_ptr XYZ_CS(new XYZ(io)); + std::shared_ptr XYZ_CS = std::make_shared(io); xyz_cs[io] = XYZ_CS; return xyz_cs[io]; } @@ -454,9 +456,11 @@ Mat Lab::tosrc(Mat& src) return channelWise(src, [this](cv::Vec3d a) -> cv::Vec3d { return tolab(a); }); } -std::map> Lab::lab_cs = {}; + std::shared_ptr Lab::get(IO io) { + static std::map> lab_cs; + if (lab_cs.count(io) == 1) { return lab_cs[io]; @@ -466,7 +470,16 @@ std::shared_ptr Lab::get(IO io) return lab_cs[io]; } -std::map> GetCS::map_cs = {}; +GetCS::GetCS() +{ + // nothing +} + +GetCS& GetCS::getInstance() +{ + static GetCS instance; + return instance; +} std::shared_ptr GetCS::get_rgb(enum COLOR_SPACE cs_name) { diff --git a/modules/mcc/src/colorspace.hpp b/modules/mcc/src/colorspace.hpp index 1db3bd9044d..57b5bc2ff40 100644 --- a/modules/mcc/src/colorspace.hpp +++ b/modules/mcc/src/colorspace.hpp @@ -293,8 +293,6 @@ enum CAM BRADFORD }; -static std::map, Mat> cams; - /** @brief XYZ color space. Chromatic adaption matrices. @@ -305,7 +303,6 @@ class XYZ : public ColorSpace XYZ(IO io_) : ColorSpace(io_, "XYZ", true) {}; Operations cam(IO dio, CAM method = BRADFORD); - static std::map> xyz_cs; static std::shared_ptr get(IO io); private: @@ -323,7 +320,6 @@ class XYZ : public ColorSpace class Lab : public ColorSpace { public: - static std::map> lab_cs; Lab(IO io); static std::shared_ptr get(IO io); @@ -352,10 +348,15 @@ class Lab : public ColorSpace class GetCS { +protected: + std::map> map_cs; + + GetCS(); // singleton, use getInstance() public: - static std::map> map_cs; - static std::shared_ptr get_rgb(enum COLOR_SPACE cs_name); - static std::shared_ptr get_cs(enum COLOR_SPACE cs_name); + static GetCS& getInstance(); + + std::shared_ptr get_rgb(enum COLOR_SPACE cs_name); + std::shared_ptr get_cs(enum COLOR_SPACE cs_name); }; } diff --git a/modules/mcc/test/test_ccm.cpp b/modules/mcc/test/test_ccm.cpp index 4e156ff088b..6682f13845e 100644 --- a/modules/mcc/test/test_ccm.cpp +++ b/modules/mcc/test/test_ccm.cpp @@ -4,8 +4,6 @@ #include "test_precomp.hpp" -#include - namespace opencv_test { namespace @@ -163,5 +161,6 @@ TEST(CV_ccmRunColorCorrection, test_masks_weights_2) false, false, true, true, true, true); ASSERT_MAT_NEAR(model2.get_mask(), mask, 0.0); } + } // namespace -} // namespace opencv_test \ No newline at end of file +} // namespace opencv_test From 6a18da62ec77aa5c439492c96482997793718a8e Mon Sep 17 00:00:00 2001 From: shanchenqi <582533558@qq.com> Date: Mon, 23 Nov 2020 10:38:38 +0800 Subject: [PATCH 69/71] update function naming style --- modules/mcc/include/opencv2/mcc/ccm.hpp | 4 +-- .../mcc/samples/color_correction_model.cpp | 2 +- modules/mcc/src/ccm.cpp | 30 +++++++++---------- modules/mcc/src/color.cpp | 16 +++++----- modules/mcc/src/color.hpp | 6 ++-- modules/mcc/test/test_ccm.cpp | 10 +++---- 6 files changed, 34 insertions(+), 34 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 7a6fa67b6fa..63c3583969a 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -500,8 +500,8 @@ class CV_EXPORTS_W ColorCorrectionModel CV_WRAP double getLoss() const; CV_WRAP Mat get_src_rgbl() const; CV_WRAP Mat get_dst_rgbl() const; - CV_WRAP Mat get_mask() const; - CV_WRAP Mat get_weights() const; + CV_WRAP Mat getMask() const; + CV_WRAP Mat getWeights() const; /** @brief Infer using fitting ccm. @param img the input image. diff --git a/modules/mcc/samples/color_correction_model.cpp b/modules/mcc/samples/color_correction_model.cpp index c5772fae532..20df704370e 100644 --- a/modules/mcc/samples/color_correction_model.cpp +++ b/modules/mcc/samples/color_correction_model.cpp @@ -76,7 +76,7 @@ int main(int argc, char *argv[]) Ptr cdraw = CCheckerDraw::create(checker); cdraw->draw(image); Mat chartsRGB = checker->getChartsRGB(); - Mat src = chartsRGB.col(1).clone().reshape(3, 18); + Mat src = chartsRGB.col(1).clone().reshape(3, chartsRGB.rows/3); src /= 255.0; //! [create] diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index 52160a2ca9d..ad1d5a0d42e 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -78,7 +78,7 @@ class ColorCorrectionModel::Impl @param weights_coeff type of double. @param saturate_mask the input array, type of cv::Mat. */ - void calWeightsMasks(Mat weights_list, double weights_coeff, Mat saturate_mask); + void calWeightsMasks(const Mat& weights_list, double weights_coeff, Mat saturate_mask); /** @brief Fitting nonlinear - optimization initial value by white balance. @return the output array, type of Mat @@ -99,10 +99,10 @@ class ColorCorrectionModel::Impl */ void fitting(void); - void get_color(Mat& img_, bool islinear = false); - void get_color(CONST_COLOR constcolor); - void get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_); - void get_color(Mat colors_, COLOR_SPACE ref_cs_); + void getColor(Mat& img_, bool islinear = false); + void getColor(CONST_COLOR constcolor); + void getColor(Mat colors_, COLOR_SPACE cs_, Mat colored_); + void getColor(Mat colors_, COLOR_SPACE ref_cs_); /** @brief Loss function base on cv::MinProblemSolver::Function. see details in https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/optim.hpp @@ -174,7 +174,7 @@ Mat ColorCorrectionModel::Impl::prepare(const Mat& inp) } } -void ColorCorrectionModel::Impl::calWeightsMasks(Mat weights_list_, double weights_coeff_, Mat saturate_mask) +void ColorCorrectionModel::Impl::calWeightsMasks(const Mat& weights_list_, double weights_coeff_, Mat saturate_mask) { // weights if (!weights_list_.empty()) @@ -299,15 +299,15 @@ Mat ColorCorrectionModel::infer(const Mat& img, bool islinear) return p->cs.fromL(img_ccm); } -void ColorCorrectionModel::Impl::get_color(CONST_COLOR constcolor) +void ColorCorrectionModel::Impl::getColor(CONST_COLOR constcolor) { - dst = (GetColor::get_color(constcolor)); + dst = (GetColor::getColor(constcolor)); } -void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE ref_cs_) +void ColorCorrectionModel::Impl::getColor(Mat colors_, COLOR_SPACE ref_cs_) { dst.reset(new Color(colors_, *GetCS::getInstance().get_cs(ref_cs_))); } -void ColorCorrectionModel::Impl::get_color(Mat colors_, COLOR_SPACE cs_, Mat colored_) +void ColorCorrectionModel::Impl::getColor(Mat colors_, COLOR_SPACE cs_, Mat colored_) { dst.reset(new Color(colors_, *GetCS::getInstance().get_cs(cs_), colored_)); } @@ -315,19 +315,19 @@ ColorCorrectionModel::ColorCorrectionModel(const Mat& src_, CONST_COLOR constcol : p(std::make_shared()) { p->src = src_; - p->get_color(constcolor); + p->getColor(constcolor); } ColorCorrectionModel::ColorCorrectionModel(const Mat& src_, Mat colors_, COLOR_SPACE ref_cs_) : p(std::make_shared()) { p->src = src_; - p->get_color(colors_, ref_cs_); + p->getColor(colors_, ref_cs_); } ColorCorrectionModel::ColorCorrectionModel(const Mat& src_, Mat colors_, COLOR_SPACE cs_, Mat colored_) : p(std::make_shared()) { p->src = src_; - p->get_color(colors_, cs_, colored_); + p->getColor(colors_, cs_, colored_); } void ColorCorrectionModel::setColorSpace(COLOR_SPACE cs_) @@ -428,10 +428,10 @@ Mat ColorCorrectionModel::get_src_rgbl() const{ Mat ColorCorrectionModel::get_dst_rgbl() const{ return p->dst_rgbl; } -Mat ColorCorrectionModel::get_mask() const{ +Mat ColorCorrectionModel::getMask() const{ return p->mask; } -Mat ColorCorrectionModel::get_weights() const{ +Mat ColorCorrectionModel::getWeights() const{ return p->weights; } } diff --git a/modules/mcc/src/color.cpp b/modules/mcc/src/color.cpp index 921d903f8cd..ce00ac47e70 100644 --- a/modules/mcc/src/color.cpp +++ b/modules/mcc/src/color.cpp @@ -148,7 +148,7 @@ Color Color::operator[](Mat mask) return Color(maskCopyTo(colors, mask), cs); } -Mat GetColor::get_ColorChecker(const double* checker, int row) +Mat GetColor::getColorChecker(const double* checker, int row) { Mat res(row, 1, CV_64FC3); for (int i = 0; i < row; ++i) @@ -158,7 +158,7 @@ Mat GetColor::get_ColorChecker(const double* checker, int row) return res; } -Mat GetColor::get_ColorChecker_MASK(const uchar* checker, int row) +Mat GetColor::getColorCheckerMASK(const uchar* checker, int row) { Mat res(row, 1, CV_8U); for (int i = 0; i < row; ++i) @@ -168,7 +168,7 @@ Mat GetColor::get_ColorChecker_MASK(const uchar* checker, int row) return res; } -std::shared_ptr GetColor::get_color(CONST_COLOR const_color) +std::shared_ptr GetColor::getColor(CONST_COLOR const_color) { /** @brief Data is from https://www.imatest.com/wp-content/uploads/2011/11/Lab-data-Iluminate-D65-D50-spectro.xls @@ -370,23 +370,23 @@ std::shared_ptr GetColor::get_color(CONST_COLOR const_color) case cv::ccm::COLORCHECKER_Macbeth: { - Mat ColorChecker2005_LAB_D50_2_ = GetColor::get_ColorChecker(*ColorChecker2005_LAB_D50_2, 24); - Mat ColorChecker2005_COLORED_MASK_ = GetColor::get_ColorChecker_MASK(ColorChecker2005_COLORED_MASK, 24); + Mat ColorChecker2005_LAB_D50_2_ = GetColor::getColorChecker(*ColorChecker2005_LAB_D50_2, 24); + Mat ColorChecker2005_COLORED_MASK_ = GetColor::getColorCheckerMASK(ColorChecker2005_COLORED_MASK, 24); std::shared_ptr Macbeth_D50_2 = std::make_shared(ColorChecker2005_LAB_D50_2_, COLOR_SPACE_Lab_D50_2, ColorChecker2005_COLORED_MASK_); return Macbeth_D50_2; } case cv::ccm::COLORCHECKER_Vinyl: { - Mat Vinyl_LAB_D50_2__ = GetColor::get_ColorChecker(*Vinyl_LAB_D50_2, 18); - Mat Vinyl_COLORED_MASK__ = GetColor::get_ColorChecker_MASK(Vinyl_COLORED_MASK, 18); + Mat Vinyl_LAB_D50_2__ = GetColor::getColorChecker(*Vinyl_LAB_D50_2, 18); + Mat Vinyl_COLORED_MASK__ = GetColor::getColorCheckerMASK(Vinyl_COLORED_MASK, 18); std::shared_ptr Vinyl_D50_2 = std::make_shared(Vinyl_LAB_D50_2__, COLOR_SPACE_Lab_D50_2, Vinyl_COLORED_MASK__); return Vinyl_D50_2; } case cv::ccm::COLORCHECKER_DigitalSG: { - Mat DigitalSG_LAB_D50_2__ = GetColor::get_ColorChecker(*DigitalSG_LAB_D50_2, 140); + Mat DigitalSG_LAB_D50_2__ = GetColor::getColorChecker(*DigitalSG_LAB_D50_2, 140); std::shared_ptr DigitalSG_D50_2 = std::make_shared(DigitalSG_LAB_D50_2__, COLOR_SPACE_Lab_D50_2); return DigitalSG_D50_2; } diff --git a/modules/mcc/src/color.hpp b/modules/mcc/src/color.hpp index 8be475ba065..57ead3558c7 100644 --- a/modules/mcc/src/color.hpp +++ b/modules/mcc/src/color.hpp @@ -107,9 +107,9 @@ class Color class GetColor { public: - static std::shared_ptr get_color(CONST_COLOR const_color); - static Mat get_ColorChecker(const double* checker, int row); - static Mat get_ColorChecker_MASK(const uchar* checker, int row); + static std::shared_ptr getColor(CONST_COLOR const_color); + static Mat getColorChecker(const double* checker, int row); + static Mat getColorCheckerMASK(const uchar* checker, int row); }; } diff --git a/modules/mcc/test/test_ccm.cpp b/modules/mcc/test/test_ccm.cpp index 6682f13845e..56ac51db410 100644 --- a/modules/mcc/test/test_ccm.cpp +++ b/modules/mcc/test/test_ccm.cpp @@ -95,7 +95,7 @@ TEST(CV_ccmRunColorCorrection, test_model) ASSERT_MAT_NEAR(dst_rgbl, model.get_dst_rgbl(), 1e-4); Mat mask = Mat::ones(24, 1, CV_8U); - ASSERT_MAT_NEAR(model.get_mask(), mask, 0.0); + ASSERT_MAT_NEAR(model.getMask(), mask, 0.0); Mat ccm = (Mat_(3, 3) << @@ -125,14 +125,14 @@ TEST(CV_ccmRunColorCorrection, test_masks_weights_1) Mat weights = (Mat_(8, 1) << 1.15789474, 1.26315789, 1.36842105, 1.47368421, 0.52631579, 0.63157895, 0.73684211, 0.84210526); - ASSERT_MAT_NEAR(model1.get_weights(), weights, 1e-4); + ASSERT_MAT_NEAR(model1.getWeights(), weights, 1e-4); Mat mask = (Mat_(24, 1) << true, false, false, true, false, false, true, false, false, true, false, false, true, false, false, true, false, false, true, false, false, true, false, false); - ASSERT_MAT_NEAR(model1.get_mask(), mask, 0.0); + ASSERT_MAT_NEAR(model1.getMask(), mask, 0.0); } TEST(CV_ccmRunColorCorrection, test_masks_weights_2) @@ -152,14 +152,14 @@ TEST(CV_ccmRunColorCorrection, test_masks_weights_2) 1.68623868, 1.37973155, 0.73213388, 1.0169629, 0.47430246, 1.70312161, 0.45414218, 1.15910007, 0.7540434, 1.05049802, 1.04551645, 1.54082353, 1.02453421, 0.6015915, 0.26154558); - ASSERT_MAT_NEAR(model2.get_weights(), weights, 1e-4); + ASSERT_MAT_NEAR(model2.getWeights(), weights, 1e-4); Mat mask = (Mat_(24, 1) << true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, false, true, true, false, false, true, true, true, true); - ASSERT_MAT_NEAR(model2.get_mask(), mask, 0.0); + ASSERT_MAT_NEAR(model2.getMask(), mask, 0.0); } } // namespace From a9f1fb008f6c1d9151b380a1b77d338aa271463a Mon Sep 17 00:00:00 2001 From: shanchenqi <582533558@qq.com> Date: Mon, 23 Nov 2020 14:20:24 +0800 Subject: [PATCH 70/71] update formulas and note for ccm.hpp --- modules/mcc/include/opencv2/mcc/ccm.hpp | 71 +++++++++---------- .../basic_ccm/color_correction_model.markdown | 1 - 2 files changed, 34 insertions(+), 38 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index 63c3583969a..ab961e8f5e3 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -190,7 +190,7 @@ C_{sl}=f(C_s) \f] In practice, \f$n\le3\f$ is used to prevent overfitting. -There are many variants of polynomial fitting, the difference lies in the way of generating $f(x)$. +There are many variants of polynomial fitting, the difference lies in the way of generating \f$f(x)\f$. It is usually necessary to use linearized reference colors and corresponding detected colors to calculate the polynomial parameters. However, not all colors can participate in the calculation. The saturation detected colors needs to be removed. See the algorithm introduction document for details. @@ -288,7 +288,7 @@ For gamma correction formula, we take the logarithm: \f[ ln(C_{sl})={\gamma}ln(C_s),\qquad C_s\ge0\ \f] -It can be seen that there is a linear relationship between \f$ln(C_s)\f$ and \f$ln(C_{sl})\f$. It can be considered that the formula is an approximation of a polynomial relationship, that is, there exists a polynomial $f$, which makes[2]: +It can be seen that there is a linear relationship between \f$ln(C_s)\f$ and \f$ln(C_{sl})\f$. It can be considered that the formula is an approximation of a polynomial relationship, that is, there exists a polynomial \f$f\f$, which makes[2]: \f[ ln(C_{sl})=f(ln(C_s)), \qquad C_s>0\\ C_{sl}=0, \qquad C_s=0 @@ -302,8 +302,8 @@ r=polyfit(ln(R_s),ln(R_{dl}))\\ g=polyfit(ln(G_s),ln(G_{dl}))\\ b=polyfit(ln(B_s),ln(B_{dl}))\\ \f] -Note that the parameter of $ln$ cannot be 0. -Therefore, we need to delete the channels whose values are 0 from $R_s$ and $R_{dl}$, $G_s$ and $G_{dl}$, $B_s$ and $B_{dl}$. +Note that the parameter of \f$ln(*) \f$ cannot be 0. +Therefore, we need to delete the channels whose values are 0 from \f$R_s \f$ and \f$R_{dl} \f$, \f$G_s\f$ and \f$G_{dl}\f$, \f$B_s\f$ and \f$B_{dl}\f$. Therefore: @@ -363,9 +363,9 @@ class CV_EXPORTS_W ColorCorrectionModel /** @brief Color Correction Model Supported list of color cards: - - @ref COLORCHECKER_Macbeth (Macbeth ColorChecker) - - @ref COLORCHECKER_Vinyl (DKK ColorChecker) - - @ref COLORCHECKER_DigitalSG (DigitalSG ColorChecker with 140 squares) + - @ref COLORCHECKER_Macbeth, the Macbeth ColorChecker + - @ref COLORCHECKER_Vinyl, the DKK ColorChecker + - @ref COLORCHECKER_DigitalSG, the DigitalSG ColorChecker with 140 squares @param src detected colors of ColorChecker patches;\n the color type is RGB not BGR, and the color values are in [0, 1]; @@ -376,9 +376,8 @@ class CV_EXPORTS_W ColorCorrectionModel /** @brief Color Correction Model @param src detected colors of ColorChecker patches;\n the color type is RGB not BGR, and the color values are in [0, 1]; - @param colors the reference color values,the color values are in [0, 1].\n + @param colors the reference color values, the color values are in [0, 1].\n @param ref_cs the corresponding color space - NOTICE: For the list of color spaces supported, see the notes above;\n If the color type is some RGB, the format is RGB not BGR;\n */ CV_WRAP ColorCorrectionModel(const Mat& src, Mat colors, COLOR_SPACE ref_cs); @@ -386,27 +385,25 @@ class CV_EXPORTS_W ColorCorrectionModel /** @brief Color Correction Model @param src detected colors of ColorChecker patches;\n the color type is RGB not BGR, and the color values are in [0, 1]; - @param colors the reference color values,the color values are in [0, 1]. + @param colors the reference color values, the color values are in [0, 1]. @param ref_cs the corresponding color space - NOTICE: For the list of color spaces supported, see the notes above;\n If the color type is some RGB, the format is RGB not BGR; @param colored mask of colored color */ CV_WRAP ColorCorrectionModel(const Mat& src, Mat colors, COLOR_SPACE ref_cs, Mat colored); /** @brief set ColorSpace - @note It should be some RGB color space; Supported list of color cards: - - @ref COLOR_SPACE_sRGB, - - @ref COLOR_SPACE_AdobeRGB, - - @ref COLOR_SPACE_WideGamutRGB, - - @ref COLOR_SPACE_ProPhotoRGB, - - @ref COLOR_SPACE_DCI_P3_RGB, - - @ref COLOR_SPACE_AppleRGB, - - @ref COLOR_SPACE_REC_709_RGB, - - @ref COLOR_SPACE_REC_2020_RGB, - - @param cs the absolute color space that detected colors convert to;\n + - @ref COLOR_SPACE_sRGB + - @ref COLOR_SPACE_AdobeRGB + - @ref COLOR_SPACE_WideGamutRGB + - @ref COLOR_SPACE_ProPhotoRGB + - @ref COLOR_SPACE_DCI_P3_RGB + - @ref COLOR_SPACE_AppleRGB + - @ref COLOR_SPACE_REC_709_RGB + - @ref COLOR_SPACE_REC_2020_RGB + @param cs the absolute color space that detected colors convert to;\n default: @ref COLOR_SPACE_sRGB */ CV_WRAP void setColorSpace(COLOR_SPACE cs); @@ -424,8 +421,6 @@ class CV_EXPORTS_W ColorCorrectionModel CV_WRAP void setDistance(DISTANCE_TYPE distance); /** @brief set Linear - - Supported list: @param linear_type the method of linearization;\n default: @ref LINEARIZATION_GAMMA */ @@ -435,29 +430,30 @@ class CV_EXPORTS_W ColorCorrectionModel @note only valid when linear is set to "gamma";\n - @param gamma the gamma value of gamma correction; - default: 2.2;\n + @param gamma the gamma value of gamma correction;\n + default: 2.2; */ CV_WRAP void setLinearGamma(double gamma); /** @brief set degree - @param deg the degree of linearization polynomial;\n - NOTICE: only valid when linear is set to - @ref LINEARIZATION_COLORPOLYFIT - @ref LINEARIZATION_GRAYPOLYFIT - @ref LINEARIZATION_COLORLOGPOLYFIT - @ref LINEARIZATION_GRAYLOGPOLYFIT - default: 3 + @note only valid when linear is set to + - @ref LINEARIZATION_COLORPOLYFIT + - @ref LINEARIZATION_GRAYPOLYFIT + - @ref LINEARIZATION_COLORLOGPOLYFIT + - @ref LINEARIZATION_GRAYLOGPOLYFIT + + - @param deg the degree of linearization polynomial;\n + default: 3 + */ CV_WRAP void setLinearDegree(int deg); - /** @brief set SaturatedThreshold + /** @brief set SaturatedThreshold.it is a tuple of [lower, upper]; + The colors in the closed interval [lower, upper] are reserved to participate + in the calculation of the loss function and initialization parameters @param lower the lower threshold to determine saturation;\n default: 0; - @param upper the upper threshold to determine saturation; - NOTICE: it is a tuple of [lower, upper]; - The colors in the closed interval [lower, upper] are reserved to participate - in the calculation of the loss function and initialization parameters\n + @param upper the upper threshold to determine saturation;\n default: 0 */ CV_WRAP void setSaturatedThreshold(double lower, double upper); @@ -476,6 +472,7 @@ class CV_EXPORTS_W ColorCorrectionModel /** @brief set InitialMethod @param initial_method_type the method of calculating CCM initial value;\n + default: INITIAL_METHOD_LEAST_SQUARE */ CV_WRAP void setInitialMethod(INITIAL_METHOD_TYPE initial_method_type); diff --git a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown index ac510cf36ea..76b98cd3f4b 100644 --- a/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown +++ b/modules/mcc/tutorials/basic_ccm/color_correction_model.markdown @@ -47,7 +47,6 @@ Here are the parameters for ColorCorrectionModel NOTICE: the color values are in [0, 1] ref_cs : the corresponding color space - NOTICE: For the list of color spaces supported, see the notes below; If the color type is some RGB, the format is RGB not BGR; Supported Color Space: Supported list of RGB color spaces: From 7769198619ae4d3f39c68344f453b3adcb1bd802 Mon Sep 17 00:00:00 2001 From: Chenqi Shan Date: Mon, 23 Nov 2020 15:27:40 +0800 Subject: [PATCH 71/71] add const value --- modules/mcc/include/opencv2/mcc/ccm.hpp | 18 ++++++++-------- modules/mcc/src/ccm.cpp | 14 ++++++------- modules/mcc/src/distance.cpp | 26 +++++++++++------------ modules/mcc/src/distance.hpp | 28 ++++++++++++------------- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/modules/mcc/include/opencv2/mcc/ccm.hpp b/modules/mcc/include/opencv2/mcc/ccm.hpp index ab961e8f5e3..a3686db473d 100644 --- a/modules/mcc/include/opencv2/mcc/ccm.hpp +++ b/modules/mcc/include/opencv2/mcc/ccm.hpp @@ -433,7 +433,7 @@ class CV_EXPORTS_W ColorCorrectionModel @param gamma the gamma value of gamma correction;\n default: 2.2; */ - CV_WRAP void setLinearGamma(double gamma); + CV_WRAP void setLinearGamma(const double& gamma); /** @brief set degree @note only valid when linear is set to @@ -442,13 +442,13 @@ class CV_EXPORTS_W ColorCorrectionModel - @ref LINEARIZATION_COLORLOGPOLYFIT - @ref LINEARIZATION_GRAYLOGPOLYFIT - - @param deg the degree of linearization polynomial;\n + @param deg the degree of linearization polynomial;\n default: 3 */ - CV_WRAP void setLinearDegree(int deg); + CV_WRAP void setLinearDegree(const int& deg); - /** @brief set SaturatedThreshold.it is a tuple of [lower, upper]; + /** @brief set SaturatedThreshold. The colors in the closed interval [lower, upper] are reserved to participate in the calculation of the loss function and initialization parameters @param lower the lower threshold to determine saturation;\n @@ -456,19 +456,19 @@ class CV_EXPORTS_W ColorCorrectionModel @param upper the upper threshold to determine saturation;\n default: 0 */ - CV_WRAP void setSaturatedThreshold(double lower, double upper); + CV_WRAP void setSaturatedThreshold(const double& lower, const double& upper); /** @brief set WeightsList @param weights_list the list of weight of each color;\n default: empty array */ - CV_WRAP void setWeightsList(Mat weights_list); + CV_WRAP void setWeightsList(const Mat& weights_list); /** @brief set WeightCoeff @param weights_coeff the exponent number of L* component of the reference color in CIE Lab color space;\n default: 0 */ - CV_WRAP void setWeightCoeff(double weights_coeff); + CV_WRAP void setWeightCoeff(const double& weights_coeff); /** @brief set InitialMethod @param initial_method_type the method of calculating CCM initial value;\n @@ -481,14 +481,14 @@ class CV_EXPORTS_W ColorCorrectionModel Terminal criteria to the algorithm;\n default: 5000; */ - CV_WRAP void setMaxCount(int max_count); + CV_WRAP void setMaxCount(const int& max_count); /** @brief set Epsilon @param epsilon used in MinProblemSolver-DownhillSolver;\n Terminal criteria to the algorithm;\n default: 1e-4; */ - CV_WRAP void setEpsilon(double epsilon); + CV_WRAP void setEpsilon(const double& epsilon); /** @brief make color correction */ CV_WRAP void run(); diff --git a/modules/mcc/src/ccm.cpp b/modules/mcc/src/ccm.cpp index ad1d5a0d42e..7e26d164124 100644 --- a/modules/mcc/src/ccm.cpp +++ b/modules/mcc/src/ccm.cpp @@ -346,23 +346,23 @@ void ColorCorrectionModel::setLinear(LINEAR_TYPE linear_type) { p->linear_type = linear_type; } -void ColorCorrectionModel::setLinearGamma(double gamma) +void ColorCorrectionModel::setLinearGamma(const double& gamma) { p->gamma = gamma; } -void ColorCorrectionModel::setLinearDegree(int deg) +void ColorCorrectionModel::setLinearDegree(const int& deg) { p->deg = deg; } -void ColorCorrectionModel::setSaturatedThreshold(double lower, double upper) +void ColorCorrectionModel::setSaturatedThreshold(const double& lower, const double& upper) { //std::vector saturated_threshold p->saturated_threshold = { lower, upper }; } -void ColorCorrectionModel::setWeightsList(Mat weights_list) +void ColorCorrectionModel::setWeightsList(const Mat& weights_list) { p->weights_list = weights_list; } -void ColorCorrectionModel::setWeightCoeff(double weights_coeff) +void ColorCorrectionModel::setWeightCoeff(const double& weights_coeff) { p->weights_coeff = weights_coeff; } @@ -370,11 +370,11 @@ void ColorCorrectionModel::setInitialMethod(INITIAL_METHOD_TYPE initial_method_t { p->initial_method_type = initial_method_type; } -void ColorCorrectionModel::setMaxCount(int max_count_) +void ColorCorrectionModel::setMaxCount(const int& max_count_) { p->max_count = max_count_; } -void ColorCorrectionModel::setEpsilon(double epsilon_) +void ColorCorrectionModel::setEpsilon(const double& epsilon_) { p->epsilon = epsilon_; } diff --git a/modules/mcc/src/distance.cpp b/modules/mcc/src/distance.cpp index fa535b88477..7996379e939 100644 --- a/modules/mcc/src/distance.cpp +++ b/modules/mcc/src/distance.cpp @@ -30,10 +30,10 @@ namespace cv { namespace ccm { -double deltaCIE76(cv::Vec3d lab1, cv::Vec3d lab2) { return norm(lab1 - lab2); }; +double deltaCIE76(const Vec3d& lab1, const Vec3d& lab2) { return norm(lab1 - lab2); }; -double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH, - double kC, double kL, double k1, double k2) +double deltaCIE94(const Vec3d& lab1, const Vec3d& lab2, const double& kH, + const double& kC, const double& kL, const double& k1, const double& k2) { double dl = lab1[0] - lab2[0]; double c1 = sqrt(pow(lab1[1], 2) + pow(lab1[2], 2)); @@ -50,20 +50,20 @@ double deltaCIE94(cv::Vec3d lab1, cv::Vec3d lab2, double kH, return res > 0 ? sqrt(res) : 0; } -double deltaCIE94GraphicArts(cv::Vec3d lab1, cv::Vec3d lab2) +double deltaCIE94GraphicArts(const Vec3d& lab1, const Vec3d& lab2) { return deltaCIE94(lab1, lab2); } -double toRad(double degree) { return degree / 180 * CV_PI; }; +double toRad(const double& degree) { return degree / 180 * CV_PI; }; -double deltaCIE94Textiles(cv::Vec3d lab1, cv::Vec3d lab2) +double deltaCIE94Textiles(const Vec3d& lab1, const Vec3d& lab2) { return deltaCIE94(lab1, lab2, 1.0, 1.0, 2.0, 0.048, 0.014); } -double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL, - double kC, double kH) +double deltaCIEDE2000_(const Vec3d& lab1, const Vec3d& lab2, const double& kL, + const double& kC, const double& kH) { double delta_L_apo = lab2[0] - lab1[0]; double l_bar_apo = (lab1[0] + lab2[0]) / 2.0; @@ -144,12 +144,12 @@ double deltaCIEDE2000_(cv::Vec3d lab1, cv::Vec3d lab2, double kL, return res > 0 ? sqrt(res) : 0; } -double deltaCIEDE2000(cv::Vec3d lab1, cv::Vec3d lab2) +double deltaCIEDE2000(const Vec3d& lab1, const Vec3d& lab2) { return deltaCIEDE2000_(lab1, lab2); } -double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL, double kC) +double deltaCMC(const Vec3d& lab1, const Vec3d& lab2, const double& kL, const double& kC) { double dL = lab2[0] - lab1[0]; double da = lab2[1] - lab1[1]; @@ -182,12 +182,12 @@ double deltaCMC(cv::Vec3d lab1, cv::Vec3d lab2, double kL, double kC) return sqrt(pow(dL / (kL * sL), 2.0) + pow(dC / (kC * sC), 2.0) + pow(dH / sH, 2.0)); } -double deltaCMC1To1(cv::Vec3d lab1, cv::Vec3d lab2) +double deltaCMC1To1(const Vec3d& lab1, const Vec3d& lab2) { return deltaCMC(lab1, lab2); } -double deltaCMC2To1(cv::Vec3d lab1, cv::Vec3d lab2) +double deltaCMC2To1(const Vec3d& lab1, const Vec3d& lab2) { return deltaCMC(lab1, lab2, 2, 1); } @@ -219,4 +219,4 @@ Mat distance(Mat src, Mat ref, DISTANCE_TYPE distance_type) }; } -} // namespace cv::ccm \ No newline at end of file +} // namespace ccm \ No newline at end of file diff --git a/modules/mcc/src/distance.hpp b/modules/mcc/src/distance.hpp index 4fc63b115ff..5acfc93cdb6 100644 --- a/modules/mcc/src/distance.hpp +++ b/modules/mcc/src/distance.hpp @@ -42,7 +42,7 @@ namespace ccm { @return distance between lab1 and lab2 */ -double deltaCIE76(Vec3d lab1, Vec3d lab2); +double deltaCIE76(const Vec3d& lab1, const Vec3d& lab2); /** @brief distance between two points in formula CIE94 @param lab1 a 3D vector @@ -55,15 +55,15 @@ double deltaCIE76(Vec3d lab1, Vec3d lab2); @return distance between lab1 and lab2 */ -double deltaCIE94(Vec3d lab1, Vec3d lab2, double kH = 1.0, - double kC = 1.0, double kL = 1.0, double k1 = 0.045, - double k2 = 0.015); +double deltaCIE94(const Vec3d& lab1, const Vec3d& lab2, const double& kH = 1.0, + const double& kC = 1.0, const double& kL = 1.0, const double& k1 = 0.045, + const double& k2 = 0.015); -double deltaCIE94GraphicArts(Vec3d lab1, Vec3d lab2); +double deltaCIE94GraphicArts(const Vec3d& lab1, const Vec3d& lab2); -double toRad(double degree); +double toRad(const double& degree); -double deltaCIE94Textiles(Vec3d lab1, Vec3d lab2); +double deltaCIE94Textiles(const Vec3d& lab1, const Vec3d& lab2); /** @brief distance between two points in formula CIE2000 @param lab1 a 3D vector @@ -73,9 +73,9 @@ double deltaCIE94Textiles(Vec3d lab1, Vec3d lab2); @param kH Hue scale @return distance between lab1 and lab2 */ -double deltaCIEDE2000_(Vec3d lab1, Vec3d lab2, double kL = 1.0, - double kC = 1.0, double kH = 1.0); -double deltaCIEDE2000(Vec3d lab1, Vec3d lab2); +double deltaCIEDE2000_(const Vec3d& lab1, const Vec3d& lab2, const double& kL = 1.0, + const double& kC = 1.0, const double& kH = 1.0); +double deltaCIEDE2000(const Vec3d& lab1, const Vec3d& lab2); /** @brief distance between two points in formula CMC @param lab1 a 3D vector @@ -85,13 +85,13 @@ double deltaCIEDE2000(Vec3d lab1, Vec3d lab2); @return distance between lab1 and lab2 */ -double deltaCMC(Vec3d lab1, Vec3d lab2, double kL = 1, double kC = 1); +double deltaCMC(const Vec3d& lab1, const Vec3d& lab2, const double& kL = 1, const double& kC = 1); -double deltaCMC1To1(Vec3d lab1, Vec3d lab2); +double deltaCMC1To1(const Vec3d& lab1, const Vec3d& lab2); -double deltaCMC2To1(Vec3d lab1, Vec3d lab2); +double deltaCMC2To1(const Vec3d& lab1, const Vec3d& lab2); -Mat distance(Mat src, Mat ref, DISTANCE_TYPE distance_type); +Mat distance(Mat src,Mat ref, DISTANCE_TYPE distance_type); } } // namespace cv::ccm