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