Merge pull request #1663 from vpisarev:ocl_experiments3
[profile/ivi/opencv.git] / samples / ocl / stereo_match.cpp
1 #include <iostream>
2 #include <string>
3 #include <sstream>
4 #include <iomanip>
5 #include <stdexcept>
6
7 #include "opencv2/core/utility.hpp"
8 #include "opencv2/ocl/ocl.hpp"
9 #include "opencv2/highgui/highgui.hpp"
10
11 using namespace cv;
12 using namespace std;
13 using namespace ocl;
14
15
16 struct App
17 {
18     App(CommandLineParser& cmd);
19     void run();
20     void handleKey(char key);
21     void printParams() const;
22
23     void workBegin()
24     {
25         work_begin = getTickCount();
26     }
27     void workEnd()
28     {
29         int64 d = getTickCount() - work_begin;
30         double f = getTickFrequency();
31         work_fps = f / d;
32     }
33     string method_str() const
34     {
35         switch (method)
36         {
37         case BM:
38             return "BM";
39         case BP:
40             return "BP";
41         case CSBP:
42             return "CSBP";
43         }
44         return "";
45     }
46     string text() const
47     {
48         stringstream ss;
49         ss << "(" << method_str() << ") FPS: " << setiosflags(ios::left)
50            << setprecision(4) << work_fps;
51         return ss.str();
52     }
53 private:
54     bool running, write_once;
55
56     Mat left_src, right_src;
57     Mat left, right;
58     oclMat d_left, d_right;
59
60     StereoBM_OCL bm;
61     StereoBeliefPropagation bp;
62     StereoConstantSpaceBP csbp;
63
64     int64 work_begin;
65     double work_fps;
66
67     string l_img, r_img;
68     string out_img;
69     enum {BM, BP, CSBP} method;
70     int ndisp; // Max disparity + 1
71     enum {GPU, CPU} type;
72 };
73
74 int main(int argc, char** argv)
75 {
76     const char* keys =
77         "{ h | help     | false                     | print help message }"
78         "{ l | left     |                           | specify left image }"
79         "{ r | right    |                           | specify right image }"
80         "{ m | method   | BM                        | specify match method(BM/BP/CSBP) }"
81         "{ n | ndisp    | 64                        |  specify number of disparity levels }"
82         "{ o | output   | stereo_match_output.jpg   | specify output path when input is images}";
83     CommandLineParser cmd(argc, argv, keys);
84     if (cmd.get<bool>("help"))
85     {
86         cout << "Available options:" << endl;
87         cmd.printMessage();
88         return 0;
89     }
90     try
91     {
92         App app(cmd);
93         cout << "Device name:" << cv::ocl::Context::getContext()->getDeviceInfo().deviceName << endl;
94
95         app.run();
96     }
97     catch (const exception& e)
98     {
99         cout << "error: " << e.what() << endl;
100     }
101     return 0;
102 }
103
104 App::App(CommandLineParser& cmd)
105     : running(false),method(BM)
106 {
107     cout << "stereo_match_ocl sample\n";
108     cout << "\nControls:\n"
109          << "\tesc - exit\n"
110          << "\to - save output image once\n"
111          << "\tp - print current parameters\n"
112          << "\tg - convert source images into gray\n"
113          << "\tm - change stereo match method\n"
114          << "\ts - change Sobel prefiltering flag (for BM only)\n"
115          << "\t1/q - increase/decrease maximum disparity\n"
116          << "\t2/w - increase/decrease window size (for BM only)\n"
117          << "\t3/e - increase/decrease iteration count (for BP and CSBP only)\n"
118          << "\t4/r - increase/decrease level count (for BP and CSBP only)\n";
119     l_img = cmd.get<string>("l");
120     r_img = cmd.get<string>("r");
121     string mstr = cmd.get<string>("m");
122     if(mstr == "BM") method = BM;
123     else if(mstr == "BP") method = BP;
124     else if(mstr == "CSBP") method = CSBP;
125     else cout << "unknown method!\n";
126     ndisp = cmd.get<int>("n");
127     out_img = cmd.get<string>("o");
128     write_once = false;
129 }
130
131
132 void App::run()
133 {
134     // Load images
135     left_src = imread(l_img);
136     right_src = imread(r_img);
137     if (left_src.empty()) throw runtime_error("can't open file \"" + l_img + "\"");
138     if (right_src.empty()) throw runtime_error("can't open file \"" + r_img + "\"");
139
140     cvtColor(left_src, left, COLOR_BGR2GRAY);
141     cvtColor(right_src, right, COLOR_BGR2GRAY);
142
143     d_left.upload(left);
144     d_right.upload(right);
145
146     imshow("left", left);
147     imshow("right", right);
148
149     // Set common parameters
150     bm.ndisp = ndisp;
151     bp.ndisp = ndisp;
152     csbp.ndisp = ndisp;
153
154     cout << endl;
155     printParams();
156
157     running = true;
158     while (running)
159     {
160         // Prepare disparity map of specified type
161         Mat disp;
162         oclMat d_disp;
163         workBegin();
164         switch (method)
165         {
166         case BM:
167             if (d_left.channels() > 1 || d_right.channels() > 1)
168             {
169                 cout << "BM doesn't support color images\n";
170                 cvtColor(left_src, left, COLOR_BGR2GRAY);
171                 cvtColor(right_src, right, COLOR_BGR2GRAY);
172                 cout << "image_channels: " << left.channels() << endl;
173                 d_left.upload(left);
174                 d_right.upload(right);
175                 imshow("left", left);
176                 imshow("right", right);
177             }
178             bm(d_left, d_right, d_disp);
179             break;
180         case BP:
181             bp(d_left, d_right, d_disp);
182             break;
183         case CSBP:
184             csbp(d_left, d_right, d_disp);
185             break;
186         }
187
188         // Show results
189         d_disp.download(disp);
190         workEnd();
191
192         if (method != BM)
193         {
194             disp.convertTo(disp, 0);
195         }
196         putText(disp, text(), Point(5, 25), FONT_HERSHEY_SIMPLEX, 1.0, Scalar::all(255));
197         imshow("disparity", disp);
198         if(write_once)
199         {
200             imwrite(out_img, disp);
201             write_once = false;
202         }
203         handleKey((char)waitKey(3));
204     }
205 }
206
207
208 void App::printParams() const
209 {
210     cout << "--- Parameters ---\n";
211     cout << "image_size: (" << left.cols << ", " << left.rows << ")\n";
212     cout << "image_channels: " << left.channels() << endl;
213     cout << "method: " << method_str() << endl
214          << "ndisp: " << ndisp << endl;
215     switch (method)
216     {
217     case BM:
218         cout << "win_size: " << bm.winSize << endl;
219         cout << "prefilter_sobel: " << bm.preset << endl;
220         break;
221     case BP:
222         cout << "iter_count: " << bp.iters << endl;
223         cout << "level_count: " << bp.levels << endl;
224         break;
225     case CSBP:
226         cout << "iter_count: " << csbp.iters << endl;
227         cout << "level_count: " << csbp.levels << endl;
228         break;
229     }
230     cout << endl;
231 }
232
233
234 void App::handleKey(char key)
235 {
236     switch (key)
237     {
238     case 27:
239         running = false;
240         break;
241     case 'p':
242     case 'P':
243         printParams();
244         break;
245     case 'g':
246     case 'G':
247         if (left.channels() == 1 && method != BM)
248         {
249             left = left_src;
250             right = right_src;
251         }
252         else
253         {
254             cvtColor(left_src, left, COLOR_BGR2GRAY);
255             cvtColor(right_src, right, COLOR_BGR2GRAY);
256         }
257         d_left.upload(left);
258         d_right.upload(right);
259         cout << "image_channels: " << left.channels() << endl;
260         imshow("left", left);
261         imshow("right", right);
262         break;
263     case 'm':
264     case 'M':
265         switch (method)
266         {
267         case BM:
268             method = BP;
269             break;
270         case BP:
271             method = CSBP;
272             break;
273         case CSBP:
274             method = BM;
275             break;
276         }
277         cout << "method: " << method_str() << endl;
278         break;
279     case 's':
280     case 'S':
281         if (method == BM)
282         {
283             switch (bm.preset)
284             {
285             case StereoBM_OCL::BASIC_PRESET:
286                 bm.preset = StereoBM_OCL::PREFILTER_XSOBEL;
287                 break;
288             case StereoBM_OCL::PREFILTER_XSOBEL:
289                 bm.preset = StereoBM_OCL::BASIC_PRESET;
290                 break;
291             }
292             cout << "prefilter_sobel: " << bm.preset << endl;
293         }
294         break;
295     case '1':
296         ndisp == 1 ? ndisp = 8 : ndisp += 8;
297         cout << "ndisp: " << ndisp << endl;
298         bm.ndisp = ndisp;
299         bp.ndisp = ndisp;
300         csbp.ndisp = ndisp;
301         break;
302     case 'q':
303     case 'Q':
304         ndisp = max(ndisp - 8, 1);
305         cout << "ndisp: " << ndisp << endl;
306         bm.ndisp = ndisp;
307         bp.ndisp = ndisp;
308         csbp.ndisp = ndisp;
309         break;
310     case '2':
311         if (method == BM)
312         {
313             bm.winSize = min(bm.winSize + 1, 51);
314             cout << "win_size: " << bm.winSize << endl;
315         }
316         break;
317     case 'w':
318     case 'W':
319         if (method == BM)
320         {
321             bm.winSize = max(bm.winSize - 1, 2);
322             cout << "win_size: " << bm.winSize << endl;
323         }
324         break;
325     case '3':
326         if (method == BP)
327         {
328             bp.iters += 1;
329             cout << "iter_count: " << bp.iters << endl;
330         }
331         else if (method == CSBP)
332         {
333             csbp.iters += 1;
334             cout << "iter_count: " << csbp.iters << endl;
335         }
336         break;
337     case 'e':
338     case 'E':
339         if (method == BP)
340         {
341             bp.iters = max(bp.iters - 1, 1);
342             cout << "iter_count: " << bp.iters << endl;
343         }
344         else if (method == CSBP)
345         {
346             csbp.iters = max(csbp.iters - 1, 1);
347             cout << "iter_count: " << csbp.iters << endl;
348         }
349         break;
350     case '4':
351         if (method == BP)
352         {
353             bp.levels += 1;
354             cout << "level_count: " << bp.levels << endl;
355         }
356         else if (method == CSBP)
357         {
358             csbp.levels += 1;
359             cout << "level_count: " << csbp.levels << endl;
360         }
361         break;
362     case 'r':
363     case 'R':
364         if (method == BP)
365         {
366             bp.levels = max(bp.levels - 1, 1);
367             cout << "level_count: " << bp.levels << endl;
368         }
369         else if (method == CSBP)
370         {
371             csbp.levels = max(csbp.levels - 1, 1);
372             cout << "level_count: " << csbp.levels << endl;
373         }
374         break;
375     case 'o':
376     case 'O':
377         write_once = true;
378         break;
379     }
380 }