io_utils.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  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. #ifndef OPENCV_RGBS_IO_UTILS_HPP
  5. #define OPENCV_RGBS_IO_UTILS_HPP
  6. #include <fstream>
  7. #include <iostream>
  8. #include <opencv2/calib3d.hpp>
  9. #include <opencv2/core.hpp>
  10. #include <opencv2/highgui.hpp>
  11. #include <opencv2/rgbd/kinfu.hpp>
  12. #include <opencv2/rgbd/large_kinfu.hpp>
  13. #include <opencv2/rgbd/colored_kinfu.hpp>
  14. namespace cv
  15. {
  16. namespace io_utils
  17. {
  18. static std::vector<std::string> readDepth(const std::string& fileList)
  19. {
  20. std::vector<std::string> v;
  21. std::fstream file(fileList);
  22. if (!file.is_open())
  23. throw std::runtime_error("Failed to read depth list");
  24. std::string dir;
  25. size_t slashIdx = fileList.rfind('/');
  26. slashIdx = slashIdx != std::string::npos ? slashIdx : fileList.rfind('\\');
  27. dir = fileList.substr(0, slashIdx);
  28. while (!file.eof())
  29. {
  30. std::string s, imgPath;
  31. std::getline(file, s);
  32. if (s.empty() || s[0] == '#')
  33. continue;
  34. std::stringstream ss;
  35. ss << s;
  36. double thumb;
  37. ss >> thumb >> imgPath;
  38. v.push_back(dir + '/' + imgPath);
  39. }
  40. return v;
  41. }
  42. struct DepthWriter
  43. {
  44. DepthWriter(std::string fileList) : file(fileList, std::ios::out), count(0), dir()
  45. {
  46. size_t slashIdx = fileList.rfind('/');
  47. slashIdx = slashIdx != std::string::npos ? slashIdx : fileList.rfind('\\');
  48. dir = fileList.substr(0, slashIdx);
  49. if (!file.is_open())
  50. throw std::runtime_error("Failed to write depth list");
  51. file << "# depth maps saved from device" << std::endl;
  52. file << "# useless_number filename" << std::endl;
  53. }
  54. void append(InputArray _depth)
  55. {
  56. Mat depth = _depth.getMat();
  57. std::string depthFname = cv::format("%04d.png", count);
  58. std::string fullDepthFname = dir + '/' + depthFname;
  59. if (!imwrite(fullDepthFname, depth))
  60. throw std::runtime_error("Failed to write depth to file " + fullDepthFname);
  61. file << count++ << " " << depthFname << std::endl;
  62. }
  63. std::fstream file;
  64. int count;
  65. std::string dir;
  66. };
  67. namespace Kinect2Params
  68. {
  69. static const Size depth_frameSize = Size(512, 424);
  70. // approximate values, no guarantee to be correct
  71. static const float depth_focal = 366.1f;
  72. static const float depth_cx = 258.2f;
  73. static const float depth_cy = 204.f;
  74. static const float depth_k1 = 0.12f;
  75. static const float depth_k2 = -0.34f;
  76. static const float depth_k3 = 0.12f;
  77. static const Size rgb_frameSize = Size(640, 480);
  78. static const float rgb_focal = 525.0f;
  79. static const float rgb_cx = 319.5f;
  80. static const float rgb_cy = 239.5f;
  81. static const float rgb_k1 = 0.0f;
  82. static const float rgb_k2 = 0.0f;
  83. static const float rgb_k3 = 0.0f;
  84. }; // namespace Kinect2Params
  85. namespace AstraParams
  86. {
  87. static const Size depth_frameSize = Size(640, 480);
  88. // approximate values, no guarantee to be correct
  89. static const float depth_fx = 535.4f;
  90. static const float depth_fy = 539.2f;
  91. static const float depth_cx = 320.1f;
  92. static const float depth_cy = 247.6f;
  93. static const float depth_k1 = 0.0f;
  94. static const float depth_k2 = 0.0f;
  95. static const float depth_k3 = 0.0f;
  96. static const Size rgb_frameSize = Size(640, 480);
  97. static const float rgb_focal = 525.0f;
  98. static const float rgb_cx = 319.5f;
  99. static const float rgb_cy = 239.5f;
  100. static const float rgb_k1 = 0.0f;
  101. static const float rgb_k2 = 0.0f;
  102. static const float rgb_k3 = 0.0f;
  103. }; // namespace Kinect2Params
  104. struct DepthSource
  105. {
  106. public:
  107. enum Type
  108. {
  109. DEPTH_LIST,
  110. DEPTH_KINECT2_LIST,
  111. DEPTH_KINECT2,
  112. DEPTH_REALSENSE,
  113. DEPTH_ASTRA
  114. };
  115. DepthSource(int cam) : DepthSource("", cam) {}
  116. DepthSource(String fileListName) : DepthSource(fileListName, -1) {}
  117. DepthSource(String fileListName, int cam)
  118. : depthFileList(fileListName.empty() ? std::vector<std::string>()
  119. : readDepth(fileListName)),
  120. frameIdx(0),
  121. undistortMap1(),
  122. undistortMap2()
  123. {
  124. if (cam >= 0)
  125. {
  126. vc = VideoCapture(VideoCaptureAPIs::CAP_OPENNI2 + cam);
  127. if (vc.isOpened())
  128. {
  129. if(cam == 20)
  130. sourceType = Type::DEPTH_ASTRA;
  131. else
  132. sourceType = Type::DEPTH_KINECT2;
  133. }
  134. else
  135. {
  136. vc = VideoCapture(VideoCaptureAPIs::CAP_REALSENSE + cam);
  137. if (vc.isOpened())
  138. {
  139. sourceType = Type::DEPTH_REALSENSE;
  140. }
  141. }
  142. }
  143. else
  144. {
  145. vc = VideoCapture();
  146. sourceType = Type::DEPTH_KINECT2_LIST;
  147. }
  148. }
  149. UMat getDepth()
  150. {
  151. UMat out;
  152. if (!vc.isOpened())
  153. {
  154. if (frameIdx < depthFileList.size())
  155. {
  156. Mat f = cv::imread(depthFileList[frameIdx++], IMREAD_ANYDEPTH);
  157. f.copyTo(out);
  158. }
  159. else
  160. {
  161. return UMat();
  162. }
  163. }
  164. else
  165. {
  166. vc.grab();
  167. switch (sourceType)
  168. {
  169. case Type::DEPTH_KINECT2: vc.retrieve(out, CAP_OPENNI_DEPTH_MAP); break;
  170. case Type::DEPTH_REALSENSE: vc.retrieve(out, CAP_INTELPERC_DEPTH_MAP); break;
  171. default:
  172. // unknown depth source
  173. vc.retrieve(out);
  174. }
  175. // workaround for Kinect 2
  176. if (sourceType == Type::DEPTH_KINECT2)
  177. {
  178. out = out(Rect(Point(), Kinect2Params::depth_frameSize));
  179. UMat outCopy;
  180. // linear remap adds gradient between valid and invalid pixels
  181. // which causes garbage, use nearest instead
  182. remap(out, outCopy, undistortMap1, undistortMap2, cv::INTER_NEAREST);
  183. cv::flip(outCopy, out, 1);
  184. }
  185. }
  186. if (out.empty())
  187. throw std::runtime_error("Matrix is empty");
  188. return out;
  189. }
  190. bool empty() { return depthFileList.empty() && !(vc.isOpened()); }
  191. void updateIntrinsics(Matx33f& _intrinsics, Size& _frameSize, float& _depthFactor)
  192. {
  193. if (vc.isOpened())
  194. {
  195. // this should be set in according to user's depth sensor
  196. int w = (int)vc.get(VideoCaptureProperties::CAP_PROP_FRAME_WIDTH);
  197. int h = (int)vc.get(VideoCaptureProperties::CAP_PROP_FRAME_HEIGHT);
  198. // it's recommended to calibrate sensor to obtain its intrinsics
  199. float fx, fy, cx, cy;
  200. float depthFactor = 1000.f;
  201. Size frameSize;
  202. if (sourceType == Type::DEPTH_KINECT2)
  203. {
  204. fx = fy = Kinect2Params::depth_focal;
  205. cx = Kinect2Params::depth_cx;
  206. cy = Kinect2Params::depth_cy;
  207. frameSize = Kinect2Params::depth_frameSize;
  208. }
  209. else if (sourceType == Type::DEPTH_ASTRA)
  210. {
  211. fx = AstraParams::depth_fx;
  212. fy = AstraParams::depth_fy;
  213. cx = AstraParams::depth_cx;
  214. cy = AstraParams::depth_cy;
  215. frameSize = AstraParams::depth_frameSize;
  216. }
  217. else
  218. {
  219. if (sourceType == Type::DEPTH_REALSENSE)
  220. {
  221. fx = (float)vc.get(CAP_PROP_INTELPERC_DEPTH_FOCAL_LENGTH_HORZ);
  222. fy = (float)vc.get(CAP_PROP_INTELPERC_DEPTH_FOCAL_LENGTH_VERT);
  223. depthFactor = 1.f / (float)vc.get(CAP_PROP_INTELPERC_DEPTH_SATURATION_VALUE);
  224. }
  225. else
  226. {
  227. fx = fy =
  228. (float)vc.get(CAP_OPENNI_DEPTH_GENERATOR | CAP_PROP_OPENNI_FOCAL_LENGTH);
  229. }
  230. cx = w / 2 - 0.5f;
  231. cy = h / 2 - 0.5f;
  232. frameSize = Size(w, h);
  233. }
  234. Matx33f camMatrix = Matx33f(fx, 0, cx, 0, fy, cy, 0, 0, 1);
  235. _intrinsics = camMatrix;
  236. _frameSize = frameSize;
  237. _depthFactor = depthFactor;
  238. }
  239. }
  240. void updateVolumeParams(const Vec3i& _resolution, float& _voxelSize, float& _tsdfTruncDist,
  241. Affine3f& _volumePose, float& _depthTruncateThreshold)
  242. {
  243. float volumeSize = 3.0f;
  244. _depthTruncateThreshold = 0.0f;
  245. // RealSense has shorter depth range, some params should be tuned
  246. if (sourceType == Type::DEPTH_REALSENSE)
  247. {
  248. volumeSize = 1.f;
  249. _voxelSize = volumeSize / _resolution[0];
  250. _tsdfTruncDist = 0.01f;
  251. _depthTruncateThreshold = 2.5f;
  252. }
  253. _volumePose = Affine3f().translate(Vec3f(-volumeSize / 2.f, -volumeSize / 2.f, 0.05f));
  254. }
  255. void updateICPParams(float& _icpDistThresh, float& _bilateralSigmaDepth)
  256. {
  257. _icpDistThresh = 0.1f;
  258. _bilateralSigmaDepth = 0.04f;
  259. // RealSense has shorter depth range, some params should be tuned
  260. if (sourceType == Type::DEPTH_REALSENSE)
  261. {
  262. _icpDistThresh = 0.01f;
  263. _bilateralSigmaDepth = 0.01f;
  264. }
  265. }
  266. void updateParams(large_kinfu::Params& params)
  267. {
  268. if (vc.isOpened())
  269. {
  270. updateIntrinsics(params.intr, params.frameSize, params.depthFactor);
  271. updateVolumeParams(params.volumeParams.resolution, params.volumeParams.voxelSize,
  272. params.volumeParams.tsdfTruncDist, params.volumeParams.pose,
  273. params.truncateThreshold);
  274. updateICPParams(params.icpDistThresh, params.bilateral_sigma_depth);
  275. if (sourceType == Type::DEPTH_KINECT2)
  276. {
  277. Matx<float, 1, 5> distCoeffs;
  278. distCoeffs(0) = Kinect2Params::depth_k1;
  279. distCoeffs(1) = Kinect2Params::depth_k2;
  280. distCoeffs(4) = Kinect2Params::depth_k3;
  281. initUndistortRectifyMap(params.intr, distCoeffs, cv::noArray(), params.intr,
  282. params.frameSize, CV_16SC2, undistortMap1, undistortMap2);
  283. }
  284. }
  285. }
  286. void updateParams(kinfu::Params& params)
  287. {
  288. if (vc.isOpened())
  289. {
  290. updateIntrinsics(params.intr, params.frameSize, params.depthFactor);
  291. updateVolumeParams(params.volumeDims, params.voxelSize,
  292. params.tsdf_trunc_dist, params.volumePose, params.truncateThreshold);
  293. updateICPParams(params.icpDistThresh, params.bilateral_sigma_depth);
  294. if (sourceType == Type::DEPTH_KINECT2)
  295. {
  296. Matx<float, 1, 5> distCoeffs;
  297. distCoeffs(0) = Kinect2Params::depth_k1;
  298. distCoeffs(1) = Kinect2Params::depth_k2;
  299. distCoeffs(4) = Kinect2Params::depth_k3;
  300. initUndistortRectifyMap(params.intr, distCoeffs, cv::noArray(), params.intr,
  301. params.frameSize, CV_16SC2, undistortMap1, undistortMap2);
  302. }
  303. }
  304. }
  305. void updateParams(colored_kinfu::Params& params)
  306. {
  307. if (vc.isOpened())
  308. {
  309. updateIntrinsics(params.intr, params.frameSize, params.depthFactor);
  310. updateVolumeParams(params.volumeDims, params.voxelSize,
  311. params.tsdf_trunc_dist, params.volumePose, params.truncateThreshold);
  312. updateICPParams(params.icpDistThresh, params.bilateral_sigma_depth);
  313. if (sourceType == Type::DEPTH_KINECT2)
  314. {
  315. Matx<float, 1, 5> distCoeffs;
  316. distCoeffs(0) = Kinect2Params::depth_k1;
  317. distCoeffs(1) = Kinect2Params::depth_k2;
  318. distCoeffs(4) = Kinect2Params::depth_k3;
  319. initUndistortRectifyMap(params.intr, distCoeffs, cv::noArray(), params.intr,
  320. params.frameSize, CV_16SC2, undistortMap1, undistortMap2);
  321. }
  322. }
  323. }
  324. std::vector<std::string> depthFileList;
  325. size_t frameIdx;
  326. VideoCapture vc;
  327. UMat undistortMap1, undistortMap2;
  328. Type sourceType;
  329. };
  330. static std::vector<std::string> readRGB(const std::string& fileList)
  331. {
  332. std::vector<std::string> v;
  333. std::fstream file(fileList);
  334. if (!file.is_open())
  335. throw std::runtime_error("Failed to read rgb list");
  336. std::string dir;
  337. size_t slashIdx = fileList.rfind('/');
  338. slashIdx = slashIdx != std::string::npos ? slashIdx : fileList.rfind('\\');
  339. dir = fileList.substr(0, slashIdx);
  340. while (!file.eof())
  341. {
  342. std::string s, imgPath;
  343. std::getline(file, s);
  344. if (s.empty() || s[0] == '#')
  345. continue;
  346. std::stringstream ss;
  347. ss << s;
  348. double thumb;
  349. ss >> thumb >> imgPath;
  350. v.push_back(dir + '/' + imgPath);
  351. }
  352. return v;
  353. }
  354. struct RGBWriter
  355. {
  356. RGBWriter(std::string fileList) : file(fileList, std::ios::out), count(0), dir()
  357. {
  358. size_t slashIdx = fileList.rfind('/');
  359. slashIdx = slashIdx != std::string::npos ? slashIdx : fileList.rfind('\\');
  360. dir = fileList.substr(0, slashIdx);
  361. if (!file.is_open())
  362. throw std::runtime_error("Failed to write rgb list");
  363. file << "# rgb maps saved from device" << std::endl;
  364. file << "# useless_number filename" << std::endl;
  365. }
  366. void append(InputArray _rgb)
  367. {
  368. Mat rgb = _rgb.getMat();
  369. std::string rgbFname = cv::format("%04d.png", count);
  370. std::string fullRGBFname = dir + '/' + rgbFname;
  371. if (!imwrite(fullRGBFname, rgb))
  372. throw std::runtime_error("Failed to write rgb to file " + fullRGBFname);
  373. file << count++ << " " << rgbFname << std::endl;
  374. }
  375. std::fstream file;
  376. int count;
  377. std::string dir;
  378. };
  379. struct RGBSource
  380. {
  381. public:
  382. enum Type
  383. {
  384. RGB_LIST,
  385. RGB_KINECT2_LIST,
  386. RGB_KINECT2,
  387. RGB_REALSENSE,
  388. RGB_ASTRA
  389. };
  390. RGBSource(int cam) : RGBSource("", cam) {}
  391. RGBSource(String fileListName) : RGBSource(fileListName, -1) {}
  392. RGBSource(String fileListName, int cam)
  393. : rgbFileList(fileListName.empty() ? std::vector<std::string>()
  394. : readRGB(fileListName)),
  395. frameIdx(0),
  396. undistortMap1(),
  397. undistortMap2()
  398. {
  399. if (cam >= 0)
  400. {
  401. vc = VideoCapture(VideoCaptureAPIs::CAP_OPENNI2 + cam);
  402. if (vc.isOpened())
  403. {
  404. if(cam == 20)
  405. sourceType = Type::RGB_ASTRA;
  406. else
  407. sourceType = Type::RGB_KINECT2;
  408. }
  409. else
  410. {
  411. vc = VideoCapture(VideoCaptureAPIs::CAP_REALSENSE + cam);
  412. if (vc.isOpened())
  413. {
  414. sourceType = Type::RGB_REALSENSE;
  415. }
  416. }
  417. }
  418. else
  419. {
  420. vc = VideoCapture();
  421. sourceType = Type::RGB_KINECT2_LIST;
  422. }
  423. }
  424. UMat getRGB()
  425. {
  426. UMat out;
  427. if (!vc.isOpened())
  428. {
  429. if (frameIdx < rgbFileList.size())
  430. {
  431. Mat f = cv::imread(rgbFileList[frameIdx++], IMREAD_COLOR);
  432. f.copyTo(out);
  433. }
  434. else
  435. {
  436. return UMat();
  437. }
  438. }
  439. else
  440. {
  441. vc.grab();
  442. switch (sourceType)
  443. {
  444. case Type::RGB_KINECT2: vc.retrieve(out, CAP_OPENNI_BGR_IMAGE); break;
  445. case Type::RGB_REALSENSE: vc.retrieve(out, CAP_INTELPERC_IMAGE); break;
  446. default:
  447. // unknown rgb source
  448. vc.retrieve(out);
  449. }
  450. // workaround for Kinect 2
  451. if (sourceType == Type::RGB_KINECT2)
  452. {
  453. out = out(Rect(Point(), Kinect2Params::rgb_frameSize));
  454. UMat outCopy;
  455. // linear remap adds gradient between valid and invalid pixels
  456. // which causes garbage, use nearest instead
  457. remap(out, outCopy, undistortMap1, undistortMap2, cv::INTER_NEAREST);
  458. cv::flip(outCopy, out, 1);
  459. }
  460. }
  461. if (out.empty())
  462. throw std::runtime_error("Matrix is empty");
  463. return out;
  464. }
  465. bool empty() { return rgbFileList.empty() && !(vc.isOpened()); }
  466. void updateIntrinsics(Matx33f& _rgb_intrinsics, Size& _rgb_frameSize)
  467. {
  468. if (vc.isOpened())
  469. {
  470. // this should be set in according to user's rgb sensor
  471. int w = (int)vc.get(VideoCaptureProperties::CAP_PROP_FRAME_WIDTH);
  472. int h = (int)vc.get(VideoCaptureProperties::CAP_PROP_FRAME_HEIGHT);
  473. // it's recommended to calibrate sensor to obtain its intrinsics
  474. float rgb_fx, rgb_fy, rgb_cx, rgb_cy;
  475. Size rgb_frameSize;
  476. if (sourceType == Type::RGB_KINECT2)
  477. {
  478. rgb_fx = rgb_fy = Kinect2Params::rgb_focal;
  479. rgb_cx = Kinect2Params::rgb_cx;
  480. rgb_cy = Kinect2Params::rgb_cy;
  481. rgb_frameSize = Kinect2Params::rgb_frameSize;
  482. }
  483. else if (sourceType == Type::RGB_ASTRA)
  484. {
  485. rgb_fx = rgb_fy = AstraParams::rgb_focal;
  486. rgb_cx = AstraParams::rgb_cx;
  487. rgb_cy = AstraParams::rgb_cy;
  488. rgb_frameSize = AstraParams::rgb_frameSize;
  489. }
  490. else
  491. {
  492. // TODO: replace to rgb types
  493. rgb_fx = rgb_fy = Kinect2Params::rgb_focal;
  494. rgb_cx = Kinect2Params::rgb_cx;
  495. rgb_cy = Kinect2Params::rgb_cy;
  496. rgb_frameSize = Size(w, h);
  497. }
  498. Matx33f rgb_camMatrix = Matx33f(rgb_fx, 0, rgb_cx, 0, rgb_fy, rgb_cy, 0, 0, 1);
  499. _rgb_intrinsics = rgb_camMatrix;
  500. _rgb_frameSize = rgb_frameSize;
  501. }
  502. }
  503. void updateVolumeParams(const Vec3i&, float&, float&, Affine3f&)
  504. {
  505. // TODO: do this settings for rgb image
  506. }
  507. void updateICPParams(float&)
  508. {
  509. // TODO: do this settings for rgb image icp
  510. }
  511. void updateParams(colored_kinfu::Params& params)
  512. {
  513. if (vc.isOpened())
  514. {
  515. updateIntrinsics(params.rgb_intr, params.rgb_frameSize);
  516. updateVolumeParams(params.volumeDims, params.voxelSize,
  517. params.tsdf_trunc_dist, params.volumePose);
  518. updateICPParams(params.icpDistThresh);
  519. if (sourceType == Type::RGB_KINECT2)
  520. {
  521. Matx<float, 1, 5> distCoeffs;
  522. distCoeffs(0) = Kinect2Params::rgb_k1;
  523. distCoeffs(1) = Kinect2Params::rgb_k2;
  524. distCoeffs(4) = Kinect2Params::rgb_k3;
  525. initUndistortRectifyMap(params.intr, distCoeffs, cv::noArray(), params.intr,
  526. params.frameSize, CV_16SC2, undistortMap1, undistortMap2);
  527. }
  528. }
  529. }
  530. std::vector<std::string> rgbFileList;
  531. size_t frameIdx;
  532. VideoCapture vc;
  533. UMat undistortMap1, undistortMap2;
  534. Type sourceType;
  535. };
  536. } // namespace io_utils
  537. } // namespace cv
  538. #endif /* ifndef OPENCV_RGBS_IO_UTILS_HPP */