mvs_camera.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #include "mvs_camera.h"
  2. #include "config.h"
  3. #ifdef _MSC_VER
  4. #pragma warning(disable: 4828)
  5. #endif
  6. #include <MvCameraControl.h>
  7. #include <spdlog/spdlog.h>
  8. #include <atomic>
  9. bool check_mvs_api_call(int api_ret, unsigned int line_number,
  10. const char *file_name, const char *api_call_str) {
  11. if (api_ret == MV_OK) [[likely]] return true;
  12. SPDLOG_ERROR("MVS api call {} failed at {}:{} with error 0x{:x}",
  13. api_call_str, file_name, line_number, api_ret);
  14. RET_ERROR;
  15. }
  16. #define MVS_API_CHECK(api_call) \
  17. if (!check_mvs_api_call( \
  18. api_call, __LINE__, __FILE__, #api_call)) [[unlikely]] \
  19. return false
  20. struct mvs_camera::impl {
  21. void *handle = nullptr;
  22. std::string_view cam_name;
  23. bool is_capturing = false;
  24. cv::cuda::GpuMat *inner_img = nullptr;
  25. std::atomic<cv::cuda::GpuMat *> next_img;
  26. static void on_error(unsigned int msg_type, void *user_data) {
  27. auto pimpl = (impl *) user_data;
  28. SPDLOG_ERROR("MVS camera {} exception 0x{:x}.", pimpl->cam_name, msg_type);
  29. if (msg_type == 0x8003) return; // stop capture
  30. assert(false);
  31. }
  32. static void on_image(unsigned char *data, MV_FRAME_OUT_INFO_EX *frame_info, void *user_data) {
  33. assert(frame_info->nFrameLen == raw_image_size);
  34. auto pimpl = (impl *) user_data;
  35. auto host_img = cv::Mat{image_height, image_width, CV_8UC1, data};
  36. // upload image to gpu
  37. if (pimpl->inner_img == nullptr) [[unlikely]] {
  38. pimpl->inner_img = new cv::cuda::GpuMat{};
  39. }
  40. pimpl->inner_img->upload(host_img);
  41. // commit new image
  42. pimpl->inner_img = pimpl->next_img.exchange(pimpl->inner_img);
  43. pimpl->next_img.notify_all();
  44. }
  45. };
  46. mvs_camera::mvs_camera()
  47. : pimpl(std::make_unique<impl>()) {}
  48. mvs_camera::~mvs_camera() {
  49. close();
  50. }
  51. bool mvs_camera::open(std::string_view camera_name) {
  52. MV_CC_DEVICE_INFO_LIST dev_info_list;
  53. MVS_API_CHECK(MV_CC_EnumDevices(MV_USB_DEVICE, &dev_info_list));
  54. MV_CC_DEVICE_INFO *dev_info = nullptr;
  55. for (int i = 0; i < dev_info_list.nDeviceNum; ++i) {
  56. auto tmp_dev_info = dev_info_list.pDeviceInfo[i];
  57. auto tmp_dev_name = (char *) tmp_dev_info->SpecialInfo.stUsb3VInfo.chUserDefinedName;
  58. if (camera_name == tmp_dev_name) {
  59. dev_info = tmp_dev_info;
  60. }
  61. }
  62. if (dev_info == nullptr) {
  63. SPDLOG_ERROR("No camera named {}.", camera_name);
  64. RET_ERROR;
  65. }
  66. pimpl->cam_name = camera_name;
  67. // MVS_API_CHECK(MV_CC_IsDeviceAccessible(dev_info, MV_ACCESS_Control));
  68. MVS_API_CHECK(MV_CC_CreateHandle(&pimpl->handle, dev_info));
  69. MVS_API_CHECK(MV_CC_OpenDevice(pimpl->handle, MV_ACCESS_Control));
  70. // close and open again to fix some bug
  71. MVS_API_CHECK(MV_CC_CloseDevice(pimpl->handle));
  72. MVS_API_CHECK(MV_CC_OpenDevice(pimpl->handle, MV_ACCESS_Control));
  73. // register callbacks
  74. MVS_API_CHECK(MV_CC_RegisterExceptionCallBack(pimpl->handle, impl::on_error, pimpl.get()));
  75. MVS_API_CHECK(MV_CC_RegisterImageCallBackEx(pimpl->handle, impl::on_image, pimpl.get()));
  76. SPDLOG_INFO("Camera {} opened successfully.", pimpl->cam_name);
  77. return true;
  78. }
  79. void mvs_camera::close() {
  80. if (pimpl->handle == nullptr) return;
  81. stop_capture();
  82. MV_CC_CloseDevice(pimpl->handle);
  83. MV_CC_DestroyHandle(pimpl->handle);
  84. pimpl->handle = nullptr;
  85. SPDLOG_INFO("Camera {} closed.", pimpl->cam_name);
  86. }
  87. bool mvs_camera::start_capture(const capture_config *config) {
  88. assert(pimpl->handle != nullptr);
  89. // config camera
  90. MVS_API_CHECK(MV_CC_SetEnumValue(pimpl->handle, "PixelFormat", PixelType_Gvsp_BayerRG8));
  91. MVS_API_CHECK(MV_CC_SetEnumValue(pimpl->handle, "AcquisitionMode",
  92. MV_CAM_ACQUISITION_MODE::MV_ACQ_MODE_CONTINUOUS));
  93. MVS_API_CHECK(MV_CC_SetEnumValue(pimpl->handle, "TriggerMode", MV_TRIGGER_MODE_ON));
  94. MVS_API_CHECK(MV_CC_SetEnumValue(pimpl->handle, "TriggerSource",
  95. MV_CAM_TRIGGER_SOURCE::MV_TRIGGER_SOURCE_SOFTWARE));
  96. MVS_API_CHECK(MV_CC_SetFloatValue(pimpl->handle, "ExposureTime", config->exposure_time));
  97. MVS_API_CHECK(MV_CC_SetFloatValue(pimpl->handle, "Gain", config->analog_gain));
  98. MVS_API_CHECK(MV_CC_StartGrabbing(pimpl->handle));
  99. pimpl->is_capturing = true;
  100. SPDLOG_INFO("Camera {} is capturing.", pimpl->cam_name);
  101. return true;
  102. }
  103. void mvs_camera::stop_capture() {
  104. if (pimpl->handle == nullptr || !pimpl->is_capturing) return;
  105. MV_CC_StopGrabbing(pimpl->handle);
  106. pimpl->is_capturing = false;
  107. SPDLOG_INFO("Camera {} stopped capturing.", pimpl->cam_name);
  108. }
  109. bool mvs_camera::software_trigger() {
  110. assert(pimpl->handle != nullptr);
  111. MVS_API_CHECK(MV_CC_TriggerSoftwareExecute(pimpl->handle));
  112. return true;
  113. }
  114. void mvs_camera::retrieve_image(cv::cuda::GpuMat **image_ptr) {
  115. pimpl->next_img.wait(nullptr);
  116. *image_ptr = pimpl->next_img.exchange(*image_ptr);
  117. }
  118. bool mvs_camera::is_opened() const {
  119. return pimpl->handle != nullptr;
  120. }
  121. bool mvs_camera::is_capturing() const {
  122. return pimpl->is_capturing;
  123. }