|
| 1 | +Color Correction Model{#tutorial_ccm_color_correction_model} |
| 2 | +=========================== |
| 3 | + |
| 4 | +In this tutorial you will learn how to use the 'Color Correction Model' to do a color correction in a image. |
| 5 | + |
| 6 | +Reference |
| 7 | +---- |
| 8 | + |
| 9 | +See details of ColorCorrection Algorithm at https://github.com/riskiest/color_calibration/tree/v4/doc/pdf/English/Algorithm. |
| 10 | + |
| 11 | +Building |
| 12 | +---- |
| 13 | + |
| 14 | +When building OpenCV, run the following command to build all the contrib module: |
| 15 | + |
| 16 | +```make |
| 17 | +cmake -D OPENCV_EXTRA_MODULES_PATH=<opencv_contrib>/modules/ |
| 18 | +``` |
| 19 | + |
| 20 | +Or only build the mcc module: |
| 21 | + |
| 22 | +```make |
| 23 | +cmake -D OPENCV_EXTRA_MODULES_PATH=<opencv_contrib>/modules/mcc |
| 24 | +``` |
| 25 | + |
| 26 | +Or make sure you check the mcc module in the GUI version of CMake: cmake-gui. |
| 27 | + |
| 28 | +Source Code of the sample |
| 29 | +----------- |
| 30 | + |
| 31 | +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. |
| 32 | + |
| 33 | +``` |
| 34 | +Here are the parameters for ColorCorrectionModel |
| 35 | +src : |
| 36 | + detected colors of ColorChecker patches; |
| 37 | + NOTICE: the color type is RGB not BGR, and the color values are in [0, 1]; |
| 38 | + type: cv::Mat; |
| 39 | +dst : |
| 40 | + the reference colors; |
| 41 | + NOTICE: Built-in color card or custom color card are supported; |
| 42 | + Built-in: |
| 43 | + Macbeth_D50_2: Macbeth ColorChecker with 2deg D50; |
| 44 | + Macbeth_D65_2: Macbeth ColorChecker with 2deg D65; |
| 45 | + Custom: |
| 46 | + You should use Color |
| 47 | + For the list of color spaces supported, see the notes below; |
| 48 | + If the color type is some RGB, the format is RGB not BGR, and the color values are in [0, 1]; |
| 49 | + type: Color; |
| 50 | +colorspace : |
| 51 | + the absolute color space that detected colors convert to; |
| 52 | + NOTICE: it should be some RGB color space; |
| 53 | + For the list of RGB color spaces supported, see the notes below; |
| 54 | + type: ColorSpace; |
| 55 | +ccm_type : |
| 56 | + the shape of color correction matrix(CCM); |
| 57 | + Supported list: |
| 58 | + "CCM_3x3": 3x3 matrix; |
| 59 | + "CCM_4x3": 4x3 matrix; |
| 60 | + type: enum CCM_TYPE; |
| 61 | +distance : |
| 62 | + the type of color distance; |
| 63 | + Supported list: |
| 64 | + "CIE2000"; |
| 65 | + "CIE94_GRAPHIC_ARTS"; |
| 66 | + "CIE94_TEXTILES"; |
| 67 | + "CIE76"; |
| 68 | + "CMC_1TO1"; |
| 69 | + "CMC_2TO1"; |
| 70 | + "RGB" : Euclidean distance of rgb color space; |
| 71 | + "RGBL" : Euclidean distance of rgbl color space; |
| 72 | + type: enum DISTANCE_TYPE; |
| 73 | +linear_type : |
| 74 | + the method of linearization; |
| 75 | + NOTICE: see Linearization.pdf for details; |
| 76 | + Supported list: |
| 77 | + "IDENTITY_" : no change is made; |
| 78 | + "GAMMA": gamma correction; |
| 79 | + Need assign a value to gamma simultaneously; |
| 80 | + "COLORPOLYFIT": polynomial fitting channels respectively; |
| 81 | + Need assign a value to deg simultaneously; |
| 82 | + "GRAYPOLYFIT": grayscale polynomial fitting; |
| 83 | + Need assign a value to deg and dst_whites simultaneously; |
| 84 | + "COLORLOGPOLYFIT": logarithmic polynomial fitting channels respectively; |
| 85 | + Need assign a value to deg simultaneously; |
| 86 | + "GRAYLOGPOLYFIT": grayscale Logarithmic polynomial fitting; |
| 87 | + Need assign a value to deg and dst_whites simultaneously; |
| 88 | + type: enum LINEAR_TYPE; |
| 89 | +gamma : |
| 90 | + the gamma value of gamma correction; |
| 91 | + NOTICE: only valid when linear is set to "gamma"; |
| 92 | + type: double; |
| 93 | +
|
| 94 | +deg : |
| 95 | + the degree of linearization polynomial; |
| 96 | + NOTICE: only valid when linear is set to "COLORPOLYFIT", "GRAYPOLYFIT", |
| 97 | + "COLORLOGPOLYFIT" and "GRAYLOGPOLYFIT"; |
| 98 | + type: int; |
| 99 | +saturated_threshold : |
| 100 | + the threshold to determine saturation; |
| 101 | + NOTICE: it is a tuple of [low, up]; |
| 102 | + The colors in the closed interval [low, up] are reserved to participate |
| 103 | + in the calculation of the loss function and initialization parameters. |
| 104 | + type: std::vector<double>; |
| 105 | +--------------------------------------------------- |
| 106 | +There are some ways to set weights: |
| 107 | + 1. set weights_list only; |
| 108 | + 2. set weights_coeff only; |
| 109 | +see CCM.pdf for details; |
| 110 | +
|
| 111 | +weights_list : |
| 112 | + the list of weight of each color; |
| 113 | + type: cv::Mat; |
| 114 | +
|
| 115 | +weights_coeff : |
| 116 | + the exponent number of L* component of the reference color in CIE Lab color space; |
| 117 | + type: double; |
| 118 | +--------------------------------------------------- |
| 119 | +initial_method_type : |
| 120 | + the method of calculating CCM initial value; |
| 121 | + see CCM.pdf for details; |
| 122 | + Supported list: |
| 123 | + 'LEAST_SQUARE': least-squre method; |
| 124 | + 'WHITE_BALANCE': white balance method; |
| 125 | +
|
| 126 | +max_count, epsilon : |
| 127 | + used in MinProblemSolver-DownhillSolver; |
| 128 | + Terminal criteria to the algorithm; |
| 129 | + type: int, double; |
| 130 | +
|
| 131 | +
|
| 132 | +--------------------------------------------------- |
| 133 | +Supported Color Space: |
| 134 | + Supported list of RGB color spaces: |
| 135 | + sRGB; |
| 136 | + AdobeRGB; |
| 137 | + WideGamutRGB; |
| 138 | + ProPhotoRGB; |
| 139 | + DCI_P3_RGB; |
| 140 | + AppleRGB; |
| 141 | + REC_709_RGB; |
| 142 | + REC_2020_RGB; |
| 143 | +
|
| 144 | + Supported list of linear RGB color spaces: |
| 145 | + sRGBL; |
| 146 | + AdobeRGBL; |
| 147 | + WideGamutRGBL; |
| 148 | + ProPhotoRGBL; |
| 149 | + DCI_P3_RGBL; |
| 150 | + AppleRGBL; |
| 151 | + REC_709_RGBL; |
| 152 | + REC_2020_RGBL; |
| 153 | +
|
| 154 | + Supported list of non-RGB color spaces: |
| 155 | + Lab_D50_2; |
| 156 | + Lab_D65_2; |
| 157 | + XYZ_D50_2; |
| 158 | + XYZ_D65_2; |
| 159 | +
|
| 160 | + Supported IO (You can use Lab(io) or XYZ(io) to create color space): |
| 161 | + A_2; |
| 162 | + A_10; |
| 163 | + D50_2; |
| 164 | + D50_10; |
| 165 | + D55_2; |
| 166 | + D55_10; |
| 167 | + D65_2; |
| 168 | + D65_10; |
| 169 | + D75_2; |
| 170 | + D75_10; |
| 171 | + E_2; |
| 172 | + E_10; |
| 173 | +``` |
| 174 | + |
| 175 | + |
| 176 | +## Code |
| 177 | + |
| 178 | +@include mcc/samples/color_correction_model.cpp |
| 179 | + |
| 180 | +## Explanation |
| 181 | + |
| 182 | + The first part is to detect the ColorChecker position. |
| 183 | + |
| 184 | +@code{.cpp}#include <opencv2/core.hpp>#include <opencv2/highgui.hpp>#include <opencv2/imgcodecs.hpp>#include <opencv2/mcc.hpp>#include <opencv2/mcc/ccm.hpp>#include <iostream>using namespace std;using namespace cv;using namespace mcc;using namespace ccm;using namespace std;@endcode |
| 185 | + |
| 186 | +``` |
| 187 | +Here is sets of header and namespaces. You can set other namespace like the code above. |
| 188 | +``` |
| 189 | + |
| 190 | +@code{.cpp} |
| 191 | + |
| 192 | +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) }" |
| 193 | + |
| 194 | + "{f | 1 | Path of the file to process (-v) }" "{nc | 1 | Maximum number of charts in the image }"};@ endcode |
| 195 | + |
| 196 | +``` |
| 197 | +Some arguments for ColorChecker detection. |
| 198 | +``` |
| 199 | + |
| 200 | +@code{.cpp} CommandLineParser parser(argc, argv, keys); parser.about(about); int t = parser.get<int>("t"); int nc = parser.get<int>("nc"); string filepath = parser.get<string>("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 |
| 201 | + |
| 202 | +``` |
| 203 | +Preparation for ColorChecker detection to get messages for the image. |
| 204 | +``` |
| 205 | + |
| 206 | +@code{.cpp}Mat imageCopy = image.clone(); |
| 207 | + |
| 208 | + Ptr<CCheckerDetector> detector = CCheckerDetector::create(); if (!detector->process(image, chartType, nc)) { printf("ChartColor not detected \n"); return 2; } vector<Ptr<mcc::CChecker>> checkers = detector->getListColorChecker();@endcode |
| 209 | + |
| 210 | +``` |
| 211 | +The CCheckerDetectorobject is created and uses getListColorChecker function to get ColorChecker message. |
| 212 | +``` |
| 213 | + |
| 214 | +@code{.cpp} for (Ptr<mcc::CChecker> checker : checkers) { Ptr<CCheckerDraw> 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 |
| 215 | + |
| 216 | +``` |
| 217 | +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. |
| 218 | +``` |
| 219 | + |
| 220 | +@code{.cpp}cv::Mat ref = = (Mat_<Vec3d>(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)); |
| 221 | + |
| 222 | +ColorCorrectionModel model8(src,ref,Lab_D50_2); @endcode |
| 223 | + |
| 224 | +``` |
| 225 | +If you use a customized ColorChecker, you can use your own reference color values and corresponding color space As shown above. |
| 226 | +``` |
| 227 | + |
| 228 | +@code{.cpp}Mat calibratedImage = model1.inferImage(filepath); @endcode |
| 229 | + |
| 230 | +``` |
| 231 | +The member function infer_image is to make correction correction using ccm matrix. |
| 232 | +``` |
| 233 | + |
| 234 | +@code{.cpp}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); @endcode |
| 235 | + |
| 236 | +``` |
| 237 | +Save the calibrated image. |
| 238 | +``` |
0 commit comments