统一数据契约

author: 周均扬

date: 2026.06.06


统一数据契约,重点是:零拷贝 + 统一入口 + 可扩展 + 跨平台 + 多线程安全。

1. 设计目标重构


2. 核心方案:引入 UnifiedFrame(统一中间层)

新增中间层: UnifiedFrame = 跨 SDK 的唯一数据契约

UnifiedFrame 定义:

#pragma once

#include <memory>
#include <string>
#include <unordered_map>
#include <any>
#include <opencv2/opencv.hpp>

enum class UnifiedPixelFormat
{
    BGR,
    RGB,
    GRAY,
    NV12
};

class UnifiedFrame
{
public:
    using Ptr = std::shared_ptr<UnifiedFrame>;

    // =====================
    // 图像数据(核心:零拷贝)
    // =====================
    cv::Mat image;

#ifdef ENABLE_CUDA
    cv::cuda::GpuMat gpu_image;
#endif

    // =====================
    // 标准化元数据
    // =====================
    uint64_t frame_id = 0;
    uint64_t timestamp_ns = 0;

    int camera_id = -1;

    UnifiedPixelFormat format = UnifiedPixelFormat::BGR;

    bool valid = true;

    // =====================
    // 扩展字段
    // =====================
    std::unordered_map<std::string, std::any> meta;

public:
    UnifiedFrame() = default;

    inline void reset()
    {
        image.release();
#ifdef ENABLE_CUDA
        gpu_image.release();
#endif
        meta.clear();
        valid = false;
    }

    inline void setTimestamp()
    {
        // 可替换为 chrono 高精度实现
        timestamp_ns = static_cast<uint64_t>(
            std::chrono::high_resolution_clock::now().time_since_epoch().count()
        );
    }
};

3. CameraSDK → UnifiedFrame(零拷贝关键点)

关键原则:CameraSDK 只负责“填数据”,不负责“解释数据”。

Adapter 设计:

class CameraFrameAdapter
{
public:
    static UnifiedFrame::Ptr convert(const FrameBuffer& src)
    {
        auto dst = std::make_shared<UnifiedFrame>();

        // ⚠️ 核心:不做 clone
        dst->image = src.image;

        dst->frame_id = src.frame_id;
        dst->camera_id = src.camera_id;
        dst->timestamp_ns = src.timestamp;

        dst->valid = src.valid;

        dst->meta["sequence"] = src.sequence;
        dst->meta["gpu"] = src.gpu;

#ifdef ENABLE_CUDA
        if (src.gpu)
        {
            dst->gpu_image = src.gpu_image;
        }
#endif

        return dst;
    }
};

4. AlgorithmSDK → UnifiedFrame(算法输入标准化)

class VisionFrameAdapter
{
public:
    static UnifiedFrame::Ptr convert(const VisionFrame& src)
    {
        auto dst = std::make_shared<UnifiedFrame>();

        dst->image = src.image;

        dst->camera_id = std::stoi(src.camera_id); // 建议后续改 string hash
        dst->timestamp_ns = static_cast<uint64_t>(src.timestamp * 1e9);

        dst->format = static_cast<UnifiedPixelFormat>(src.format);

        for (auto& [k, v] : src.metadata)
        {
            dst->meta[k] = v;
        }

        return dst;
    }

    static VisionFrame toVisionFrame(const UnifiedFrame& src)
    {
        VisionFrame vf;
        vf.image = src.image;

        vf.camera_id = std::to_string(src.camera_id);
        vf.timestamp = src.timestamp_ns / 1e9;

        vf.format = PixelFormat::BGR;

        vf.metadata = src.meta;

        return vf;
    }
};

5. 统一 Pipeline 架构

5.1 标准工业链路

CameraSDK -> FrameBuffer (zero-copy) -> UnifiedFrame (adapter layer) -> AlgorithmSDK algorithms -> VisionFrame (optional interop)

5.2 多线程架构

Lock-free / SPSC Queue(核心)

template<typename T>
class FrameQueue
{
public:
    void push(T frame);
    T pop();
};

5.3 Pipeline:

Camera Thread -> FrameBuffer Pool -> Adapter Thread -> UnifiedFrame Queue -> Inference Thread -> Postprocess Thread

6. Zero-Copy 关键优化点

❌ 必须避免

cv::Mat copy = src.image.clone();

✔ 正确做法

dst->image = src.image;  // ref-count sharing

OpenCV cv::Mat 本身就是:

✔ reference-counted shared buffer ✔ shallow copy 默认 zero-copy


CUDA路径(高级优化)

dst->gpu_image = src.gpu_image; // 同样是浅拷贝

7. CameraSDK / AlgorithmSDK 解耦策略

❌ 不要做:

✔ 正确方式:

CameraSDK -> (Adapter Layer) -> UnifiedFrame -> (Adapter Layer) -> AlgorithmSDK

8. 统一设计带来的收益

✔ 架构层

✔ 性能层

✔ 工业扩展性

✔ 多线程能力