stereo_match.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * stereo_match.cpp
  3. * calibration
  4. *
  5. * Created by Victor Eruhimov on 1/18/10.
  6. * Copyright 2010 Argus Corp. All rights reserved.
  7. *
  8. */
  9. #include "opencv2/calib3d/calib3d.hpp"
  10. #include "opencv2/imgproc.hpp"
  11. #include "opencv2/imgcodecs.hpp"
  12. #include "opencv2/highgui.hpp"
  13. #include "opencv2/core/utility.hpp"
  14. #include <stdio.h>
  15. #include <sstream>
  16. using namespace cv;
  17. static void print_help(char** argv)
  18. {
  19. printf("\nDemo stereo matching converting L and R images into disparity and point clouds\n");
  20. printf("\nUsage: %s <left_image> <right_image> [--algorithm=bm|sgbm|hh|hh4|sgbm3way] [--blocksize=<block_size>]\n"
  21. "[--max-disparity=<max_disparity>] [--scale=scale_factor>] [-i=<intrinsic_filename>] [-e=<extrinsic_filename>]\n"
  22. "[--no-display] [--color] [-o=<disparity_image>] [-p=<point_cloud_file>]\n", argv[0]);
  23. }
  24. static void saveXYZ(const char* filename, const Mat& mat)
  25. {
  26. const double max_z = 1.0e4;
  27. FILE* fp = fopen(filename, "wt");
  28. for(int y = 0; y < mat.rows; y++)
  29. {
  30. for(int x = 0; x < mat.cols; x++)
  31. {
  32. Vec3f point = mat.at<Vec3f>(y, x);
  33. if(fabs(point[2] - max_z) < FLT_EPSILON || fabs(point[2]) > max_z) continue;
  34. fprintf(fp, "%f %f %f\n", point[0], point[1], point[2]);
  35. }
  36. }
  37. fclose(fp);
  38. }
  39. int main(int argc, char** argv)
  40. {
  41. std::string img1_filename = "";
  42. std::string img2_filename = "";
  43. std::string intrinsic_filename = "";
  44. std::string extrinsic_filename = "";
  45. std::string disparity_filename = "";
  46. std::string point_cloud_filename = "";
  47. enum { STEREO_BM=0, STEREO_SGBM=1, STEREO_HH=2, STEREO_VAR=3, STEREO_3WAY=4, STEREO_HH4=5 };
  48. int alg = STEREO_SGBM;
  49. int SADWindowSize, numberOfDisparities;
  50. bool no_display;
  51. bool color_display;
  52. float scale;
  53. Ptr<StereoBM> bm = StereoBM::create(16,9);
  54. Ptr<StereoSGBM> sgbm = StereoSGBM::create(0,16,3);
  55. cv::CommandLineParser parser(argc, argv,
  56. "{@arg1||}{@arg2||}{help h||}{algorithm||}{max-disparity|0|}{blocksize|0|}{no-display||}{color||}{scale|1|}{i||}{e||}{o||}{p||}");
  57. if(parser.has("help"))
  58. {
  59. print_help(argv);
  60. return 0;
  61. }
  62. img1_filename = samples::findFile(parser.get<std::string>(0));
  63. img2_filename = samples::findFile(parser.get<std::string>(1));
  64. if (parser.has("algorithm"))
  65. {
  66. std::string _alg = parser.get<std::string>("algorithm");
  67. alg = _alg == "bm" ? STEREO_BM :
  68. _alg == "sgbm" ? STEREO_SGBM :
  69. _alg == "hh" ? STEREO_HH :
  70. _alg == "var" ? STEREO_VAR :
  71. _alg == "hh4" ? STEREO_HH4 :
  72. _alg == "sgbm3way" ? STEREO_3WAY : -1;
  73. }
  74. numberOfDisparities = parser.get<int>("max-disparity");
  75. SADWindowSize = parser.get<int>("blocksize");
  76. scale = parser.get<float>("scale");
  77. no_display = parser.has("no-display");
  78. color_display = parser.has("color");
  79. if( parser.has("i") )
  80. intrinsic_filename = parser.get<std::string>("i");
  81. if( parser.has("e") )
  82. extrinsic_filename = parser.get<std::string>("e");
  83. if( parser.has("o") )
  84. disparity_filename = parser.get<std::string>("o");
  85. if( parser.has("p") )
  86. point_cloud_filename = parser.get<std::string>("p");
  87. if (!parser.check())
  88. {
  89. parser.printErrors();
  90. return 1;
  91. }
  92. if( alg < 0 )
  93. {
  94. printf("Command-line parameter error: Unknown stereo algorithm\n\n");
  95. print_help(argv);
  96. return -1;
  97. }
  98. if ( numberOfDisparities < 1 || numberOfDisparities % 16 != 0 )
  99. {
  100. printf("Command-line parameter error: The max disparity (--maxdisparity=<...>) must be a positive integer divisible by 16\n");
  101. print_help(argv);
  102. return -1;
  103. }
  104. if (scale < 0)
  105. {
  106. printf("Command-line parameter error: The scale factor (--scale=<...>) must be a positive floating-point number\n");
  107. return -1;
  108. }
  109. if (SADWindowSize < 1 || SADWindowSize % 2 != 1)
  110. {
  111. printf("Command-line parameter error: The block size (--blocksize=<...>) must be a positive odd number\n");
  112. return -1;
  113. }
  114. if( img1_filename.empty() || img2_filename.empty() )
  115. {
  116. printf("Command-line parameter error: both left and right images must be specified\n");
  117. return -1;
  118. }
  119. if( (!intrinsic_filename.empty()) ^ (!extrinsic_filename.empty()) )
  120. {
  121. printf("Command-line parameter error: either both intrinsic and extrinsic parameters must be specified, or none of them (when the stereo pair is already rectified)\n");
  122. return -1;
  123. }
  124. if( extrinsic_filename.empty() && !point_cloud_filename.empty() )
  125. {
  126. printf("Command-line parameter error: extrinsic and intrinsic parameters must be specified to compute the point cloud\n");
  127. return -1;
  128. }
  129. int color_mode = alg == STEREO_BM ? 0 : -1;
  130. Mat img1 = imread(img1_filename, color_mode);
  131. Mat img2 = imread(img2_filename, color_mode);
  132. if (img1.empty())
  133. {
  134. printf("Command-line parameter error: could not load the first input image file\n");
  135. return -1;
  136. }
  137. if (img2.empty())
  138. {
  139. printf("Command-line parameter error: could not load the second input image file\n");
  140. return -1;
  141. }
  142. if (scale != 1.f)
  143. {
  144. Mat temp1, temp2;
  145. int method = scale < 1 ? INTER_AREA : INTER_CUBIC;
  146. resize(img1, temp1, Size(), scale, scale, method);
  147. img1 = temp1;
  148. resize(img2, temp2, Size(), scale, scale, method);
  149. img2 = temp2;
  150. }
  151. Size img_size = img1.size();
  152. Rect roi1, roi2;
  153. Mat Q;
  154. if( !intrinsic_filename.empty() )
  155. {
  156. // reading intrinsic parameters
  157. FileStorage fs(intrinsic_filename, FileStorage::READ);
  158. if(!fs.isOpened())
  159. {
  160. printf("Failed to open file %s\n", intrinsic_filename.c_str());
  161. return -1;
  162. }
  163. Mat M1, D1, M2, D2;
  164. fs["M1"] >> M1;
  165. fs["D1"] >> D1;
  166. fs["M2"] >> M2;
  167. fs["D2"] >> D2;
  168. M1 *= scale;
  169. M2 *= scale;
  170. fs.open(extrinsic_filename, FileStorage::READ);
  171. if(!fs.isOpened())
  172. {
  173. printf("Failed to open file %s\n", extrinsic_filename.c_str());
  174. return -1;
  175. }
  176. Mat R, T, R1, P1, R2, P2;
  177. fs["R"] >> R;
  178. fs["T"] >> T;
  179. stereoRectify( M1, D1, M2, D2, img_size, R, T, R1, R2, P1, P2, Q, CALIB_ZERO_DISPARITY, -1, img_size, &roi1, &roi2 );
  180. Mat map11, map12, map21, map22;
  181. initUndistortRectifyMap(M1, D1, R1, P1, img_size, CV_16SC2, map11, map12);
  182. initUndistortRectifyMap(M2, D2, R2, P2, img_size, CV_16SC2, map21, map22);
  183. Mat img1r, img2r;
  184. remap(img1, img1r, map11, map12, INTER_LINEAR);
  185. remap(img2, img2r, map21, map22, INTER_LINEAR);
  186. img1 = img1r;
  187. img2 = img2r;
  188. }
  189. numberOfDisparities = numberOfDisparities > 0 ? numberOfDisparities : ((img_size.width/8) + 15) & -16;
  190. bm->setROI1(roi1);
  191. bm->setROI2(roi2);
  192. bm->setPreFilterCap(31);
  193. bm->setBlockSize(SADWindowSize > 0 ? SADWindowSize : 9);
  194. bm->setMinDisparity(0);
  195. bm->setNumDisparities(numberOfDisparities);
  196. bm->setTextureThreshold(10);
  197. bm->setUniquenessRatio(15);
  198. bm->setSpeckleWindowSize(100);
  199. bm->setSpeckleRange(32);
  200. bm->setDisp12MaxDiff(1);
  201. sgbm->setPreFilterCap(63);
  202. int sgbmWinSize = SADWindowSize > 0 ? SADWindowSize : 3;
  203. sgbm->setBlockSize(sgbmWinSize);
  204. int cn = img1.channels();
  205. sgbm->setP1(8*cn*sgbmWinSize*sgbmWinSize);
  206. sgbm->setP2(32*cn*sgbmWinSize*sgbmWinSize);
  207. sgbm->setMinDisparity(0);
  208. sgbm->setNumDisparities(numberOfDisparities);
  209. sgbm->setUniquenessRatio(10);
  210. sgbm->setSpeckleWindowSize(100);
  211. sgbm->setSpeckleRange(32);
  212. sgbm->setDisp12MaxDiff(1);
  213. if(alg==STEREO_HH)
  214. sgbm->setMode(StereoSGBM::MODE_HH);
  215. else if(alg==STEREO_SGBM)
  216. sgbm->setMode(StereoSGBM::MODE_SGBM);
  217. else if(alg==STEREO_HH4)
  218. sgbm->setMode(StereoSGBM::MODE_HH4);
  219. else if(alg==STEREO_3WAY)
  220. sgbm->setMode(StereoSGBM::MODE_SGBM_3WAY);
  221. Mat disp, disp8;
  222. //Mat img1p, img2p, dispp;
  223. //copyMakeBorder(img1, img1p, 0, 0, numberOfDisparities, 0, IPL_BORDER_REPLICATE);
  224. //copyMakeBorder(img2, img2p, 0, 0, numberOfDisparities, 0, IPL_BORDER_REPLICATE);
  225. int64 t = getTickCount();
  226. float disparity_multiplier = 1.0f;
  227. if( alg == STEREO_BM )
  228. {
  229. bm->compute(img1, img2, disp);
  230. if (disp.type() == CV_16S)
  231. disparity_multiplier = 16.0f;
  232. }
  233. else if( alg == STEREO_SGBM || alg == STEREO_HH || alg == STEREO_HH4 || alg == STEREO_3WAY )
  234. {
  235. sgbm->compute(img1, img2, disp);
  236. if (disp.type() == CV_16S)
  237. disparity_multiplier = 16.0f;
  238. }
  239. t = getTickCount() - t;
  240. printf("Time elapsed: %fms\n", t*1000/getTickFrequency());
  241. //disp = dispp.colRange(numberOfDisparities, img1p.cols);
  242. if( alg != STEREO_VAR )
  243. disp.convertTo(disp8, CV_8U, 255/(numberOfDisparities*16.));
  244. else
  245. disp.convertTo(disp8, CV_8U);
  246. Mat disp8_3c;
  247. if (color_display)
  248. cv::applyColorMap(disp8, disp8_3c, COLORMAP_TURBO);
  249. if(!disparity_filename.empty())
  250. imwrite(disparity_filename, color_display ? disp8_3c : disp8);
  251. if(!point_cloud_filename.empty())
  252. {
  253. printf("storing the point cloud...");
  254. fflush(stdout);
  255. Mat xyz;
  256. Mat floatDisp;
  257. disp.convertTo(floatDisp, CV_32F, 1.0f / disparity_multiplier);
  258. reprojectImageTo3D(floatDisp, xyz, Q, true);
  259. saveXYZ(point_cloud_filename.c_str(), xyz);
  260. printf("\n");
  261. }
  262. if( !no_display )
  263. {
  264. std::ostringstream oss;
  265. oss << "disparity " << (alg==STEREO_BM ? "bm" :
  266. alg==STEREO_SGBM ? "sgbm" :
  267. alg==STEREO_HH ? "hh" :
  268. alg==STEREO_VAR ? "var" :
  269. alg==STEREO_HH4 ? "hh4" :
  270. alg==STEREO_3WAY ? "sgbm3way" : "");
  271. oss << " blocksize:" << (alg==STEREO_BM ? SADWindowSize : sgbmWinSize);
  272. oss << " max-disparity:" << numberOfDisparities;
  273. std::string disp_name = oss.str();
  274. namedWindow("left", cv::WINDOW_NORMAL);
  275. imshow("left", img1);
  276. namedWindow("right", cv::WINDOW_NORMAL);
  277. imshow("right", img2);
  278. namedWindow(disp_name, cv::WINDOW_AUTOSIZE);
  279. imshow(disp_name, color_display ? disp8_3c : disp8);
  280. printf("press ESC key or CTRL+C to close...");
  281. fflush(stdout);
  282. printf("\n");
  283. while(1)
  284. {
  285. if(waitKey() == 27) //ESC (prevents closing on actions like taking screenshots)
  286. break;
  287. }
  288. }
  289. return 0;
  290. }