问题描述
当我将这个库 https://github.com/stereolabs/zed-open-capture 作为第三方库引用时,我想定义一个类来调用相机,截取部分代码如下:
#pragma once
#include "dataflow/utils/camera_interface.h"
#include "videocapture.hpp"
#include <memory>
#include <opencv2/opencv.hpp>
namespace dataflow {
/**
* @brief ZED 相机类,实现 CameraInterface 接口
*/
class ZedCamera : public CameraInterface {
public:
/**
* @brief 构造函数
* @param serial_number ZED 相机的序列号,如果为空则使用第一个可用的相机
* @param resolution 分辨率
* @param fps 帧率
* @param dst_width 目标宽度
* @param dst_height 目标高度
*/
ZedCamera(const std::string& serial_number = "",
sl_oc::video::RESOLUTION resolution = sl_oc::video::RESOLUTION::HD720,
int fps = 30,
int dst_width = 0,
int dst_height = 0);编译时会出现如下的错误:
/workspace/nova_dataflow/dataflow/utils/zed_camera.h:24:22: error: 'sl_oc::video' has not been declared
24 | sl_oc::video::RESOLUTION resolution = sl_oc::video::RESOLUTION::HD720,
| ^~~~~
/workspace/nova_dataflow/dataflow/utils/zed_camera.h:54:28: error: 'video' is not a member of 'sl_oc'
54 | std::unique_ptr<sl_oc::video::VideoCapture> cap_;
| ^~~~~
/workspace/nova_dataflow/dataflow/utils/zed_camera.h:54:47: error: template argument 1 is invalid
54 | std::unique_ptr<sl_oc::video::VideoCapture> cap_;初步分析
可以肯定的是,我确实正确 include 了 videocapture.hpp 文件(部分代码如下):
#ifndef VIDEOCAPTURE_HPP
#define VIDEOCAPTURE_HPP
#include "defines.hpp"
#include <thread>
#include <mutex>
#include <fstream> // std::ofstream
#include <iomanip>
#define LOG_SEP ","
#ifdef VIDEO_MOD_AVAILABLE
#include "videocapture_def.hpp"
namespace sl_oc {
#ifdef SENSORS_MOD_AVAILABLE
namespace sensors {
class SensorCapture;
}
#endif
namespace video {
/*!
* \brief The Frame struct containing the acquired video frames
*/
struct SL_OC_EXPORT Frame
{
uint64_t frame_id = 0; //!< Increasing index of frames
uint64_t timestamp = 0; //!< Timestamp in nanoseconds
uint8_t* data = nullptr; //!< Frame data in YUV 4:2:2 format
uint16_t width = 0; //!< Frame width
uint16_t height = 0; //!< Frame height
uint8_t channels = 0; //!< Number of channels per pixel
};唯一值得怀疑的是 VIDEO_MOD_AVAILABLE 这个定义,但是编译随便找一个相关的文件 flags.make 中可以看到:
# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.16
# compile CXX with /usr/bin/aarch64-linux-gnu-g++
CXX_FLAGS = -no-pie -fopenmp -O2 -s -flto -fPIE -O3 -g -fno-omit-frame-pointer -Wall -Wextra -Wpedantic -Werror=return-type -fPIC -mtune=cortex-a72 -mcpu=cortex-a72 -std=gnu++2a
CXX_DEFINES = -DEMBEDDED_ARM -DVIDEO_MOD_AVAILABLE
CXX_INCLUDES = -I/workspace/nova_dataflow/third-party/zed-open-capture/include -I/workspace/nova_dataflow/third-party/zed-open-capture/examples/include -isystem /rootfs/usr/include/opencv4 明显是有 -DVIDEO_MOD_AVAILABLE 的,那问题到底出现在哪里呢?
原因
为了描述方便,将被依赖的库称为 sub,将依赖它的项目成为 top。
当您编译 top 库时,编译器可能没有看到 VIDEO_MOD_AVAILABLE 宏的定义,因此ideocapture.hpp 文件中的条件编译指令 #ifdef VIDEO_MOD_AVAILABLE 没有被执行,导致 sl_oc::video 命名空间和相关的类型没有被定义。
也就是 sub 库中添加的宏定义
add_definitions(-DVIDEO_MOD_AVAILABLE)并不会传递到 top 中。
自然解决办法就有两个:
解决办法
方案一:top增加宏定义
top 项目的 CMakeLists.txt 中
add_definitions(-DVIDEO_MOD_AVAILABLE)方案二:top 的文件处理这个宏定义
#include "dataflow/utils/zed_camera.h"
#include <stdexcept>
namespace dataflow {
#ifdef VIDEO_MOD_AVAILABLE
ZedCamera::ZedCamera(const std::string& serial_number,
int resolution,
int fps,
int dst_width,
int dst_height)
: dst_width_(dst_width), dst_height_(dst_height) {
// 获取相机参数
sl_oc::video::VideoParams params;
params.res = resolution;
params.fps = static_cast<sl_oc::video::FPS>(fps);
// 初始化视频捕获
cap_ = std::make_unique<sl_oc::video::VideoCapture>(params);
if (!cap_->initializeVideo()) {
throw std::runtime_error("Failed to initialize ZED camera");
}
// 获取图像尺寸
cap_->getFrameSize(width_, height_);
// 如果目标尺寸为0,则使用原始尺寸
if (dst_width_ == 0) {
dst_width_ = width_;
}
if (dst_height_ == 0) {
dst_height_ = height_;
}
}
cv::Mat ZedCamera::GetImage() const {
const sl_oc::video::Frame frame = cap_->getLastFrame();
if (frame.data == nullptr) {
return cv::Mat();
}
// 将 YUV 格式转换为 BGR 格式
cv::Mat yuv(height_, width_, CV_8UC2, frame.data);
cv::Mat bgr;
cv::cvtColor(yuv, bgr, cv::COLOR_YUV2BGR_YUYV);
return bgr;
}
std::vector<cv::Mat> ZedCamera::GetImages() const {
std::vector<cv::Mat> images;
images.push_back(GetImage());
return images;
}
cv::Mat ZedCamera::GetResizedImage() const {
cv::Mat image = GetImage();
if (image.empty()) {
return cv::Mat();
}
cv::Mat resized;
cv::resize(image, resized, cv::Size(dst_width_, dst_height_));
return resized;
}
std::vector<cv::Mat> ZedCamera::GetResizedImages() const {
std::vector<cv::Mat> images;
images.push_back(GetResizedImage());
return images;
}
#else // VIDEO_MOD_AVAILABLE
ZedCamera::ZedCamera(const std::string& serial_number,
int resolution,
int fps,
int dst_width,
int dst_height) {
throw std::runtime_error("ZED 相机模块未启用");
}
cv::Mat ZedCamera::GetImage() const {
throw std::runtime_error("ZED 相机模块未启用");
}
std::vector<cv::Mat> ZedCamera::GetImages() const {
throw std::runtime_error("ZED 相机模块未启用");
}
cv::Mat ZedCamera::GetResizedImage() const {
throw std::runtime_error("ZED 相机模块未启用");
}
std::vector<cv::Mat> ZedCamera::GetResizedImages() const {
throw std::runtime_error("ZED 相机模块未启用");
}
#endif // VIDEO_MOD_AVAILABLE
} // namespace dataflow