OpenCV
Open Source Computer Vision
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
Detecting colorcheckers

In this tutorial you will learn how to use the 'mcc' module to detect colorcharts in a image. Here we will only use the basic detection algorithm and an improved version that enhances accuracy using a neural network.

Source Code of the sample

run
<path_of_your_opencv_build_directory>/bin/example_cpp_macbeth_chart_detection -t=<type_of_chart> -v=<optional_path_to_video_if_not_provided_webcam_will_be_used.mp4> --ci=<optional_camera_id_needed_only_if_video_not_provided> --nc=<optional_maximum_number_of_charts_to_look_for>
  • -t=# is the chart type where 0 (Standard), 1 (DigitalSG), 2 (Vinyl)
  • –ci=# is the camera ID where 0 (default is the main camera), 1 (secondary camera) etc
  • –nc=# By default its values is 1 which means only the best chart will be detected

Examples:

Run a movie on a standard macbeth chart:
/home/opencv/build/bin/example_cpp_macbeth_chart_detection -t=0 -v=mcc24.mp4
Or run on a vinyl macbeth chart from camera 0:
/home/opencv/build/bin/example_cpp_macbeth_chart_detection -t=2 --ci=0
Or run on a vinyl macbeth chart, detecting the best 5 charts(Detections can be less than 5 but never more):
/home/opencv/build/bin/example_cpp_macbeth_chart_detection -t=2 --ci=0 --nc=5
Simple run on CPU with neural network (GPU wont be used)
/home/opencv/build/bin/example_cpp_macbeth_chart_detection -t=0 -m=/home/model.pb --pb=/home/model.pbtxt -v=mcc24.mp4
To run on GPU with neural network
/home/opencv/build/bin/example_cpp_macbeth_chart_detection -t=0 -m=/home/model.pb --pb=/home/model.pbtxt -v=mcc24.mp4 --use_gpu
To run on GPU with neural network and detect the best 5 charts (Detections can be less than 5 but not more than 5)
/home/opencv/build/bin/example_cpp_macbeth_chart_detection -t=0 -m=/home/model.pb --pb=/home/model.pbtxt -v=mcc24.mp4 --use_gpu --nc=5
1#include <opencv2/core.hpp>
2#include <opencv2/highgui.hpp>
4#ifdef HAVE_OPENCV_DNN
5#include <opencv2/dnn.hpp>
6#include "../dnn/common.hpp"
7#endif
8#include <iostream>
9
10using namespace std;
11using namespace cv;
12#ifdef HAVE_OPENCV_DNN
13using namespace cv::dnn;
14#endif
15using namespace mcc;
16
17const string about =
18 "This sample demonstrates mcc checker detection with DNN based model and thresholding (default) techniques.\n\n"
19 "To run default:\n"
20 "\t ./example_cpp_macbeth_chart_detection --input=path/to/your/input/image/or/video (don't give --input flag if want to use device camera)\n"
21#ifdef HAVE_OPENCV_DNN
22 "With DNN model:\n"
23 "\t ./example_cpp_macbeth_chart_detection mcc --input=path/to/your/input/image/or/video\n\n"
24 "Model path can also be specified using --model argument. And config path can be specified using --config. Download it using python download_models.py mcc from dnn samples directory\n\n"
25#else
26 "Note: DNN-based detection is not available in this build.\n\n"
27#endif
28 ;
29
30const string param_keys =
31 "{ help h | | Print help message. }"
32#ifdef HAVE_OPENCV_DNN
33 "{ @alias | | An alias name of model to extract preprocessing parameters from models.yml file. }"
34 "{ zoo | ../dnn/models.yml | An optional path to file with preprocessing parameters }"
35#endif
36 "{ input i | | Path to input image or video file. Skip this argument to capture frames from a camera.}"
37 "{ type | 0 | chartType: 0-Standard, 1-DigitalSG, 2-Vinyl, default:0 }"
38 "{ num_charts | 1 | Maximum number of charts in the image }"
39#ifdef HAVE_OPENCV_DNN
40 "{ model | | Path to the model file for using dnn model. }";
41#else
42 ;
43#endif
44
45#ifdef HAVE_OPENCV_DNN
46const string backend_keys = format(
47 "{ backend | default | Choose one of computation backends: "
48 "default: automatically (by default), "
49 "openvino: Intel's Deep Learning Inference Engine (https://software.intel.com/openvino-toolkit), "
50 "opencv: OpenCV implementation, "
51 "vkcom: VKCOM, "
52 "cuda: CUDA, "
53 "webnn: WebNN }");
54
55const string target_keys = format(
56 "{ target | cpu | Choose one of target computation devices: "
57 "cpu: CPU target (by default), "
58 "opencl: OpenCL, "
59 "opencl_fp16: OpenCL fp16 (half-float precision), "
60 "vpu: VPU, "
61 "vulkan: Vulkan, "
62 "cuda: CUDA, "
63 "cuda_fp16: CUDA fp16 (half-float preprocess) }");
64#endif
65
66// Initialize keys before use
67string keys = param_keys;
68static void initKeys() {
69#ifdef HAVE_OPENCV_DNN
70 keys += backend_keys + target_keys;
71#endif
72}
73
74static bool processFrame(const Mat& frame, Ptr<CCheckerDetector> detector, Mat& src, Mat& tgt, int nc){
75 Mat imageCopy = frame.clone();
76 if (!detector->process(frame, nc))
77 {
78 return false;
79 }
80 vector<Ptr<CChecker>> checkers = detector->getListColorChecker();
81 detector->draw(checkers, frame);
82 src = checkers[0]->getChartsRGB(false);
83 tgt = detector->getRefColors();
84
85 imshow("Image result", frame);
86 imshow("Original", imageCopy);
87
88 return true;
89}
90
91int main(int argc, char *argv[])
92{
93 initKeys();
94 CommandLineParser parser(argc, argv, keys);
95 parser.about(about);
96
97 if (parser.has("help"))
98 {
99 cout << about << endl;
100 parser.printMessage();
101 return -1;
102 }
103
104#ifdef HAVE_OPENCV_DNN
105 string modelName = parser.get<String>("@alias");
106 string zooFile = parser.get<String>("zoo");
107 const char* path = getenv("OPENCV_SAMPLES_DATA_PATH");
108 if ((path != NULL) || parser.has("@alias") || (parser.get<String>("model") != "")) {
109 zooFile = findFile(zooFile);
110 }
111 else{
112 cout<<"[WARN] set the environment variables or pass the arguments --model, --config and models.yml file using --zoo for using dnn based detector. Continuing with default detector.\n\n";
113 }
114
115 keys += genPreprocArguments(modelName, zooFile);
116 parser = CommandLineParser(argc, argv, keys);
117#endif
118
119 int t = parser.get<int>("type");
120
121 CV_Assert(0 <= t && t <= 2);
122 ColorChart chartType = ColorChart(t);
123
124#ifdef HAVE_OPENCV_DNN
125 const string sha1 = parser.get<String>("sha1");
126 const string model_path = findModel(parser.get<string>("model"), sha1);
127 const string config_sha1 = parser.get<String>("config_sha1");
128 const string pbtxt_path = findModel(parser.get<string>("config"), config_sha1);
129 const string backend = parser.get<String>("backend");
130 const string target = parser.get<String>("target");
131#endif
132
133 int nc = parser.get<int>("num_charts");
134
135 Ptr<CCheckerDetector> detector;
136#ifdef HAVE_OPENCV_DNN
137 if (model_path != "" && pbtxt_path != ""){
138 EngineType engine = ENGINE_AUTO;
139 if (backend != "default" || target != "cpu"){
140 engine = ENGINE_CLASSIC;
141 }
142 Net net = readNetFromTensorflow(model_path, pbtxt_path, engine);
143 net.setPreferableBackend(getBackendID(backend));
144 net.setPreferableTarget(getTargetID(target));
145
146 detector = CCheckerDetector::create(net);
147 cout<<"Detecting checkers using neural network."<<endl;
148 }
149 else{
150 detector = CCheckerDetector::create();
151 }
152#else
153 detector = CCheckerDetector::create();
154#endif
155 detector->setColorChartType(chartType);
156
157 bool isVideo = true;
158 Mat image;
159 VideoCapture cap;
160
161 if (parser.has("input")){
162 const string inputFile = parser.get<String>("input");
163 image = imread(findFile(inputFile));
164 if (!image.empty())
165 {
166 isVideo = false;
167 }
168 else
169 {
170 // Not an image, so try opening it as a video.
171 cap.open(findFile(inputFile));
172 if (!cap.isOpened())
173 {
174 cout << "[ERROR] Could not open file as an image or video: " << inputFile << endl;
175 return -1;
176 }
177 }
178 }
179 else
180 cap.open(0);
181
182 Mat src, tgt;
183 bool found = false;
184 if (isVideo){
185 cout<<"To print the actual colors and reference colors for current frame press SPACEBAR. To resume press SPACEBAR again"<<endl;
186
187 while (cap.grab())
188 {
189 Mat frame;
190 cap.retrieve(frame);
191
192 found = processFrame(frame, detector, src, tgt, nc);
193
194 int key = waitKey(10);
195 if (key == ' '){
196 if(found){
197 cout<<"Reference colors: "<<tgt<<endl<<"--------------------"<<endl;
198 cout<<"Actual colors: "<<src<<endl<<endl;
199 cout<<"Press spacebar to resume."<<endl;
200
201 waitKey(0);
202 cout << "Resumed! Processing continues..." << endl;
203 }
204 else{
205 cout<<"No color chart detected!!"<<endl;
206 }
207 }
208 else if (key == 27) exit(0);
209 }
210 if(found){
211 cout<<"Reference colors: "<<tgt<<endl<<"--------------------"<<endl;
212 cout<<"Actual colors: "<<src<<endl<<endl;
213 }
214 }
215 else{
216 found = processFrame(image, detector, src, tgt, nc);
217 if(found){
218 cout<<"Reference colors: "<<tgt<<endl<<"--------------------"<<endl;
219 cout<<"Actual colors: "<<src<<endl<<endl;
220 waitKey(0);
221 }
222 else{
223 cout<<"No chart detected!!"<<endl;
224 }
225 }
226 return 0;
227}
Designed for command line parsing.
Definition utility.hpp:890
n-dimensional dense array class
Definition mat.hpp:952
CV_NODISCARD_STD Mat clone() const
Creates a full copy of the array and the underlying data.
Class for video capturing from video files, image sequences or cameras.
Definition videoio.hpp:764
virtual bool open(const String &filename, int apiPreference=CAP_ANY)
Opens a video file or a capturing device or an IP video stream for video capturing.
virtual bool retrieve(OutputArray image, int flag=0)
Decodes and returns the grabbed video frame.
virtual bool isOpened() const
Returns true if video capturing has been initialized already.
virtual bool grab()
Grabs the next frame from video file or capturing device.
This class allows to create and manipulate comprehensive artificial neural networks.
Definition dnn.hpp:535
void setPreferableBackend(int backendId)
Ask network to use specific computation backend where it supported.
void setPreferableTarget(int targetId)
Ask network to make computations on specific target device.
std::string String
Definition cvstd.hpp:151
std::shared_ptr< _Tp > Ptr
Definition cvstd_wrapper.hpp:23
cv::String findFile(const cv::String &relative_path, bool required=true, bool silentMode=false)
Try to find requested data file.
#define CV_Assert(expr)
Checks a condition at runtime and throws exception if it fails.
Definition exception.hpp:198
Net readNetFromTensorflow(CV_WRAP_FILE_PATH const String &model, CV_WRAP_FILE_PATH const String &config=String(), int engine=ENGINE_AUTO, const std::vector< String > &extraOutputs=std::vector< String >())
Reads a network model stored in TensorFlow framework's format.
EngineType
Definition dnn.hpp:1020
@ ENGINE_CLASSIC
Force use the old dnn engine similar to 4.x branch.
Definition dnn.hpp:1021
@ ENGINE_AUTO
Try to use the new engine and then fall back to the classic version.
Definition dnn.hpp:1023
cv::gapi::GBackend backend()
Get a reference to CPU (OpenCV) backend.
int waitKey(int delay=0)
Waits for a pressed key.
CV_EXPORTS_W Mat imread(const String &filename, int flags=IMREAD_COLOR_BGR)
Loads an image from a file.
ColorChart
enum to hold the type of the checker
Definition mcc_checker_detector.hpp:53
int main(int argc, char *argv[])
Definition highgui_qt.cpp:3
Definition all_layers.hpp:47
Definition core.hpp:107
STL namespace.

Explanation

  1. Set header and namespaces

    #include <opencv2/mcc.hpp>
    using namespace std;
    using namespace cv;
    using namespace mcc;

    If you want you can set the namespace like the code above.

  2. Create the detector object
    Ptr<CCheckerDetector> detector = CCheckerDetector::create();
  3. Or create the detector object with neural network

    Ptr<CCheckerDetector> detector = CCheckerDetector::create(net);

    This is just to create the object.

  4. Run the detector

    detector->process(image, chartType);

    If the detector successfully detects atleast one chart, it return true otherwise it returns false. In the above given code we print a failure message if no chart were detected. Otherwise if it were successful, the list of colorcharts is stored inside the detector itself, we will see in the next step on how to extract it. By default it will detect atmost one chart, but you can tune the third parameter, nc(maximum number of charts), for detecting more charts.

  5. Get List of ColorCheckers

    std::vector<cv::Ptr<mcc::CChecker>> checkers;
    detector->getListColorChecker(checkers);

    All the colorcheckers that were detected are now stored in the 'checkers' vector.

  6. Draw the colorcheckers back to the image
    detector->draw(checkers, image);