| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- #include "mvs_camera.h"
- #include "image_ringbuffer.hpp"
- #ifdef _MSC_VER
- #pragma warning(disable: 4828)
- #endif
- #include <MvCameraControl.h>
- #include <spdlog/spdlog.h>
- #include <opencv2/core/mat.hpp>
- #include <boost/predef.h>
- #ifdef BOOST_OS_WINDOWS_AVAILABLE
- #include <format>
- #define fmt std
- #else
- #include <fmt/chrono.h>
- #include <fmt/format.h>
- #endif
- bool check_mvs_api_call(int api_ret, unsigned int line_number,
- const char *file_name, const char *api_call_str) {
- if (api_ret == MV_OK) [[likely]] return true;
- SPDLOG_ERROR("MVS api call {} failed at {}:{} with error 0x{:x}",
- api_call_str, file_name, line_number, api_ret);
- RET_ERROR;
- }
- #define MVS_API_CHECK(api_call) \
- if (!check_mvs_api_call( \
- api_call, __LINE__, __FILE__, #api_call)) [[unlikely]] \
- return false
- struct mvs_camera::impl {
- static constexpr auto image_width = 1224;
- static constexpr auto image_height = 1024;
- static constexpr auto image_size = image_width * sizeof(uint8_t) * image_height;
- void *handle = nullptr;
- const char *cam_name = nullptr;
- image_ringbuffer *ring_buf = nullptr;
- bool is_capturing = false;
- explicit impl(const char *_cam_name)
- : cam_name(_cam_name) {
- CALL_ASSERT(open());
- }
- ~impl() {
- CALL_ASSERT(close());
- }
- bool open() {
- MV_CC_DEVICE_INFO_LIST dev_info_list;
- MVS_API_CHECK(MV_CC_EnumDevices(MV_USB_DEVICE, &dev_info_list));
- MV_CC_DEVICE_INFO *dev_info = nullptr;
- for (int i = 0; i < dev_info_list.nDeviceNum; ++i) {
- auto tmp_dev_info = dev_info_list.pDeviceInfo[i];
- auto tmp_dev_name = (char *) tmp_dev_info->SpecialInfo.stUsb3VInfo.chUserDefinedName;
- if (strcmp(cam_name, tmp_dev_name) == 0) {
- dev_info = tmp_dev_info;
- }
- }
- if (dev_info == nullptr) {
- SPDLOG_ERROR("No camera named {}.", cam_name);
- RET_ERROR;
- }
- // MVS_API_CHECK(MV_CC_IsDeviceAccessible(dev_info, MV_ACCESS_Control));
- MVS_API_CHECK(MV_CC_CreateHandle(&handle, dev_info));
- MVS_API_CHECK(MV_CC_OpenDevice(handle, MV_ACCESS_Control));
- // close and open again to fix some bug
- MVS_API_CHECK(MV_CC_CloseDevice(handle));
- MVS_API_CHECK(MV_CC_OpenDevice(handle, MV_ACCESS_Control));
- // register callbacks
- MVS_API_CHECK(MV_CC_RegisterExceptionCallBack(handle, impl::on_error, this));
- MVS_API_CHECK(MV_CC_RegisterImageCallBackEx(handle, impl::on_image, this));
- SPDLOG_INFO("Camera {} opened successfully.", cam_name);
- return true;
- }
- bool start() {
- // make sure ring buffer is assigned properly
- assert(ring_buf != nullptr);
- // config camera
- assert(handle != nullptr);
- MVS_API_CHECK(MV_CC_SetEnumValue(handle, "PixelFormat", PixelType_Gvsp_BayerRG8));
- MVS_API_CHECK(MV_CC_SetEnumValue(handle, "BinningHorizontal", 2));
- MVS_API_CHECK(MV_CC_SetEnumValue(handle, "BinningVertical", 2));
- MVS_API_CHECK(MV_CC_SetEnumValue(handle, "AcquisitionMode",
- MV_CAM_ACQUISITION_MODE::MV_ACQ_MODE_CONTINUOUS));
- MVS_API_CHECK(MV_CC_SetEnumValue(handle, "TriggerMode", MV_TRIGGER_MODE_ON));
- MVS_API_CHECK(MV_CC_SetEnumValue(handle, "TriggerSource",
- MV_CAM_TRIGGER_SOURCE::MV_TRIGGER_SOURCE_SOFTWARE));
- // start capture
- MVS_API_CHECK(MV_CC_StartGrabbing(handle));
- is_capturing = true;
- SPDLOG_INFO("Camera {} is capturing.", cam_name);
- return true;
- }
- bool trigger() {
- assert(handle != nullptr);
- MVS_API_CHECK(MV_CC_TriggerSoftwareExecute(handle));
- return true;
- }
- bool stop() {
- assert(handle != nullptr);
- if (!is_capturing) return true;
- MVS_API_CHECK(MV_CC_StopGrabbing(handle));
- is_capturing = false;
- SPDLOG_INFO("Camera {} stopped capturing.", cam_name);
- return true;
- }
- bool close() {
- assert(handle != nullptr);
- stop();
- MVS_API_CHECK(MV_CC_CloseDevice(handle));
- MVS_API_CHECK(MV_CC_DestroyHandle(handle));
- SPDLOG_INFO("Camera {} closed.", cam_name);
- return true;
- }
- static void on_error(unsigned int msg_type, void *user_data) {
- auto pimpl = (impl *) user_data;
- SPDLOG_ERROR("MVS camera {} exception 0x{:x}.", pimpl->cam_name, msg_type);
- if (msg_type == 0x8003) return; // stop capture
- assert(false);
- }
- static void on_image(unsigned char *data, MV_FRAME_OUT_INFO_EX *frame_info, void *user_data) {
- ((impl *) user_data)->on_image_impl(data, frame_info);
- }
- void on_image_impl(unsigned char *data, MV_FRAME_OUT_INFO_EX *frame_info) {
- assert(frame_info->nFrameLen == image_size);
- auto host_img = cv::Mat{image_height, image_width, CV_8UC1, data};
- ring_buf->push_image(host_img);
- }
- };
- mvs_camera::mvs_camera(const char *camera_name)
- : pimpl(std::make_unique<impl>(camera_name)) {
- }
- mvs_camera::~mvs_camera() = default;
- cv::Size mvs_camera::get_output_size() {
- return {impl::image_width, impl::image_height};
- }
- void mvs_camera::set_ring_buffer(image_ringbuffer *ring_buf) {
- pimpl->ring_buf = ring_buf;
- }
- bool mvs_camera::start() {
- return pimpl->start();
- }
- bool mvs_camera::trigger() {
- return pimpl->trigger();
- }
- void mvs_camera::stop() {
- pimpl->stop();
- }
- bool mvs_camera::set_capture_config(const capture_config &config) {
- MVS_API_CHECK(MV_CC_SetFloatValue(pimpl->handle, "ExposureTime", config.exposure_time_ms * 1000)); // ms -> us
- MVS_API_CHECK(MV_CC_SetFloatValue(pimpl->handle, "Gain", config.analog_gain_db));
- return true;
- }
- bool mvs_camera::is_capturing() const {
- return pimpl->is_capturing;
- }
|