stereo_match.cpp 10 KB

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