1
2 #include "opencv2/core.hpp"
3 #include "opencv2/highgui.hpp"
4 #include "opencv2/imgproc.hpp"
5 #include "opencv2/core/utility.hpp"
6
7 #include <time.h>
8 #include <vector>
9 #include <iostream>
10 #include <opencv2/ximgproc.hpp>
11
12
13
14 using namespace cv;
15
16 #ifdef HAVE_EIGEN
17
18 #define MARK_RADIUS 5
19 #define PALLET_RADIUS 100
20 int max_width = 1280;
21 int max_height = 720;
22
23 static int globalMouseX;
24 static int globalMouseY;
25 static int selected_r;
26 static int selected_g;
27 static int selected_b;
28 static bool globalMouseClick = false;
29 static bool glb_mouse_left = false;
30 static bool drawByReference = false;
31 static bool mouseDraw = false;
32 static bool mouseClick;
33 static bool mouseLeft;
34 static int mouseX;
35 static int mouseY;
36
37 cv::Mat mat_draw;
38 cv::Mat mat_input_gray;
39 cv::Mat mat_input_reference;
40 cv::Mat mat_input_confidence;
41 cv::Mat mat_pallet(PALLET_RADIUS*2,PALLET_RADIUS*2,CV_8UC3);
42
43
44 static void mouseCallback(int event, int x, int y, int flags, void* param);
45 void drawTrajectoryByReference(cv::Mat& img);
46 double module(Point pt);
47 double distance(Point pt1, Point pt2);
48 double cross(Point pt1, Point pt2);
49 double angle(Point pt1, Point pt2);
50 int inCircle(Point p, Point c, int r);
51 void createPlate(Mat &im1, int radius);
52
53
54 #endif
55
56 const String keys =
57 "{help h usage ? | | print this message }"
58 "{@image | | input image }"
59 "{sigma_spatial |8 | parameter of post-filtering }"
60 "{sigma_luma |8 | parameter of post-filtering }"
61 "{sigma_chroma |8 | parameter of post-filtering }"
62 "{dst_path |None | optional path to save the resulting colorized image }"
63 "{dst_raw_path |None | optional path to save drawed image before filtering }"
64 "{draw_by_reference |false | optional flag to use color image as reference }"
65 ;
66
67
68
main(int argc,char * argv[])69 int main(int argc, char* argv[])
70 {
71
72 CommandLineParser parser(argc,argv,keys);
73 parser.about("fastBilateralSolverFilter Demo");
74 if (parser.has("help"))
75 {
76 parser.printMessage();
77 return 0;
78 }
79
80 #ifdef HAVE_EIGEN
81
82 String img = parser.get<String>(0);
83 double sigma_spatial = parser.get<double>("sigma_spatial");
84 double sigma_luma = parser.get<double>("sigma_luma");
85 double sigma_chroma = parser.get<double>("sigma_chroma");
86 String dst_path = parser.get<String>("dst_path");
87 String dst_raw_path = parser.get<String>("dst_raw_path");
88 drawByReference = parser.get<bool>("draw_by_reference");
89
90 mat_input_reference = cv::imread(img, IMREAD_COLOR);
91 if (mat_input_reference.empty())
92 {
93 std::cerr << "input image '" << img << "' could not be read !" << std::endl << std::endl;
94 parser.printMessage();
95 return 1;
96 }
97
98 cvtColor(mat_input_reference, mat_input_gray, COLOR_BGR2GRAY);
99
100 if(mat_input_gray.cols > max_width)
101 {
102 double scale = float(max_width) / float(mat_input_gray.cols);
103 cv::resize(mat_input_reference, mat_input_reference, cv::Size(), scale, scale);
104 cv::resize(mat_input_gray, mat_input_gray, cv::Size(), scale, scale);
105 }
106
107 if(mat_input_gray.rows > max_height)
108 {
109 double scale = float(max_height) / float(mat_input_gray.rows);
110 cv::resize(mat_input_reference, mat_input_reference, cv::Size(), scale, scale);
111 cv::resize(mat_input_gray, mat_input_gray, cv::Size(), scale, scale);
112 }
113
114
115 float filtering_time;
116 std::cout << "mat_input_reference:" << mat_input_reference.cols<<"x"<< mat_input_reference.rows<< std::endl;
117 std::cout << "please select a color from the palette, by clicking into that," << std::endl;
118 std::cout << " then select a coarse region in the image to be coloured." << std::endl;
119 std::cout << " press 'escape' to see the final coloured image." << std::endl;
120
121
122 cv::Mat mat_gray;
123 cv::cvtColor(mat_input_reference, mat_gray, cv::COLOR_BGR2GRAY);
124
125 cv::Mat target = mat_input_reference.clone();
126 cvtColor(mat_gray, mat_input_reference, COLOR_GRAY2BGR);
127
128 cv::namedWindow("draw", cv::WINDOW_AUTOSIZE);
129
130 // construct pallet
131 createPlate(mat_pallet, PALLET_RADIUS);
132 selected_b = 0;
133 selected_g = 0;
134 selected_r = 0;
135
136 cv::Mat mat_show(target.rows,target.cols+PALLET_RADIUS*2,CV_8UC3);
137 cv::Mat color_select(target.rows-mat_pallet.rows,PALLET_RADIUS*2,CV_8UC3,cv::Scalar(selected_b, selected_g, selected_r));
138 target.copyTo(Mat(mat_show,Rect(0,0,target.cols,target.rows)));
139 mat_pallet.copyTo(Mat(mat_show,Rect(target.cols,0,mat_pallet.cols,mat_pallet.rows)));
140 color_select.copyTo(Mat(mat_show,Rect(target.cols,PALLET_RADIUS*2,color_select.cols,color_select.rows)));
141
142 cv::imshow("draw", mat_show);
143 cv::setMouseCallback("draw", mouseCallback, (void *)&mat_show);
144 mat_input_confidence = 0*cv::Mat::ones(mat_gray.size(),mat_gray.type());
145
146 int show_count = 0;
147 while (1)
148 {
149 mouseX = globalMouseX;
150 mouseY = globalMouseY;
151 mouseClick = globalMouseClick;
152 mouseLeft = glb_mouse_left;
153
154
155 if (mouseClick)
156 {
157 drawTrajectoryByReference(target);
158
159 if(show_count%5==0)
160 {
161 cv::Mat target_temp(target.size(),target.type());
162 filtering_time = static_cast<float>(getTickCount());
163 if(mouseDraw)
164 {
165 cv::cvtColor(target, target_temp, cv::COLOR_BGR2YCrCb);
166 std::vector<cv::Mat> src_channels;
167 std::vector<cv::Mat> dst_channels;
168
169 cv::split(target_temp,src_channels);
170
171 cv::Mat result1 = cv::Mat(mat_input_gray.size(),mat_input_gray.type());
172 cv::Mat result2 = cv::Mat(mat_input_gray.size(),mat_input_gray.type());
173
174 dst_channels.push_back(mat_input_gray);
175 cv::ximgproc::fastBilateralSolverFilter(mat_input_gray,src_channels[1],mat_input_confidence,result1,sigma_spatial,sigma_luma,sigma_chroma);
176 dst_channels.push_back(result1);
177 cv::ximgproc::fastBilateralSolverFilter(mat_input_gray,src_channels[2],mat_input_confidence,result2,sigma_spatial,sigma_luma,sigma_chroma);
178 dst_channels.push_back(result2);
179
180 cv::merge(dst_channels,target_temp);
181 cv::cvtColor(target_temp, target_temp, cv::COLOR_YCrCb2BGR);
182 }
183 else
184 {
185 target_temp = target.clone();
186 }
187 filtering_time = static_cast<float>(((double)getTickCount() - filtering_time)/getTickFrequency());
188 std::cout << "solver time: " << filtering_time << "s" << std::endl;
189
190 cv::Mat color_selected(target_temp.rows-mat_pallet.rows,PALLET_RADIUS*2,CV_8UC3,cv::Scalar(selected_b, selected_g, selected_r));
191 target_temp.copyTo(Mat(mat_show,Rect(0,0,target_temp.cols,target_temp.rows)));
192 mat_pallet.copyTo(Mat(mat_show,Rect(target_temp.cols,0,mat_pallet.cols,mat_pallet.rows)));
193 color_selected.copyTo(Mat(mat_show,Rect(target_temp.cols,PALLET_RADIUS*2,color_selected.cols,color_selected.rows)));
194 cv::imshow("draw", mat_show);
195 }
196 show_count++;
197 }
198 if (cv::waitKey(2) == 27)
199 break;
200 }
201 mat_draw = target.clone();
202 cv::cvtColor(target, target, cv::COLOR_BGR2YCrCb);
203
204 std::vector<cv::Mat> src_channels;
205 std::vector<cv::Mat> dst_channels;
206
207 cv::split(target,src_channels);
208
209 cv::Mat result1 = cv::Mat(mat_input_gray.size(),mat_input_gray.type());
210 cv::Mat result2 = cv::Mat(mat_input_gray.size(),mat_input_gray.type());
211
212 filtering_time = static_cast<float>(getTickCount());
213
214 // dst_channels.push_back(src_channels[0]);
215 dst_channels.push_back(mat_input_gray);
216 cv::ximgproc::fastBilateralSolverFilter(mat_input_gray,src_channels[1],mat_input_confidence,result1,sigma_spatial,sigma_luma,sigma_chroma);
217 dst_channels.push_back(result1);
218 cv::ximgproc::fastBilateralSolverFilter(mat_input_gray,src_channels[2],mat_input_confidence,result2,sigma_spatial,sigma_luma,sigma_chroma);
219 dst_channels.push_back(result2);
220
221 cv::merge(dst_channels,target);
222 cv::cvtColor(target, target, cv::COLOR_YCrCb2BGR);
223
224 filtering_time = static_cast<float>(((double)getTickCount() - filtering_time)/getTickFrequency());
225 std::cout << "solver time: " << filtering_time << "s" << std::endl;
226
227
228
229 cv::imshow("mat_draw",mat_draw);
230 cv::imshow("output",target);
231
232 if(dst_path!="None")
233 {
234 imwrite(dst_path,target);
235 }
236 if(dst_raw_path!="None")
237 {
238 imwrite(dst_raw_path,mat_draw);
239 }
240
241 cv::waitKey(0);
242
243
244
245 #else
246 std::cout << "Can not find eigen, please build with eigen by set WITH_EIGEN=ON" << '\n';
247 #endif
248
249 return 0;
250 }
251
252
253 #ifdef HAVE_EIGEN
mouseCallback(int event,int x,int y,int,void *)254 static void mouseCallback(int event, int x, int y, int, void*)
255 {
256 switch (event)
257 {
258 case cv::EVENT_MOUSEMOVE:
259 if (globalMouseClick)
260 {
261 globalMouseX = x;
262 globalMouseY = y;
263 }
264 break;
265
266 case cv::EVENT_LBUTTONDOWN:
267 globalMouseClick = true;
268 globalMouseX = x;
269 globalMouseY = y;
270 break;
271
272 case cv::EVENT_LBUTTONUP:
273 glb_mouse_left = true;
274 globalMouseClick = false;
275 break;
276 }
277 }
278
drawTrajectoryByReference(cv::Mat & img)279 void drawTrajectoryByReference(cv::Mat& img)
280 {
281 int i, j;
282 uchar red, green, blue;
283 float gray;
284 int y, x;
285 int r = MARK_RADIUS;
286 int r2 = r * r;
287 uchar* colorPix;
288 uchar* grayPix;
289
290 if(mouseY < PALLET_RADIUS*2 && img.cols <= mouseX && mouseX < img.cols+PALLET_RADIUS*2)
291 {
292 colorPix = mat_pallet.ptr<uchar>(mouseY, mouseX - img.cols);
293 // colorPix = mat_pallet.ptr<uchar>(mouseY, mouseX);
294 selected_b = *colorPix;
295 colorPix++;
296 selected_g = *colorPix;
297 colorPix++;
298 selected_r = *colorPix;
299 colorPix++;
300 std::cout << "x y:("<<mouseX<<"," <<mouseY<< " rgb_select:("<< selected_r<<","<<selected_g<<","<<selected_b<<")" << '\n';
301 }
302 else
303 {
304 mouseDraw = true;
305 y = mouseY - r;
306 for(i=-r; i<r+1 ; i++, y++)
307 {
308 x = mouseX - r;
309 colorPix = mat_input_reference.ptr<uchar>(y, x);
310 grayPix = mat_input_gray.ptr<uchar>(y, x);
311 for(j=-r; j<r+1; j++, x++)
312 {
313 if(i*i + j*j > r2)
314 {
315 colorPix += mat_input_reference.channels();
316 grayPix += mat_input_gray.channels();
317 continue;
318 }
319
320 if(y<0 || y>=mat_input_reference.rows || x<0 || x>=mat_input_reference.cols)
321 {
322 break;
323 }
324
325 blue = *colorPix;
326 colorPix++;
327 green = *colorPix;
328 colorPix++;
329 red = *colorPix;
330 colorPix++;
331 gray = *grayPix;
332 grayPix++;
333 mat_input_confidence.at<uchar>(y,x) = 255;
334 float draw_y = 0.229f*(float(selected_r)) + 0.587f*(float(selected_g)) + 0.114f*(float(selected_b));
335 int draw_b = int(float(selected_b)*(gray/draw_y));
336 int draw_g = int(float(selected_g)*(gray/draw_y));
337 int draw_r = int(float(selected_r)*(gray/draw_y));
338
339 if(drawByReference)
340 {
341 cv::circle(img, cv::Point2d(x, y), 1, cv::Scalar(blue, green, red), -1);
342 }
343 else
344 {
345 cv::circle(img, cv::Point2d(x, y), 1, cv::Scalar(draw_b, draw_g, draw_r), -1);
346 }
347 }
348 }
349 }
350 }
351
module(Point pt)352 double module(Point pt)
353 {
354 return sqrt((double)pt.x*pt.x + pt.y*pt.y);
355 }
356
distance(Point pt1,Point pt2)357 double distance(Point pt1, Point pt2)
358 {
359 int dx = pt1.x - pt2.x;
360 int dy = pt1.y - pt2.y;
361 return sqrt((double)dx*dx + dy*dy);
362 }
363
cross(Point pt1,Point pt2)364 double cross(Point pt1, Point pt2)
365 {
366 return pt1.x*pt2.x + pt1.y*pt2.y;
367 }
368
angle(Point pt1,Point pt2)369 double angle(Point pt1, Point pt2)
370 {
371 return acos(cross(pt1, pt2) / (module(pt1)*module(pt2) + DBL_EPSILON));
372 }
373
374 // p or c is the center
inCircle(Point p,Point c,int r)375 int inCircle(Point p, Point c, int r)
376 {
377 int dx = p.x - c.x;
378 int dy = p.y - c.y;
379 return dx*dx + dy*dy <= r*r ? 1 : 0;
380
381 }
382
383 //draw the hsv-plate
createPlate(Mat & im1,int radius)384 void createPlate(Mat &im1, int radius)
385 {
386 Mat hsvImag(Size(radius << 1, radius << 1), CV_8UC3, Scalar(0, 0, 255));
387 int w = hsvImag.cols;
388 int h = hsvImag.rows;
389 int cx = w >> 1;
390 int cy = h >> 1;
391 Point pt1(cx, 0);
392
393 for (int j = 0; j < w; j++)
394 {
395 for (int i = 0; i < h; i++)
396 {
397 Point pt2(j - cx, i - cy);
398 if (inCircle(Point(0, 0), pt2, radius))
399 {
400 int theta = static_cast<int>(angle(pt1, pt2) * 180 / CV_PI);
401 if (i > cx)
402 {
403 theta = -theta + 360;
404 }
405 hsvImag.at<Vec3b>(i, j)[0] = saturate_cast<uchar>(theta / 2);
406 hsvImag.at<Vec3b>(i, j)[1] = saturate_cast<uchar>(module(pt2) / cx * 255);
407 hsvImag.at<Vec3b>(i, j)[2] = 255;
408 }
409 }
410 }
411
412
413 cvtColor(hsvImag, im1, COLOR_HSV2BGR);
414 }
415
416
417 #endif
418