orb_camera.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #include "orb_camera_impl.h"
  2. #include "image_utility.hpp"
  3. #include "object_manager.h"
  4. #include "utility.hpp"
  5. #include <boost/asio/post.hpp>
  6. #include <opencv2/imgcodecs.hpp>
  7. #include <opencv2/imgproc.hpp>
  8. using boost::asio::post;
  9. namespace orb_camera_impl {
  10. ob::Context ob_ctx;
  11. const char *get_fmt_name(OBFormat fmt) {
  12. switch (fmt) {
  13. // @formatter:off
  14. case OB_FORMAT_YUYV: return "yuyv";
  15. case OB_FORMAT_MJPG: return "mjpg";
  16. case OB_FORMAT_RGB: return "rgb";
  17. case OB_FORMAT_Y16: return "y16";
  18. case OB_FORMAT_RLE: return "rle";
  19. case OB_FORMAT_Y14: return "y14";
  20. default: return "unknown";
  21. // @formatter:on
  22. }
  23. RET_ERROR_P;
  24. }
  25. // convert uncompressed video frame to image_xxx
  26. template<typename T>
  27. auto video_uc_frame_to_image(const video_frame_type &frame) {
  28. auto info = image_info_type<T>();
  29. info.ptr = std::shared_ptr<T>( // extend frame's lifetime
  30. (T *) frame->data(), [pf = frame](void *) {});
  31. info.loc = MEM_HOST;
  32. info.size = cv::Size(frame->width(), frame->height());
  33. info.pitch = frame->width() * sizeof(T);
  34. assert(frame->dataSize() == info.pitch * info.size.height);
  35. return create_image(info);
  36. }
  37. auto mjpeg_frame_to_image(const video_frame_type &frame) { // TODO: accelerate with CUDA
  38. assert(frame->format() == OB_FORMAT_MJPG);
  39. auto img_data = cv::_InputArray((uchar *) frame->data(), frame->dataSize());
  40. auto img_bgr = cv::imdecode(img_data, cv::IMREAD_UNCHANGED);
  41. auto img_rgb_info = create_image_info<uchar3>(img_bgr.size(), MEM_HOST);
  42. cv::cvtColor(img_bgr, img_rgb_info.as_mat(), cv::COLOR_BGR2RGB);
  43. return create_image(img_rgb_info);
  44. }
  45. image_f32c1 depth_y16_to_mm(const image_u16c1 &y16, float scale) { // TODO: accelerate with CUDA
  46. auto y16_info = y16->as_host_info();
  47. auto f32_info = create_image_info<float1>(y16_info.size, MEM_HOST);
  48. y16->as_host().convertTo(f32_info.as_mat(), CV_32FC1, scale);
  49. return create_image(f32_info);
  50. }
  51. }
  52. std::shared_ptr<ob::Device> orb_camera::impl::get_device(const char *sn) {
  53. auto dev_list = ob_ctx.queryDeviceList();
  54. return dev_list->getDeviceBySN(sn);
  55. }
  56. orb_camera::impl *orb_camera::impl::create(orb_camera::create_config conf) {
  57. auto dev = get_device(conf.sn_str);
  58. auto ret = new impl();
  59. ret->pipe = std::make_shared<ob::Pipeline>(dev);
  60. ret->ctx = conf.ctx;
  61. ret->stream = conf.stream;
  62. return ret;
  63. }
  64. orb_camera::impl::~impl() {
  65. if (is_capturing) {
  66. stop();
  67. }
  68. }
  69. void orb_camera::impl::create_video_info_list(
  70. const pf_list_type &pf_list, v_info_list_type *v_info) {
  71. v_info->reserve(pf_list->count());
  72. for (uint32_t k = 0; k < pf_list->count(); ++k) {
  73. auto pf = pf_list->getProfile(k)->as<ob::VideoStreamProfile>();
  74. assert(pf != nullptr);
  75. auto info = video_info{};
  76. info.index = k;
  77. info.fmt_name = get_fmt_name(pf->format());
  78. info.fps = pf->fps();
  79. info.width = pf->width();
  80. info.height = pf->height();
  81. v_info->push_back(info);
  82. }
  83. }
  84. orb_camera::impl::v_info_list_type *
  85. orb_camera::impl::query_video_info(OBSensorType s_type) {
  86. switch (s_type) {
  87. case OB_SENSOR_COLOR: {
  88. if (c_pf_list == nullptr) [[unlikely]] {
  89. c_pf_list = pipe->getStreamProfileList(s_type);
  90. c_info = std::make_unique<v_info_list_type>();
  91. create_video_info_list(c_pf_list, c_info.get());
  92. }
  93. return c_info.get();
  94. }
  95. case OB_SENSOR_DEPTH: {
  96. if (d_pf_list == nullptr) [[unlikely]] {
  97. d_pf_list = pipe->getStreamProfileList(s_type);
  98. d_info = std::make_unique<v_info_list_type>();
  99. create_video_info_list(d_pf_list, d_info.get());
  100. }
  101. return d_info.get();
  102. }
  103. }
  104. RET_ERROR_P;
  105. }
  106. bool orb_camera::impl::start(start_config conf) {
  107. assert(!is_capturing);
  108. auto ob_conf = std::make_shared<ob::Config>();
  109. if (conf.color.enable) {
  110. assert(c_pf_list != nullptr);
  111. ob_conf->enableStream(c_pf_list->getProfile(conf.color.config_index));
  112. c_name = conf.color.name;
  113. }
  114. if (conf.depth.enable) {
  115. assert(d_pf_list != nullptr);
  116. ob_conf->enableStream(d_pf_list->getProfile(conf.depth.config_index));
  117. d_name = conf.depth.name;
  118. }
  119. if (conf.color.enable && conf.depth.enable) {
  120. ob_conf->setAlignMode(ALIGN_D2C_HW_MODE);
  121. }
  122. pipe->start(ob_conf, [this](auto frames) {
  123. frames_callback(std::move(frames));
  124. });
  125. is_capturing = true;
  126. return true;
  127. }
  128. void orb_camera::impl::frames_callback(const frames_type &frames) {
  129. auto c_img = image_u8c3();
  130. if (auto c_frame = frames->colorFrame(); c_frame != nullptr) {
  131. assert(c_name != invalid_obj_name);
  132. auto fmt = c_frame->format();
  133. if (fmt == OB_FORMAT_RGB) {
  134. c_img = video_uc_frame_to_image<uchar3>(c_frame);
  135. } else {
  136. assert(fmt == OB_FORMAT_MJPG);
  137. c_img = mjpeg_frame_to_image(c_frame);
  138. }
  139. }
  140. auto d_img = image_f32c1();
  141. if (auto d_frame = frames->depthFrame(); d_frame != nullptr) {
  142. assert(d_name != invalid_obj_name);
  143. assert(d_frame->format() == OB_FORMAT_Y16);
  144. auto y16_img = video_uc_frame_to_image<ushort1>(d_frame);
  145. d_img = depth_y16_to_mm(y16_img, d_frame->getValueScale());
  146. }
  147. post(*ctx, [=, _c_name = c_name, _d_name = d_name] {
  148. if (c_img != nullptr) { OBJ_SAVE(_c_name, c_img); }
  149. if (d_img != nullptr) { OBJ_SAVE(_d_name, d_img); }
  150. });
  151. }
  152. void orb_camera::impl::stop() {
  153. assert(is_capturing);
  154. pipe->stop();
  155. is_capturing = false;
  156. }
  157. orb_camera *orb_camera::create(orb_camera::create_config conf) {
  158. auto pimpl = std::unique_ptr<impl>(impl::create(conf));
  159. if (pimpl == nullptr) return nullptr;
  160. auto ret = new orb_camera();
  161. ret->pimpl = std::move(pimpl);
  162. return ret;
  163. }
  164. orb_camera::~orb_camera() = default;
  165. std::vector<orb_camera::device_info>
  166. orb_camera::query_device_info() {
  167. auto dev_list = ob_ctx.queryDeviceList();
  168. std::vector<device_info> ret;
  169. ret.reserve(dev_list->deviceCount());
  170. for (auto k = 0; k < dev_list->deviceCount(); ++k) {
  171. ret.push_back({.sn_str = dev_list->serialNumber(k)});
  172. }
  173. return ret;
  174. }
  175. std::vector<orb_camera::video_info> *
  176. orb_camera::query_video_info(video_type type) {
  177. switch (type) {
  178. case V_COLOR:
  179. return pimpl->query_video_info(OB_SENSOR_COLOR);
  180. case V_DEPTH:
  181. return pimpl->query_video_info(OB_SENSOR_DEPTH);
  182. }
  183. RET_ERROR_P;
  184. }
  185. bool orb_camera::start(orb_camera::start_config conf) {
  186. return pimpl->start(conf);
  187. }
  188. void orb_camera::stop() {
  189. pimpl->stop();
  190. }
  191. bool orb_camera::is_capturing() const {
  192. return pimpl->is_capturing;
  193. }
  194. orb_camera::video_info::operator std::string() {
  195. return fmt::format("{}x{} @ {}fps ({})", width, height, fps, fmt_name);
  196. }