stereo_camera.hpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #ifndef REMOTEAR2_STEREO_CAMERA_HPP
  2. #define REMOTEAR2_STEREO_CAMERA_HPP
  3. #include "config.h"
  4. #include "mvs_camera.h"
  5. #include <opencv2/cudaimgproc.hpp>
  6. #include <atomic>
  7. #include <thread>
  8. struct stereo_camera {
  9. mvs_camera left_camera, right_camera;
  10. cv::cuda::GpuMat *left_raw_image = nullptr, *right_raw_image = nullptr;
  11. cv::cuda::GpuMat left_rgb_image, right_rgb_image;
  12. std::atomic_flag *left_save_raw_flag, *right_save_raw_flag;
  13. stereo_camera() {
  14. left_rgb_image = cv::cuda::GpuMat{image_height, image_width, CV_8UC3};
  15. right_rgb_image = cv::cuda::GpuMat{image_height, image_width, CV_8UC3};
  16. left_save_raw_flag = left_camera.get_save_raw_flag();
  17. right_save_raw_flag = right_camera.get_save_raw_flag();
  18. }
  19. ~stereo_camera() {
  20. close();
  21. }
  22. bool open() {
  23. if (!open_impl()) { // keep consistency
  24. close();
  25. return false;
  26. }
  27. return true;
  28. }
  29. void close() {
  30. stop_capture();
  31. left_camera.close();
  32. right_camera.close();
  33. }
  34. bool start_capture(float exposure_time_us, float analog_gain, int trigger_interval_ms) {
  35. if (!start_capture_impl(exposure_time_us, analog_gain)) {
  36. stop_capture();
  37. return false;
  38. }
  39. start_trigger_thread(trigger_interval_ms);
  40. return true;
  41. }
  42. bool set_capture_config(float exposure_time_us, float analog_gain) {
  43. auto config = mvs_camera::capture_config{};
  44. config.exposure_time = exposure_time_us;
  45. config.analog_gain = analog_gain;
  46. if (memcmp(&config, &last_config, sizeof(config)) == 0) return true;
  47. CALL_CHECK(left_camera.modify_config(config));
  48. CALL_CHECK(right_camera.modify_config(config));
  49. return true;
  50. }
  51. void stop_capture() {
  52. // stop trigger thread
  53. if (trigger_thread != nullptr) {
  54. // let thread exit by itself
  55. should_stop.test_and_set();
  56. trigger_thread->join();
  57. delete trigger_thread;
  58. // cleanup
  59. should_stop.clear();
  60. trigger_thread = nullptr;
  61. }
  62. left_camera.stop_capture();
  63. right_camera.stop_capture();
  64. }
  65. bool software_trigger() {
  66. return left_camera.software_trigger() &&
  67. right_camera.software_trigger();
  68. }
  69. void retrieve_raw_images() {
  70. assert(is_capturing());
  71. // clean old images
  72. delete left_raw_image;
  73. delete right_raw_image;
  74. left_raw_image = nullptr;
  75. right_raw_image = nullptr;
  76. // retrieve new images
  77. left_camera.retrieve_image(&left_raw_image);
  78. right_camera.retrieve_image(&right_raw_image);
  79. assert(left_raw_image != nullptr);
  80. assert(right_raw_image != nullptr);
  81. }
  82. bool is_opened() const {
  83. assert(left_camera.is_opened() == right_camera.is_opened());
  84. return left_camera.is_opened();
  85. }
  86. bool is_capturing() const {
  87. assert(left_camera.is_capturing() == right_camera.is_capturing());
  88. return left_camera.is_capturing();
  89. }
  90. void debayer_images() {
  91. cv::cuda::cvtColor(*left_raw_image, left_rgb_image, cv::COLOR_BayerRG2RGB);
  92. cv::cuda::cvtColor(*right_raw_image, right_rgb_image, cv::COLOR_BayerRG2RGB);
  93. }
  94. void set_raw_saver(raw_file_saver *saver) {
  95. left_camera.set_raw_saver(saver);
  96. right_camera.set_raw_saver(saver);
  97. }
  98. void request_save_raw() {
  99. left_save_raw_flag->test_and_set();
  100. right_save_raw_flag->test_and_set();
  101. }
  102. private:
  103. std::thread *trigger_thread = nullptr;
  104. std::atomic_flag should_stop;
  105. mvs_camera::capture_config last_config;
  106. bool open_impl() {
  107. CALL_CHECK(left_camera.open(left_camera_name));
  108. CALL_CHECK(right_camera.open(right_camera_name));
  109. return true;
  110. }
  111. bool start_capture_impl(float exposure_time, float analog_gain) {
  112. last_config.exposure_time = exposure_time;
  113. last_config.analog_gain = analog_gain;
  114. CALL_CHECK(left_camera.start_capture(last_config));
  115. CALL_CHECK(right_camera.start_capture(last_config));
  116. return true;
  117. }
  118. void start_trigger_thread(int fps) {
  119. assert(trigger_thread == nullptr);
  120. trigger_thread = new std::thread{[=, this]() {
  121. auto trigger_interval = std::chrono::microseconds{(int) 1e6 / fps};
  122. auto next_trigger_time = std::chrono::high_resolution_clock::now();
  123. while (true) {
  124. if (should_stop.test()) break;
  125. software_trigger();
  126. // resume at (almost) exact time // TODO: test performance
  127. next_trigger_time += trigger_interval;
  128. std::this_thread::sleep_until(next_trigger_time - default_spin_time);
  129. while (std::chrono::high_resolution_clock::now() < next_trigger_time)
  130. std::this_thread::yield();
  131. }
  132. }};
  133. }
  134. };
  135. #endif //REMOTEAR2_STEREO_CAMERA_HPP