3d-scanner.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #include <librealsense2/rs.hpp>
  2. #include <iostream>
  3. #include <filesystem>
  4. #include <pcl/io/ply_io.h>
  5. #include <pcl/point_types.h>
  6. #include "pcl-helper.hpp"
  7. struct ColoredPoints
  8. {
  9. rs2::points points;
  10. rs2::video_frame color;
  11. ColoredPoints(rs2::points p, rs2::video_frame c) : points(p), color(c) {}
  12. };
  13. void configure_filters(rs2::decimation_filter &dec_filter, rs2::threshold_filter &thr_filter, rs2::spatial_filter &spat_filter, int dec_filter_magnitude, float min_dist, float max_dist, int magnitude, int smooth_alpha, int smooth_delta, int holes_fill);
  14. void apply_filters(rs2::decimation_filter &dec_filter, rs2::threshold_filter &thr_filter, rs2::spatial_filter &spat_filter, rs2::disparity_transform &depth_to_disparity, rs2::disparity_transform &disparity_to_depth, rs2::depth_frame &depth_frame);
  15. ColoredPoints scan(rs2::decimation_filter &dec_filter, rs2::threshold_filter &thr_filter, rs2::spatial_filter &spat_filter, rs2::disparity_transform &depth_to_disparity, rs2::disparity_transform &disparity_to_depth, rs2::pipeline &pipe);
  16. void scan_and_convert(rs2::decimation_filter &dec_filter, rs2::threshold_filter &thr_filter, rs2::spatial_filter &spat_filter, rs2::disparity_transform &depth_to_disparity, rs2::disparity_transform &disparity_to_depth, rs2::pipeline &pipe, std::vector<PCLHelper::PtrCloud> &pointclouds);
  17. bool align_and_save_pointclouds(std::vector<PCLHelper::PtrCloud> &pointclouds);
  18. void save_original_pointclouds(std::vector<PCLHelper::PtrCloud> &pointclouds);
  19. void wipe_old_scans();
  20. int prompt_user();
  21. int main()
  22. try
  23. {
  24. rs2::pipeline pipe;
  25. pipe.start();
  26. // define filters
  27. rs2::decimation_filter dec_filter; // Decimation - reduces depth frame density
  28. rs2::threshold_filter thr_filter; // Threshold - removes values outside recommended range
  29. rs2::spatial_filter spat_filter; // Spatial - edge-preserving spatial smoothing
  30. // rs2::hole_filling_filter hole_filter; // Hole filling - fills small holes in the depth image
  31. const std::string disparity_filter_name = "Disparity"; // Declare disparity transform from depth to disparity and vice versa
  32. rs2::disparity_transform depth_to_disparity(true);
  33. rs2::disparity_transform disparity_to_depth(false);
  34. configure_filters(dec_filter, thr_filter, spat_filter, 3, 0.0, 0.4, 5, 1, 1, 5);
  35. std::vector<PCLHelper::PtrCloud> pointclouds;
  36. PCLHelper::PtrCloud converted_points;
  37. PCLHelper::PtrCloud cropped_points;
  38. bool running = true;
  39. while (running)
  40. {
  41. int number = prompt_user();
  42. switch (number)
  43. {
  44. case 1:
  45. scan_and_convert(dec_filter, thr_filter, spat_filter, depth_to_disparity, disparity_to_depth, pipe, pointclouds);
  46. break;
  47. case 2:
  48. if (pointclouds.size() < 2)
  49. {
  50. std::cout << "Not enough pointclouds to merge, just exiting...";
  51. }
  52. else
  53. {
  54. save_original_pointclouds(pointclouds);
  55. if (!align_and_save_pointclouds(pointclouds))
  56. {
  57. std::cout << "Failed to align pointclouds, exiting...";
  58. break;
  59. }
  60. std::cout << "\nYou can find the scanned object parts in the output[Nr].ply files.";
  61. }
  62. break;
  63. case 3:
  64. pointclouds.clear();
  65. std::cout << "Scan buffer cleared.";
  66. wipe_old_scans();
  67. break;
  68. case 4:
  69. std::cout << "Exiting...";
  70. running = false;
  71. break;
  72. default:
  73. std::cout << "Invalid option, please try again.";
  74. break;
  75. }
  76. }
  77. return EXIT_SUCCESS;
  78. }
  79. catch (const rs2::error &e)
  80. {
  81. std::cerr << "RealSense error calling " << e.get_failed_function() << "(" << e.get_failed_args() << "):\n " << e.what() << std::endl;
  82. return EXIT_FAILURE;
  83. }
  84. catch (const std::exception &e)
  85. {
  86. std::cerr << e.what() << std::endl;
  87. return EXIT_FAILURE;
  88. }
  89. void configure_filters(rs2::decimation_filter &dec_filter, rs2::threshold_filter &thr_filter, rs2::spatial_filter &spat_filter, int dec_filter_magnitude, float min_dist, float max_dist, int magnitude, int smooth_alpha, int smooth_delta, int holes_fill)
  90. {
  91. dec_filter.set_option(RS2_OPTION_FILTER_MAGNITUDE, dec_filter_magnitude);
  92. thr_filter.set_option(RS2_OPTION_MIN_DISTANCE, min_dist);
  93. thr_filter.set_option(RS2_OPTION_MAX_DISTANCE, max_dist);
  94. spat_filter.set_option(RS2_OPTION_FILTER_MAGNITUDE, magnitude);
  95. spat_filter.set_option(RS2_OPTION_FILTER_SMOOTH_ALPHA, smooth_alpha);
  96. spat_filter.set_option(RS2_OPTION_FILTER_SMOOTH_DELTA, smooth_delta);
  97. spat_filter.set_option(RS2_OPTION_HOLES_FILL, holes_fill);
  98. }
  99. /* Apply filters.
  100. The implemented flow of the filters pipeline is in the following order:
  101. 1. apply decimation filter
  102. 2. apply threshold filter
  103. 3. transform the scene into disparity domain
  104. 4. apply spatial filter
  105. 5. apply temporal filter
  106. 6. revert the results back (if step Disparity filter was applied
  107. to depth domain (each post processing block is optional and can be applied independantly).
  108. */
  109. void apply_filters(rs2::decimation_filter &dec_filter, rs2::threshold_filter &thr_filter, rs2::spatial_filter &spat_filter, rs2::disparity_transform &depth_to_disparity, rs2::disparity_transform &disparity_to_depth, rs2::depth_frame &depth_frame)
  110. {
  111. depth_frame = dec_filter.process(depth_frame);
  112. depth_frame = thr_filter.process(depth_frame);
  113. depth_frame = depth_to_disparity.process(depth_frame);
  114. depth_frame = spat_filter.process(depth_frame);
  115. depth_frame = disparity_to_depth.process(depth_frame);
  116. }
  117. ColoredPoints scan(rs2::decimation_filter &dec_filter, rs2::threshold_filter &thr_filter, rs2::spatial_filter &spat_filter, rs2::disparity_transform &depth_to_disparity, rs2::disparity_transform &disparity_to_depth, rs2::pipeline &pipe)
  118. {
  119. rs2::pointcloud pointcloud;
  120. rs2::points points;
  121. // let the auto exposure settle
  122. for (auto i = 0; i < 30; ++i)
  123. pipe.wait_for_frames();
  124. rs2::frameset data = pipe.wait_for_frames();
  125. rs2::video_frame color = data.get_color_frame();
  126. if (!color)
  127. color = data.get_infrared_frame();
  128. rs2::depth_frame depth_frame = data.get_depth_frame();
  129. apply_filters(dec_filter, thr_filter, spat_filter, depth_to_disparity, disparity_to_depth, depth_frame);
  130. pointcloud.map_to(color);
  131. points = pointcloud.calculate(depth_frame);
  132. return ColoredPoints(points, color);
  133. }
  134. void scan_and_convert(rs2::decimation_filter &dec_filter, rs2::threshold_filter &thr_filter, rs2::spatial_filter &spat_filter, rs2::disparity_transform &depth_to_disparity, rs2::disparity_transform &disparity_to_depth, rs2::pipeline &pipe, std::vector<PCLHelper::PtrCloud> &pointclouds)
  135. {
  136. // does a scan, convertes it to pcl format and puts it into an array
  137. std::cout << "Scanning... ";
  138. ColoredPoints scanned_points = scan(dec_filter, thr_filter, spat_filter, depth_to_disparity, disparity_to_depth, pipe);
  139. std::cout << "\nConverting... ";
  140. PCLHelper::PtrCloud converted_points = PCLHelper::points_to_pcl(scanned_points.points, scanned_points.color);
  141. pointclouds.push_back(converted_points);
  142. }
  143. bool align_and_save_pointclouds(std::vector<PCLHelper::PtrCloud> &pointclouds)
  144. {
  145. for (int i = 0; i < pointclouds.size(); i++)
  146. {
  147. if (i == 0)
  148. {
  149. PCLHelper::save_to_ply("scans_fitted/", "output" + std::to_string(i) + ".ply", pointclouds[i]);
  150. continue;
  151. }
  152. if (PCLHelper::icp(pointclouds[0], pointclouds[i], 80) == 0)
  153. {
  154. PCLHelper::save_to_ply("scans_fitted/", "output" + std::to_string(i) + ".ply", pointclouds[i]);
  155. }
  156. else
  157. {
  158. std::cout << "ICP failed";
  159. return false;
  160. }
  161. }
  162. return true;
  163. }
  164. void save_original_pointclouds(std::vector<PCLHelper::PtrCloud> &pointclouds)
  165. {
  166. for (int i = 0; i < pointclouds.size(); i++)
  167. {
  168. PCLHelper::save_to_ply("scans_original/", "output" + std::to_string(i) + ".ply", pointclouds[i]);
  169. }
  170. }
  171. void wipe_old_scans()
  172. {
  173. std::filesystem::path dirPathFitted = "scans_fitted";
  174. std::filesystem::path dirPathOriginal = "scans_original";
  175. std::uintmax_t numRemovedFitted = std::filesystem::remove_all(dirPathFitted);
  176. std::uintmax_t numRemovedOriginal = std::filesystem::remove_all(dirPathOriginal);
  177. if (numRemovedFitted == 0 && numRemovedOriginal == 0)
  178. {
  179. std::cout << "No Scans to delete. " << std::filesystem::current_path() << std::endl;
  180. }
  181. else
  182. {
  183. std::cout << "All scans delted." << std::endl;
  184. }
  185. }
  186. int prompt_user()
  187. {
  188. int number;
  189. std::cout << "\n Welcome to the 3d-scanner, choose your option: ";
  190. std::cout << "\n (1) Scan ";
  191. std::cout << "\n (2) Align and save pointclouds ";
  192. std::cout << "\n (3) Wipe old scans ";
  193. std::cout << "\n (4) exit \n";
  194. std::cin >> number;
  195. return number;
  196. }