odometry_evaluation.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html
  4. // This code is also subject to the license terms in the LICENSE_WillowGarage.md file found in this module's directory
  5. #include <opencv2/rgbd.hpp>
  6. #include <opencv2/highgui.hpp>
  7. #include <opencv2/calib3d.hpp>
  8. #include <opencv2/imgproc.hpp>
  9. #include <opencv2/core/utility.hpp>
  10. #include <iostream>
  11. #include <fstream>
  12. using namespace std;
  13. using namespace cv;
  14. using namespace cv::rgbd;
  15. #define BILATERAL_FILTER 0// if 1 then bilateral filter will be used for the depth
  16. class MyTickMeter
  17. {
  18. public:
  19. MyTickMeter() { reset(); }
  20. void start() { startTime = getTickCount(); }
  21. void stop()
  22. {
  23. int64 time = getTickCount();
  24. if ( startTime == 0 )
  25. return;
  26. ++counter;
  27. sumTime += ( time - startTime );
  28. startTime = 0;
  29. }
  30. int64 getTimeTicks() const { return sumTime; }
  31. double getTimeSec() const { return (double)getTimeTicks()/getTickFrequency(); }
  32. int64 getCounter() const { return counter; }
  33. void reset() { startTime = sumTime = 0; counter = 0; }
  34. private:
  35. int64 counter;
  36. int64 sumTime;
  37. int64 startTime;
  38. };
  39. static
  40. void writeResults( const string& filename, const vector<string>& timestamps, const vector<Mat>& Rt )
  41. {
  42. CV_Assert( timestamps.size() == Rt.size() );
  43. ofstream file( filename.c_str() );
  44. if( !file.is_open() )
  45. return;
  46. cout.precision(4);
  47. for( size_t i = 0; i < Rt.size(); i++ )
  48. {
  49. const Mat& Rt_curr = Rt[i];
  50. if( Rt_curr.empty() )
  51. continue;
  52. CV_Assert( Rt_curr.type() == CV_64FC1 );
  53. Mat R = Rt_curr(Rect(0,0,3,3)), rvec;
  54. Rodrigues(R, rvec);
  55. double alpha = norm( rvec );
  56. if(alpha > DBL_MIN)
  57. rvec = rvec / alpha;
  58. double cos_alpha2 = std::cos(0.5 * alpha);
  59. double sin_alpha2 = std::sin(0.5 * alpha);
  60. rvec *= sin_alpha2;
  61. CV_Assert( rvec.type() == CV_64FC1 );
  62. // timestamp tx ty tz qx qy qz qw
  63. file << timestamps[i] << " " << fixed
  64. << Rt_curr.at<double>(0,3) << " " << Rt_curr.at<double>(1,3) << " " << Rt_curr.at<double>(2,3) << " "
  65. << rvec.at<double>(0) << " " << rvec.at<double>(1) << " " << rvec.at<double>(2) << " " << cos_alpha2 << endl;
  66. }
  67. file.close();
  68. }
  69. static
  70. void setCameraMatrixFreiburg1(float& fx, float& fy, float& cx, float& cy)
  71. {
  72. fx = 517.3f; fy = 516.5f; cx = 318.6f; cy = 255.3f;
  73. }
  74. static
  75. void setCameraMatrixFreiburg2(float& fx, float& fy, float& cx, float& cy)
  76. {
  77. fx = 520.9f; fy = 521.0f; cx = 325.1f; cy = 249.7f;
  78. }
  79. /*
  80. * This sample helps to evaluate odometry on TUM datasets and benchmark http://vision.in.tum.de/data/datasets/rgbd-dataset.
  81. * At this link you can find instructions for evaluation. The sample runs some opencv odometry and saves a camera trajectory
  82. * to file of format that the benchmark requires. Saved file can be used for online evaluation.
  83. */
  84. int main(int argc, char** argv)
  85. {
  86. if(argc != 4)
  87. {
  88. cout << "Format: file_with_rgb_depth_pairs trajectory_file odometry_name [Rgbd or ICP or RgbdICP or FastICP]" << endl;
  89. return -1;
  90. }
  91. vector<string> timestamps;
  92. vector<Mat> Rts;
  93. const string filename = argv[1];
  94. ifstream file( filename.c_str() );
  95. if( !file.is_open() )
  96. return -1;
  97. char dlmrt = '/';
  98. size_t pos = filename.rfind(dlmrt);
  99. string dirname = pos == string::npos ? "" : filename.substr(0, pos) + dlmrt;
  100. const int timestampLength = 17;
  101. const int rgbPathLehgth = 17+8;
  102. const int depthPathLehgth = 17+10;
  103. float fx = 525.0f, // default
  104. fy = 525.0f,
  105. cx = 319.5f,
  106. cy = 239.5f;
  107. if(filename.find("freiburg1") != string::npos)
  108. setCameraMatrixFreiburg1(fx, fy, cx, cy);
  109. if(filename.find("freiburg2") != string::npos)
  110. setCameraMatrixFreiburg2(fx, fy, cx, cy);
  111. Mat cameraMatrix = Mat::eye(3,3,CV_32FC1);
  112. {
  113. cameraMatrix.at<float>(0,0) = fx;
  114. cameraMatrix.at<float>(1,1) = fy;
  115. cameraMatrix.at<float>(0,2) = cx;
  116. cameraMatrix.at<float>(1,2) = cy;
  117. }
  118. Ptr<OdometryFrame> frame_prev = Ptr<OdometryFrame>(new OdometryFrame()),
  119. frame_curr = Ptr<OdometryFrame>(new OdometryFrame());
  120. Ptr<Odometry> odometry = Odometry::create(string(argv[3]) + "Odometry");
  121. if(odometry.empty())
  122. {
  123. cout << "Can not create Odometry algorithm. Check the passed odometry name." << endl;
  124. return -1;
  125. }
  126. odometry->setCameraMatrix(cameraMatrix);
  127. MyTickMeter gtm;
  128. int count = 0;
  129. for(int i = 0; !file.eof(); i++)
  130. {
  131. string str;
  132. std::getline(file, str);
  133. if(str.empty()) break;
  134. if(str.at(0) == '#') continue; /* comment */
  135. Mat image, depth;
  136. // Read one pair (rgb and depth)
  137. // example: 1305031453.359684 rgb/1305031453.359684.png 1305031453.374112 depth/1305031453.374112.png
  138. #if BILATERAL_FILTER
  139. MyTickMeter tm_bilateral_filter;
  140. #endif
  141. {
  142. string rgbFilename = str.substr(timestampLength + 1, rgbPathLehgth );
  143. string timestap = str.substr(0, timestampLength);
  144. string depthFilename = str.substr(2*timestampLength + rgbPathLehgth + 3, depthPathLehgth );
  145. image = imread(dirname + rgbFilename);
  146. depth = imread(dirname + depthFilename, -1);
  147. CV_Assert(!image.empty());
  148. CV_Assert(!depth.empty());
  149. CV_Assert(depth.type() == CV_16UC1);
  150. cout << i << " " << rgbFilename << " " << depthFilename << endl;
  151. // scale depth
  152. Mat depth_flt;
  153. depth.convertTo(depth_flt, CV_32FC1, 1.f/5000.f);
  154. #if !BILATERAL_FILTER
  155. depth_flt.setTo(std::numeric_limits<float>::quiet_NaN(), depth == 0);
  156. depth = depth_flt;
  157. #else
  158. tm_bilateral_filter.start();
  159. depth = Mat(depth_flt.size(), CV_32FC1, Scalar(0));
  160. const double depth_sigma = 0.03;
  161. const double space_sigma = 4.5; // in pixels
  162. Mat invalidDepthMask = depth_flt == 0.f;
  163. depth_flt.setTo(-5*depth_sigma, invalidDepthMask);
  164. bilateralFilter(depth_flt, depth, -1, depth_sigma, space_sigma);
  165. depth.setTo(std::numeric_limits<float>::quiet_NaN(), invalidDepthMask);
  166. tm_bilateral_filter.stop();
  167. cout << "Time filter " << tm_bilateral_filter.getTimeSec() << endl;
  168. #endif
  169. timestamps.push_back( timestap );
  170. }
  171. {
  172. Mat gray;
  173. cvtColor(image, gray, COLOR_BGR2GRAY);
  174. frame_curr->image = gray;
  175. frame_curr->depth = depth;
  176. Mat Rt;
  177. if(!Rts.empty())
  178. {
  179. MyTickMeter tm;
  180. tm.start();
  181. gtm.start();
  182. bool res = odometry->compute(frame_curr, frame_prev, Rt);
  183. gtm.stop();
  184. tm.stop();
  185. count++;
  186. cout << "Time " << tm.getTimeSec() << endl;
  187. #if BILATERAL_FILTER
  188. cout << "Time ratio " << tm_bilateral_filter.getTimeSec() / tm.getTimeSec() << endl;
  189. #endif
  190. if(!res)
  191. Rt = Mat::eye(4,4,CV_64FC1);
  192. }
  193. if( Rts.empty() )
  194. Rts.push_back(Mat::eye(4,4,CV_64FC1));
  195. else
  196. {
  197. Mat& prevRt = *Rts.rbegin();
  198. cout << "Rt " << Rt << endl;
  199. Rts.push_back( prevRt * Rt );
  200. }
  201. if(!frame_prev.empty())
  202. frame_prev->release();
  203. std::swap(frame_prev, frame_curr);
  204. }
  205. }
  206. std::cout << "Average time " << gtm.getTimeSec()/count << std::endl;
  207. writeResults(argv[2], timestamps, Rts);
  208. return 0;
  209. }