DeepStream-3D 自定义应用和库教程#

ds3d 框架、接口和自定义库专为 DeepStream-3D 处理而设计。ds3d 与 Gstreamer/Glib 框架无关。这些接口能够进行不同类型的数据融合。开发人员可以为 dataloaderdatafilterdatarender 实现不同类型的自定义库。该接口具有 ABI 兼容层和现代 C++ 接口。开发人员只需专注于现代 C++ 接口进行应用程序或自定义库开发。

DS3D dataloaderGstAppSrc 加载,使其可用于深度相机(如立体相机和飞行时间相机)来捕获图像/深度数据或从文件系统加载数据。此外,它还可用于从传感器或激光雷达数据文件捕获激光雷达数据。datafilternvds3dfilter Gst-plugin 加载。它可用于 2D 深度数据处理、从深度提取 3D 点云数据、其他 2D 深度或 3D 点数据过滤器以及激光雷达或 3D 数据推理。datarenderGstAppSink 加载。它可用于 2D 深度渲染以及 3D 点云和激光雷达数据渲染。它也可用于文件转储。

DS3D 应用示例#

  • DeepStream-3D 多模态激光雷达和相机传感器融合应用 示例应用程序展示了使用 DS3D 框架的激光雷达和相机数据的多模态传感器融合管线。示例中包含 2 个多模态传感器融合管线示例。示例应用位于 /opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-3d-lidar-sensor-fusion

    • 请参阅 DeepStream 3D 多模态激光雷达和相机传感器融合应用 以查看 deepstream-3d-lidar-sensor-fusion 的更多详细信息

    • DS3D BEVFusion 管线通过 deepstream-3d-lidar-sensor-fusion 显示了 6 个相机加 1 个激光雷达数据融合推理和渲染管线的概述。

      DeepStream 3D Lidar BEVFusion pipeline overview
    • DS3D V2XFusion 管线通过 deepstream-3d-lidar-sensor-fusion 显示了 1 个相机加 1 个激光雷达,批量为 4 的数据输入融合推理和渲染管线的概述。

      DeepStream 3D Lidar V2XFusion pipeline overview
  • deepstream-lidar-inference 具有加载这些自定义库并将这些组件以简单方式连接在一起的示例代码。除此之外,DS3D 还具有用于 Gstreamer 组件的简单 C++ 安全指针。接口位于 /opt/nvidia/deepstream/deepstream/sources/libs/ds3d/gst/ 中的头文件中。

下图显示了 deepstream-lidar-inference 中激光雷达 3D 数据推理和渲染管线的概述。

DeepStream Lidar point cloud inference and rendering overview

请在 DeepStream 3D 激光雷达推理应用 中查看更多详细信息。

下图显示了 deepstream-3d-depth-camera 中深度到 3D 点处理管线的概述。

DeepStream Depth Camera for 3D point cloud processing overview

请在 DeepStream 3D 深度相机应用 中查看更多详细信息。

所有组件均以 YAML 格式配置。它们由 Gst-plugins 加载。有 3 个主要组件,它们都可以加载到 deepstream 管线中。

DS3D 数据格式 ds3d/datamap#

ds3d/datamap 识别 DS3D 框架中使用的数据格式。在 GStreamer 插件之间流动的数据缓冲区将属于此数据类型。ds3d/datamap 是键值对,其中键是字符串,值是指针、结构或张量帧到数据。缓冲区上的所有操作均由 GuardDataMap 管理。

示例

  • 创建 GuardDataMap datamap 并设置标量键值。

    #include <ds3d/common/hpp/datamap.hpp>
    using namespace ds3d;
    
    GuardDataMap datamap(NvDs3d_CreateDataHashMap(), true); // creat a empty datamap
    TimeStamp ts{0};
    datamap.setData("DS3D::Timestamp", ts); // set timestamp
    
    float score = 0.1;
    datamap.setData("DS3D::Score", score); // copy score into datamap
    
  • 用户定义的结构添加到 ds3d datamap 中。

    ds3d datamap 要求每种数据类型在将数据添加到 datamap 之前都具有 typeid: uint64_t。这可以防止运行时出现任何错误的数据类型转换。为了实现这一点,有两种方法可以为结构启用 typeid。

    示例 1,直接在自定义数据结构定义中使用 REGISTER_TYPE_ID。这主要在用户定义新结构时使用。

    #define DS3D_TYPEID_TIMESTAMP 0x20002
    struct TimeStamp {
      uint64_t t0 = 0;
      uint64_t t1 = 0;
      uint64_t t2 = 0;
      REGISTER_TYPE_ID(DS3D_TYPEID_TIMESTAMP)
    };
    
    // Add the shared_ptr into datamap
    std::shared_ptr<TimeStamp> timePtr(new TimeStamp);
    datamap.setPtrData("DS3D::Timestamp0", timePtr);
    
    // Add a copy of the TimeStamp into datamap
    TimeStamp time1;
    datamap.setData("DS3D::Timestamp1", time1);
    

    示例 2,实例化模板 struct TpId<> { static constexpr TIdType __typeid(); },当将第三方数据结构添加到 datamap 且无法修改第三方现有 DataStructure 时,这很有帮助。

    // this is the 3rd-party structure
    struct Existing3rdpartData {
      float v0;
      int v1;
    };
    
    // derive ds3d::__TypeID for any 3rdparty data structure.
    #incude "ds3d/common/type_trait.h"
    #define DS3D_TYPEID_EXISTING_3RDPART_DATA 0x80001
    namespace ds3d {
    template <>
    struct TpId<Existing3rdpartData>: __TypeID<DS3D_TYPEID_EXISTING_3RDPART_DATA> {};
    }
    
    // Add the shared_ptr into datamap
    std::shared_ptr<Existing3rdpartData> dataPtr(new Existing3rdpartData);
    datamap.setPtrData("3rdpartyData0", dataPtr);
    
    // Add a copy of the Existing3rdpartData into datamap
    Existing3rdpartData data3rdparty{0.0f, 0};
    datamap.setData("3rdpartyData1", data3rdparty);
    
  • 创建 LiDAR 张量帧并添加到 GuardDataMap datamap 中。

    std::vector<vec4f> lidardata = {
        {{-5.0f, -5.0f, -3.0f, 0.6f}}, {{-5.0f, -5.0f, -3.0f, 0.85f}},
        {{1.0f, 0.5f, -1.0f, 0.82f}}, {{-5.0f, -5.0f, -3.0f, 0.8f}},
    };
    void* pointPtr = (void*)(&lidardata[0]);
    uint32_t pointsN = lidardata.size();
    FrameGuard lidarFrame = wrapLidarXYZIFrame<float>(
        (void*)pointPtr, pointsN, MemType::kCpu, 0,
    [holder = std::move(lidardata)](void*) {}); // lambda deleter
    
    const std::string keyName = "DS3D::LidarXYZI"; // user define a key name.
    // setGuardData holds a reference_count on the lidarFrame without deep-copy
    datamap.setGuardData(keyName, lidarFrame);
    
  • 创建 2D 图像张量帧并添加到 GuardDataMap datamap 中。

    std::vector<vec4b> imagedata = {
        {{255, 0, 0, 255}}, {{0, 255, 0, 255}}, {{0, 255, 0, 255}},
        {{0, 0, 255, 255}}, {{255, 255, 0, 255}}, {{0, 255, 0, 255}},
    };
    uint32_t width = 3, height = 2;
    Frame2DPlane colorPlane = {width, height, (uint32_t)sizeof(vec4b) * width, sizeof(vec4b), 0};
    void* colorPtr = (void*)(&imagedata[0]);
    uint32_t bytes = colorPlane.pitchInBytes * colorPlane.height;
    
    Frame2DGuard imageFrame = impl::Wrap2DFrame<uint8_t, FrameType::kColorRGBA>(
      colorPtr, {colorPlane}, bytes, MemType::kCpu, 0,
      [holder = std::move(imagedata)](void*) {}); // lambda deleter
    
    const std::string keyName = "DS3D::ColorFrame"; // user define a key name.
    // setGuardData holds a reference_count on the imageFrame without deep-copy
    datamap.setGuardData(keyName, imageFrame);
    
  • 创建自定义形状的张量帧并添加到 GuardDataMap datamap 中。

    std::vector<float> tensordata = {
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11.0f
    };
    void* tensorPtr = (void*)(&tensordata[0]);
    Shape tensorShape{3, {1, 3, 4}}; // tensor shape (1, 3, 4)
    uint32_t bytes = tensordata.size() * sizeof(tensordata[0]);
    FrameGuard tensorFrame = impl::WrapFrame<float, FrameType::kCustom>(
            tensorPtr, bytes, tensorShape, MemType::kCpu, 0,
            [holder = std::move(imagedata)](void*) {}); // lambda deleter
    
    const std::string keyName = "DS3D::dataarray"; // user define a key name.
    // setGuardData holds a reference_count on the tensorFrame without deep-copy
    datamap.setGuardData(keyName, tensorFrame);
    
  • 从 GuardDataMap datamap 查询数据值

    GuardDataMap::getGuardData,返回安全引用计数保护数据 GuardDataT<DataStructure>,例如 Frame2DGuard、FrameGuard、GuardDataT<TimeStamp> GuardDataMap::getPtrData,返回引用计数 std::shared_ptr<DataStructure>,例如 std::shared_ptr<TimeStamp> GuardDataMap::getData,返回 DataStructure 的副本。例如 TimeStamp

    // example to use different ways to get timestamp.
    std::string timeKey = "DS3D::Timestamp";
    if (datamap.hasData(timeKey)) {
        // get a COPY of Timestamp
        TimeStamp t0;
        DS_ASSERT(isGood(datamap.getData(timeKey, t0));
    
        // get a std::shared_ptr of Timestamp
        std::shared_ptr<TimeStamp> tPtr;
        DS_ASSERT(isGood(datamap.getPtrData(timeKey, tPtr));
    
        // get a reference-counted GuardDataT<Timestamp>
        GuardDataT<TimeStamp> timeGuard;
        DS_ASSERT(isGood(datamap.getPtrData(timeKey, timeGuard));
    
    // example to get a lidar tensor frame
    FrameGuard pointFrame;
    std::string lidarKey = "DS3D::LidarXYZI";
    if (datamap.hasData(lidarKey)) { // get lidar tensor frame
        // pointFrame holds a reference count
        DS_ASSERT(isGood(dataMap.getGuardData(lidarKey, pointFrame)));
        DataType dType = pointFrame->dataType();
        FrameType frameType = pointFrame->frameType();
        MemType memType = pointFrame->memType();
        Shape pShape = pointFrame->shape();
        void *dataPtr = pointFrame->base();
        size_t dataBytes = pointFrame->bytes();
    }
    
    // example to get a RGBA image tensor frame
    Frame2DGuard rgbaImage;
    std::string imageKey = "DS3D::ColorFrame";
    if (datamap.hasData(imageKey)) { // get 2D image tensor frame
        // rgbaImage holds a reference count
        DS_ASSERT(isGood(dataMap.getGuardData(imageKey, rgbaImage)));
        DataType dType = rgbaImage->dataType();
        FrameType frameType = rgbaImage->frameType();
        MemType memType = rgbaImage->memType();
        Shape pShape = rgbaImage->shape();
        void *dataPtr = rgbaImage->base();
        size_t dataBytes = rgbaImage->bytes();
        DS_ASSERT(rgbaImage->planes() == 1); // RGBA image has 1 plane.
        Frame2DPlane plane = rgbaImage->getPlane(0);
    }
    
    // example to get a custom shaped tensor frame, e.g. data_array
    FrameGuard tensorFrame;
    std::string tensorKey = "DS3D::dataarray";
    if (datamap.hasData(tensorKey)) { // get any tensor frame
        // tensorFrame holds a reference count
        DS_ASSERT(isGood(dataMap.getGuardData(tensorKey, tensorFrame)));
        DataType dType = tensorFrame->dataType();
        FrameType frameType = tensorFrame->frameType();
        MemType memType = tensorFrame->memType();
        Shape pShape = tensorFrame->shape();
        void *dataPtr = tensorFrame->base();
        size_t dataBytes = tensorFrame->bytes();
    }
    

DS3D DataMap 与 GstBuffer 互操作#

DS3D DataMap 具有 ABI 兼容类 ds3d::abiRefDataMap。因此,定义了 NvDs3DBuffer 以存储 DS3D datamap 以及 GstBuffer。头文件为 ds3d/gst/nvds3d_meta.h

struct NvDs3DBuffer {
    uint32_t magicID;  // must be 'DS3D'
    ds3d::abiRefDataMap* datamap;
};

警告

请勿直接使用 datamap。访问它的简单且安全的方法是通过 GuardDataMap。请参阅以下示例

  • GstBuffer 获取 datamap 的示例

#include <ds3d/common/hpp/datamap.hpp>
#include <ds3d/common/hpp/frame.hpp>
using namespace ds3d;

GstBuffer *gstBuf = ; // get the gstBuf from probe function or Gstreamer plugins
if (NvDs3D_IsDs3DBuf(gstBuf)) {
  const abiRefDataMap* refDataMap = nullptr;
  ErrCode c = NvDs3D_Find1stDataMap(gstBuf, refDataMap);
  if (refDataMap) {
    GuardDataMap dataMap(*refDataMap);
    FrameGuard lidarFrame;
    c = dataMap.getGuardData("DS3D::LidarXYZI", pointFrame); // get lidar points reference.

    FrameGuard uvCoord;
    c = dataMap.getGuardData("DS3D::TextureCoordKey", uvCoord); // get 3D points UV coordinates reference.

    Frame2DGuard depthFrame;
    c = dataMap.getGuardData("DS3D::DepthFrame", depthFrame); // get depth frame reference.

    DepthScale scale;
    c = dataMap.getData("DS3D::DepthScaleUnit", scale); // copy depth scale
  }

}
  • 在新的 GstBuffer 中创建一个 ds3d::datamap 的示例

    #include <ds3d/common/hpp/datamap.hpp>
    #include <ds3d/common/hpp/frame.hpp>
    #include <ds3d/common/impl/impl_frames.h>
    GuardDataMap datamap(NvDs3d_CreateDataHashMap(), true); // set true to take the reference ownership.
    
    /* Create color image frame and store them into ds3d datamap. */
    // Assume format is RGBA
    {
      Frame2DPlane colorPlane = {1920, 1080, 1920 * sizeof(uint8_t) , sizeof(uint8_t), 0};
      uint32_t colorBytesPerFrame = colorPlane.pitchInBytes * colorPlane.height;
      std::vector<uint8_t> data(colorBytesPerFrame); // Image data
      void* dataPtr = &data[0];
      // create color 2D frame
      Frame2DGuard frame = Wrap2DFrame<uint8_t, FrameType::kColorRGBA>(
            dataPtr, {_config.colorPlane}, bytesPerFrame, MemType::kCpu, 0,
            [data = std::move(data)](void*) {});
      c = datamap.setGuardData(kColorFrame, colorFrame); // store colorFrame reference into datamap.
      ... // check error code
    }
    

    准备好 datamap 后,您可以创建一个带有 DS3D datamap 的新 GstBuffer。

    // ``GuardDataMap datamap`` is ready
    GstBuffer* gstBuf = nullptr;
    ErrCode c = NvDs3D_CreateGstBuf(gstBuf, datamap.abiRef(), false); // set false to increase reference count.
    ... // check error code
    
  • 使用新的 ds3d datamap 更新现有 DS3D GstBuffer 的示例。

    // Assume ``GuardDataMap datamap`` is ready
    // Assume ``GstBuffer* gstBuf`` is created by another compoment
    ErrCode c = NvDs3D_UpdateDataMap(gstBuf, datamap.abiRef(), false); // set false to increase reference count.
      ... // check error code
    

ds3d::dataloader - 加载用于数据捕获的自定义库#

加载和管理 DS3D Dataloader#

示例

name: realsense_dataloader
type: ds3d::dataloader
out_caps: ds3d/datamap
custom_lib_path: libnvds_3d_dataloader_realsense.so
custom_create_function: createRealsenseDataloader
config_body:
  streams: [color, depth]

自定义 dataloader 必须具有 type: ds3d::dataloader。它通过显式调用 NvDs3D_CreateDataLoaderSrc(srcConfig, loaderSrc, start) 以及完整的组件 YAML 内容来创建。在此调用期间,将加载 custom_lib_path,并通过 custom_create_function 创建特定的数据加载器。GstAppsrc 对象也将在 loaderSrc.gstElement 中创建。

GstAppsrc 管理 ds3d::dataloader 数据流。此 ds3d::dataloader 组件可以由 gst-pipeline 自动启动,也可以由应用程序调用手动启动。

GuardDataLoader dataloader = loaderSrc.customProcessor;
ErrCode c = dataloader.start();

要停止 dataloader,用户可以将 GstAppsrc 状态设置为 GST_STATE_READY 或手动停止它。

GuardDataLoader dataloader = loaderSrc.customProcessor;
ErrCode c = dataloader.stop();

DeepStream 用户应用程序中的 DS3D Dataloader#

DS3D 自定义数据加载器与 Gstreamer/Glib 框架无关。但它也可以与 Gstramer 一起工作。ds3d::dataloader 可以与 GstAppSrc 交互式地协同工作。它们可以通过 NvDs3D_CreateDataLoaderSrc 创建。

示例

#include <ds3d/common/config.h>
#include <ds3d/gst/nvds3d_gst_plugin.h>

std::string yamlStr = R"(
  name: ds3d_lidar_file_source
  type: ds3d::dataloader
  out_caps: ds3d/datamap
  custom_lib_path: libnvds_lidarfileread.so
  custom_create_function: createLidarFileLoader
  config_body:
    data_config_file: lidar_data_list.yaml
    points_num: 242180
    mem_type: gpu # choose [cpu gpu]
    gpu_id: 0
    mem_pool_size: 6
    element_size: 4
    output_datamap_key: DS3D::LidarXYZI
)";

ErrCode c = ErrCode::kGood;
ComponentConfig config;
c = parseComponentConfig(yamlStr.c_str(), "./config_lidar_loader.yaml", config);
DS_ASSERT(config.type == ComponentType::kDataLoader);
DS_ASSERT(config.customLibPath == "libnvds_lidarfileread.so");
DS_ASSERT(config.customCreateFunction == "createLidarFileLoader");

gst::DataLoaderSrc appLoader;
c = NvDs3D_CreateDataLoaderSrc(c, appLoader, true);
// get DS3D custom dataloader.
GuardDataLoader dataLoader = appLoader.customProcessor;
// get GstAppSrc from this appLoader;
GstElement* appsrc = appLoader.gstElement.get();

// gstreamer pipeline setup and running.
// during each read_data from GstAppSrc callback. it would simultaneously reading data from dataloader
// GuardDataMap datamap;
// dataloader.read_data(datamap);

// DS3D dataloader would stop qutomatically when Gstpipeline is stopped.
// But in the case if user want to stop it early or manually.
// Obtain DS3D custom dataloader and stop manually.
c = dataloader.flush();
c = dataloader.stop();

GuardDataLoader 提供对 abiDataLoader 的安全访问。创建后,它将维护对 dataloader 的引用指针。

实现 DS3D 自定义 Dataloader#

示例

#include <ds3d/common/impl/impl_dataloader.h>
class TestTimeDataLoader : public ds3d::impl::SyncImplDataLoader {
public:
    TestTimeDataLoader() = default;

protected:
    ErrCode startImpl(const std::string& content, const std::string& path) override
    {
        setOutputCaps("ds3d/datamap");
        return ErrCode::kGood;
    }
    ErrCode readDataImpl(GuardDataMap& datamap) override
    {
        datamap.reset(NvDs3d_CreateDataHashMap());
        static uint64_t iTime = 0;
        TimeStamp t{iTime++, 0, 0};
        datamap.setData("time", t);
        emitError(ErrCode::kGood, "timstamp added");
        return ErrCode::kGood;
    }
    ErrCode stopImpl() override { return ErrCode::kGood; }
    ErrCode flushImpl() override { return ErrCode::kGood; }
};

DS3D_EXTERN_C_BEGIN
DS3D_EXPORT_API abiRefDataLoader*
createTestTimeDataloader()
{
    return NewAbiRef<abiDataLoader>(new TestTimeDataLoader);
}
DS3D_EXTERN_C_END

如上面的示例所示,您需要从 ds3d::impl::SyncImplDataLoader 类派生 dataloader,并为以下内容实现接口

ErrCode startImpl(const std::string& content, const std::string& path) override;
ErrCode readDataImpl(GuardDataMap& datamap) override;
ErrCode stopImpl() override;
ErrCode flushImpl() override;

ds3d::databridge - 加载自定义库以实现与 DS3D 之间的数据转换。#

此插件和自定义库有助于将数据类型转换为 ds3d/datamap 和从 ds3d/datamap 转换数据类型

更多详细信息:Gst-nvds3dbridge

ds3d::datafilter- DS3D 自定义 DataFilter#

DS3D DataFilter 处理来自 ds3d::datamap 的输入,并生成输入新的 ds3d::datamap 输出。用户可以为其用例实现自定义 datafilter 库。

在 DeepStream 应用中创建和管理 DS3D Datafilter#

示例

#include <ds3d/common/config.h>
#include <ds3d/gst/nvds3d_gst_ptr.h>
#include <ds3d/gst/nvds3d_gst_plugin.h>

std::string yamlStr = R"(
  name: fusion_inference
  type: ds3d::datafilter
  in_caps: ds3d/datamap
  out_caps: ds3d/datamap
  custom_lib_path: libnvds_tritoninferfilter.so
  custom_create_function: createLidarInferenceFilter
  config_body:
    mem_pool_size: 2
    model_inputs:
    config_file: model_config_files/config_triton_bev_fusion_infer_grpc.pbtxt
    - name: input_image_0
      datatype: UINT8
      shape: [1, 900, 1600, 4]
      from: DS3D::ColorFrame_0+1
      is_2d_frame: true
    - name: input_lidar
      datatype: FP32
      shape: [242180, 4]
      from: DS3D::LidarXYZI+0
)";

gst::ElePtr gstPlugin = gst::elementMake("nvds3dfilter", "ds3d-custom-filter");
g_object_set(G_OBJECT(gstPlugin.get()), "config-content", yamlStr.c_str(), nullptr);
GstElement* ele = gstPlugin.get();

自定义 datafilter 必须具有 type: ds3d::datafilter。它通过 nvds3dfilter Gst-plugin 加载。它由 gst_element_set_state(GST_STATE_READY) 启动。在此调用期间,将加载 custom_lib_path,并通过 custom_create_function 创建特定的数据过滤器。nvds3dfilter Gst-plugin 具有 config-contentconfig-file 属性。必须设置其中一个属性才能创建 datafilter 对象。

实现自定义 DS3D Datafilter#

示例

#include <ds3d/common/impl/impl_datafilter.h>
class TestFakeDataFilter : public impl::BaseImplDataFilter {
public:
    TestFakeDataFilter() = default;

protected:
    ErrCode startImpl(const std::string& content, const std::string& path) override
    {
        setInputCaps(kFakeCapsMetaName);
        setOutputCaps(kFakeCapsMetaName);
        return ErrCode::kGood;
    }
    ErrCode processImpl(
        GuardDataMap datamap, OnGuardDataCBImpl outputDataCb,
        OnGuardDataCBImpl inputConsumedCb) override
    {
        DS_ASSERT(datamap);
        TimeStamp t;
        ErrCode c = datamap.getData("time", t);
        if (!isGood(c)) {
            return c;
        }
        t.t0 += 1;
        inputConsumedCb(ErrCode::kGood, datamap);
        c = datamap.setData("time", t);
        if (!isGood(c)) {
            return c;
        }
        outputDataCb(ErrCode::kGood, datamap);
        return ErrCode::kGood;
    }

    ErrCode flushImpl() override { return ErrCode::kGood; }
    ErrCode stopImpl() override { return ErrCode::kGood; }
};

DS3D_EXTERN_C_BEGIN
DS3D_EXPORT_API abiRefdatafilter*
createTestFakeDatafilter()
{
    return NewAbiRef<abidatafilter>(new TestFakeDataFilter);
}
DS3D_EXTERN_C_END

如上面的示例所示,您需要从 ds3d::impl::BaseImplDataFilter 类派生 datafilter,并为以下内容实现接口

ErrCode startImpl(const std::string& content, const std::string& path) override;
ErrCode processImpl(
        GuardDataMap datamap, OnGuardDataCBImpl outputDataCb,
        OnGuardDataCBImpl inputConsumedCb) override;
ErrCode stopImpl() override;
ErrCode flushImpl() override;

要通过 nvds3dfilter Gst-plugin 加载此自定义库,您还需要导出特定的符号 createTestFakeDatafilter

ds3d::datarender - 加载 DS3D 自定义 DataRender#

DS3D 自定义 DataRender 与 Gstreamer/Glib 框架无关。但它也可以与 Gstramer 一起工作。ds3d::datarender 可以与 GstAppSink 交互式地协同工作。它们可以通过 NvDs3D_CreateDataRenderSink 创建。

示例

加载和管理 DS3D Datarender#

示例

#include <ds3d/common/config.h>
#include <ds3d/gst/nvds3d_gst_plugin.h>

std::string yamlStr = R"(
            name: lidar_render
            type: ds3d::datarender
            in_caps: ds3d/datamap
            custom_lib_path: libnvds_3d_gl_datarender.so
            custom_create_function: createLidarDataRender
            gst_properties:
              sync: True
              async: False
              drop: False
            config_body:
              title: ds3d-lidar-render
              streams: [lidardata]
              width: 1280
              height: 720
              block: True
              view_position: [0, 0, 60]
              view_target: [0, 0, 0]
              view_up: [0, 1, 0]
              near: 0.3
              far: 100
              fov: 50
              lidar_color: [0, 255, 0]
              lidar_data_key: DS3D::LidarXYZI
              element_size: 4
              lidar_bbox_key: DS3D::Lidar3DBboxRawData
              enable_label: True
)";

ErrCode c = ErrCode::kGood;
ComponentConfig config;
c = parseComponentConfig(yamlStr.c_str(), "./config_lidar_loader.yaml", config);
DS_ASSERT(config.type == ComponentType::kDataRender);
DS_ASSERT(config.customLibPath == "libnvds_3d_gl_datarender.so");
DS_ASSERT(config.customCreateFunction == "createLidarDataRender");

gst::DataRenderSink appRender;
c = NvDs3D_CreateDataRenderSink(config, appRender, true);
// get DS3D custom datarender.
GuardDataRender datarender = appRender.customProcessor;
// get GstAppSink from this appRender;
GstElement* appsink = appRender.gstElement.get();

// gstreamer pipeline setup and running.
// during each render_data from GstAppSink callback. it would simultaneously reading data from datarender
// datarender.render(datamap, consumed_callback);

// DS3D datarender would stop qutomatically when Gstpipeline is stopped.
// But in the case if user want to stop it early or manually.
// Obtain DS3D custom datarender and stop manually.
c = datarender.stop();

自定义 datarender 必须具有 type: ds3d::datarender。它通过显式调用 NvDs3D_CreateDataRenderSink(sinkConfig, renderSink, start) 以及完整的组件 YAML 内容来创建。在此调用期间,将加载 custom_lib_path,并通过 custom_create_function 创建特定的数据加载器。GstAppsink 对象也将在 renderSink.gstElement 中创建。

GstAppsink 管理 ds3d::datarender 数据流。此 ds3d::datarender 组件可以由 gst-pipeline 自动启动,也可以由应用程序调用手动启动。

GuardDataRender datarender = renderSink.customProcessor;
ErrCode c = datarender.start();

要停止 datarender,您可以将 GstAppsink 状态设置为 GST_STATE_READY,或手动停止。.. code-block:: text

GuardDataRender datarender = renderSink.customProcessor; ErrCode c = datarender.stop();

GuardDataRender 提供对 abidatarender 的安全访问。创建后,它将维护对 datarender 的引用指针。preroll 仅调用一次以初始化某些资源。

实现 DS3D 自定义 Datarender#

示例

#include <ds3d/common/impl/impl_datarender.h>
class TestFakeDataRender : public impl::BaseImplDataRender {
public:
    TestFakeDataRender() = default;

protected:
    ErrCode startImpl(const std::string& content, const std::string& path) override
    {
        setInputCaps("ds3d/datamap");
        return ErrCode::kGood;
    }
    ErrCode prerollImpl(GuardDataMap datamap) override { return ErrCode::kGood; }
    ErrCode renderImpl(GuardDataMap datamap, OnGuardDataCBImpl dataDoneCb) override
    {
        DS_ASSERT(datamap);
        emitError(ErrCode::kGood, "data rendered");
        dataDoneCb(ErrCode::kGood, datamap);
        return ErrCode::kGood;
    }
    ErrCode flushImpl() override { return ErrCode::kGood; }
    ErrCode stopImpl() override { return ErrCode::kGood; }
};

DS3D_EXTERN_C_BEGIN
DS3D_EXPORT_API abiRefdatarender*
createTestFakedatarender()
{
    return NewAbiRef<abiDataRender>(new TestFakeDataRender());
}
DS3D_EXTERN_C_END

如上面的示例所示,您需要从 ds3d::impl::BaseImplDataRender 类派生 datarender,并为以下内容实现接口

ErrCode startImpl(const std::string& content, const std::string& path) override;
ErrCode prerollImpl(GuardDataMap datamap) override;
ErrCode renderImpl(GuardDataMap datamap, OnGuardDataCBImpl dataDoneCb) override;
ErrCode stopImpl() override;
ErrCode flushImpl() override;

要通过 NvDs3D_CreateDataRenderSink 加载此自定义库,您还需要导出特定的符号 createTestFakedatarender

自定义库配置规范#

组件通用配置规范#

ds3d 通用配置规范#

属性

含义

类型和范围

示例

type

自定义处理器类型

字符串,[ds3d::dataloader, ds3d::datafilter, ds3d::datarender]

type: ds3d::dataloader

name

指示用户定义的组件名称

字符串

name: depthloader

in_caps

指示组件的 Gst sink caps

字符串

in_caps: ds3d/datamap

out_caps

指示组件的 Gst sink caps

字符串

out_caps: ds3d/datamap

custom_lib_path

指示自定义库路径

字符串

custom_lib_path: libnvds_3d_gl_datarender.so

custom_create_function

指示用于创建特定 ds3d 处理组件的自定义函数

字符串

custom_create_function: createPointCloudDataRender

config_body

指示自定义组件的 YAML 特定内容

字符串

config_body

in_streams: [color, depth] max_points: 407040

这些自定义库是 DeepStream 发布包的一部分。

支持的 DS3D 自定义处理库#

DS3D 自定义库#

DS3D 处理类型

功能

DS3D 自定义库

DS3D 创建实例函数

描述

dataloader

激光雷达文件读取器

libnvds_lidarfileread.so

createLidarFileLoader

激光雷达文件数据读取器库,请参阅 自定义 Dataloader libnvds_lidarfileread 配置规范 中的详细信息

dataloader

realsense 相机深度/图像捕获

libnvds_3d_dataloader_realsense.so

createRealsenseDataloader

RealSense 相机捕获数据加载器库,请参阅 自定义 Dataloader libnvds_3d_dataloader_realsense 配置规范 中的详细信息

datafilter

多传感器 triton 推理库

libnvds_tritoninferfilter.so

createLidarInferenceFilter

多模态传感器 triton 推理库,请参阅 libnvds_tritoninferfilter 配置规范 中的详细信息

datafilter

data_alignment

libnvds_3d_alignment_datafilter.so

createLidarAlignmentFilter

激光雷达/相机传感器内部和外部参数以及对齐,请参阅 自定义 ds3d::datafilter 库:libnvds_3d_alignment_datafilter.so 中的详细信息

datafilter

lidar_data_preprocess

libnvds_3d_lidar_preprocess_datafilter.so

createLidarPreprocessFilter

激光雷达数据体素处理,请参阅 自定义 Datafilter libnvds_3d_lidar_preprocess_datafilter 规范 中的详细信息

datafilter

depth-to-point-cound

libnvds_3d_depth2point_datafilter.so

createDepth2PointFilter

将图像深度数据转换为 3D 点云数据,请参阅 自定义 datafilter libnvds_3d_depth2point_datafilter 配置规范 中的详细信息

databridge

将 2D 桥接到 DS3D

libnvds_3d_video_databridge.so

createVideoBridge2d3d

将 DeepStream 2D batchmeta 和 surface 转换为 ds3d::datamap,请参阅 配置文件 中的详细信息

datamixer

用于视频和激光雷达/雷达的混合器

libnvds_3d_multisensor_mixer.so

createMultiSensorMixer

将视频数据 (2D) 和 LiDAR 数据 (3D) 组合到单个 ds3d::datamap 中,请参阅 配置文件 中的详细信息

datarender

3D 多视图场景渲染

libnvds_3d_gles_ensemble_render.so

NvDs3D_CreateGlesEnsembleRender

使用 GLES 渲染 3D 多视图场景,其中包含 ds3d::datamap 内的各种元素(纹理、LiDAR 点、边界框),请参阅 自定义 datarender libnvds_3d_gles_ensemble_render 配置规范 中的详细信息

datarender

具有纹理的 3D 点云数据渲染

libnvds_3d_gl_datarender.so

createPointCloudDataRender

使用 ds3d::datamap 内的 RGBA 颜色纹理渲染 3D(场景构建)点云 (XYZ) 数据,请参阅 自定义 datarender libnvds_3d_gl_datarender 配置规范 中的详细信息

datarender

3D 激光雷达 (XYZI/XYZ) 数据渲染

libnvds_3d_gl_datarender.so

createLidarDataRender

渲染 ds3d::datamap 内的 3D 激光雷达 (XYZI/XYZ) 数据,请参阅 自定义 datarender libnvds_3d_gl_datarender 配置规范 中的详细信息

datarender

深度图像 2D 渲染

libnvds_3d_gl_datarender.so

createDepthStreamDataRender

渲染 ds3d::datamap 内的 2D 深度和相机 RGBA 数据,请参阅 自定义 datarender libnvds_3d_gl_datarender 配置规范 中的详细信息

libnvds_tritoninferfilter 配置规范#

具有 ds3d::datamap 中键值对的多模态张量 Triton 推理,支持用户定义的自定义预处理和后处理。

  • 多模态 triton 推理标头的配置

    name: multimodal_triton_infer
    type: ds3d::datafilter
    in_caps: ds3d/datamap
    out_caps: ds3d/datamap
    custom_lib_path: libnvds_tritoninferfilter.so
    custom_create_function: createLidarInferenceFilter
    
  • Config body 规范

libnvds_tritoninferfilter config_body 字段#

属性

含义

类型和范围

示例

in_streams

将处理哪种数据类型

字符串列表,可选

in_streams: [lidar]

gpu_id

GPU 设备 ID

整数,默认值:0

gpu_id: 0

config_file

nvinferserver(triton) 底层库配置文件,支持 gRPC 和 CAPI,请参阅 底层 libnvds_infer_server.so 配置文件规范 中的更多详细信息

路径字符串

config_file: model_config_files/config_triton_bev_fusion_infer_grpc.pbtxt

mem_pool_size

输入张量池的大小

整数

mem_pool_size: 8

model_inputs

模型 ‘s 输入层信息,如果没有定义 custom_preprocess,inferencefilter 会将 ds3d::datamap 中的键值帧转发到 triton 的输入张量

字典列表

  • name: input_image_0

    datatype: UINT8 shape: [1, 900, 1600, 4] from: DS3D::ColorFrame_0+1 is_2d_frame: true

input_tensor_mem_type

预处理后的输入张量内存类型

字符串:[GpuCuda CpuCuda]

input_tensor_mem_type: GpuCuda

custom_preprocess_lib_path

自定义预处理库路径

字符串

custom_preprocess_lib_path: /opt/nvidia/deepstream/deepstream/lib/libnvds_lidar_custom_preprocess_impl.so

custom_preprocess_func_name

自定义预处理函数名称

字符串

custom_preprocess_func_name: CreateInferServerCustomPreprocess

postprocess

用户定义的后处理信息

字典

postprocess

score_threshold: 0.5

labels

用户为自定义后处理定义的标签

字典列表

labels
  • car

    color: [255, 158, 0]

  • truck

    color: [255, 99, 71]

model_inputs 包含所有输入层信息。如果在 config body 中指定了自定义预处理函数/库。该库将搜索输入 ds3d::datamapfrom 键名,并将帧/张量数据转发到 Triton 服务器的输入张量。from 键名必须是 ds3d::datamap 内的帧、2D 帧或张量

  • model_inputs 的配置规范

列表 model_inputs 的项#

属性

描述

类型和范围

示例

name

模型的输入张量名称

字符串

name: input_image_0

datatype

模型的输入数据类型

字符串值,取值范围:[FP32, FP16, INT8, INT32, INT16, UINT8, UINT16, UINT32, FP64, INT64, UINT64, BYTES, BOOL]

datatype: FP32

shape

模型的输入张量形状

整数列表

shape: [1, 900, 1600, 4]

from

输入 ds3d::datamap 的键名,该值必须是帧/2D 帧/张量。如果自定义预处理不存在,则帧将直接转发到 Triton 的输入张量。

字符串

from: DS3D::ColorFrame_5

is_2d_frame

指示 ds3d::datamap 内部的 from 是 2D 帧。

布尔值

is_2d_frame: true

  • triton 推理之前的自定义预处理

如果指定了 custom_preprocess_lib_pathcustom_preprocess_func_name,则将加载自定义处理,并解析配置主体,获取所有通用和用户定义的信息。然后处理每个输入 ds3d::datamap 并生成用于 triton 推理输入的 batchArray

用户可以从 sources/includes/ds3d/common/hpp/lidar_custom_process.hpp 派生接口 IInferCustomPreprocessor。请参阅 sources/libs/ds3d/inference_custom_lib/ds3d_v2x_infer_custom_preprocess/nvinferserver_custom_preprocess.cpp 中的示例

#include <ds3d/common/hpp/datamap.hpp>
#include <ds3d/common/hpp/frame.hpp>
#include <ds3d/common/hpp/lidar_custom_process.hpp>
using namespace ds3d;
using namespace nvdsinferserver;
class NvInferServerCustomPreProcess : public IInferCustomPreprocessor {
public:
  // process key-values from datamap and generate into model inputs batchArray.
  NvDsInferStatus preproc(GuardDataMap &datamap, SharedIBatchArray batchArray, cudaStream_t stream) override {...}
};
extern "C" {
IInferCustomPreprocessor *CreateInferServerCustomPreprocess() {
  return new NvInferServerCustomPreProcess();
} }
  • Triton 推理后的自定义后处理

后处理对于每个模型都非常具体。您需要根据推理输出张量结果来实现自己的后处理函数。自定义后处理库和函数在 nvdsinferserver 的配置中指定。例如,在 apps/sample_apps/deepstream-3d-lidar-sensor-fusion/model_config_files/config_triton_bev_fusion_infer_grpc.pbtxt 中。

infer_config {
  backend {
    triton {
      model_name: "bevfusion"
      grpc {...}
  } }
  extra {
    output_buffer_pool_size: 4
    # specify custom postprocess function
    custom_process_funcion: "Nvds3d_CreateLidarDetectionPostprocess"
  }
  custom_lib {
    # specify custom postprocess library
    path: "libnvds_3d_infer_postprocess_lidar_detection.so"
  }
}

此处提供了一个自定义后处理实现的示例:sources/libs/ds3d/inference_custom_lib/ds3d_lidar_detection_postprocess/ds3d_infer_postprocess_lidar_detection.cpp

#include "infer_custom_process.h"
#include <ds3d/common/hpp/frame.hpp>
#include <ds3d/common/hpp/datamap.hpp>
using namespace ds3d;
using namespace nvdsinferserver;
class DS3DTritonLidarInferCustomPostProcess : public IInferCustomProcessor {
public:
  // process key-values from datamap and generate into model inputs batchArray.
  NvDsInferStatus inferenceDone(const IBatchArray* batchArray, const IOptions* inOptions) override {
   ...

    // get ``ds3d::datamap`` from ``inOptions``
    abiRefDataMap* refDataMap = nullptr;
    if (inOptions->hasValue(kLidarRefDataMap)) {
        INFER_ASSERT(inOptions->getObj(kLidarRefDataMap, refDataMap) == NVDSINFER_SUCCESS);
    }
    GuardDataMap dataMap(*refDataMap);
    ...
    // parsing output tensors from batchArray
    TensorMap outTensors;
    for (uint32_t i = 0; i < batchArray->getSize(); ++i) {
        auto buf = batchArray->getSafeBuf(i);
        outTensors[buf->getBufDesc().name] = buf;
    }
    std::vector<Lidar3DBbox> bboxes;
    ret = parseLidar3Dbbox(outTensors, bboxes);
    // warp data into ds3d frame ``bboxFrame``
    size_t bufBytes = sizeof(Lidar3DBbox) * bboxes.size();
    void* bufBase = (void*)bboxes.data();
    Shape shape{3, {1, (int)bboxes.size(), sizeof(Lidar3DBbox)}};
    FrameGuard bboxFrame = impl::WrapFrame<uint8_t, FrameType::kCustom>(
        bufBase, bufBytes, shape, MemType::kCpu, 0, [outdata = std::move(bboxes)](void*) {});
    // add key-value fram into ds3d::datamap
    ErrCode code = dataMap.setGuardData(_3dBboxKey, bboxFrame);
    ...
    return ret;
  }
};
extern "C" {
IInferCustomProcessor *Nvds3d_CreateLidarDetectionPostprocess() {
  return new DS3DTritonLidarInferCustomPostProcess();
} }

自定义数据过滤器 libnvds_3d_alignment_datafilter 规范#

可以使用 DeepStreamSDK 提供的自定义库完成激光雷达和视频数据的Data alignment(数据对齐)。

更多详细信息请参见此处: 自定义 ds3d::datafilter 库:libnvds_3d_alignment_datafilter.so

自定义数据过滤器 libnvds_3d_lidar_preprocess_datafilter 规范#

在 V2X 模型传感器融合推理之前,将 LiDAR 数据预处理为体素数据格式。源文件位于 /opt/nvidia/deepstream/deepstream/sources/libs/ds3d/datafilter/lidar_preprocess

  • LiDAR 数据预处理 ds3d::datafilter 标头配置

    name: lidarpreprocess
    type: ds3d::datafilter
    out_caps: ds3d/datamap
    custom_lib_path: libnvds_3d_lidar_preprocess_datafilter.so
    custom_create_function: createLidarPreprocessFilter
    
  • 配置主体规范

例如

config_body:
mem_pool_size: 4
filter_input_datamap_key: DS3D::LidarXYZI_0
model_inputs:
- name: feats
  datatype: FP16
  shape: [4, 8000, 10, 9]
- name: coords
  datatype: INT32
  shape: [4, 8000, 4]
- name: N
  datatype: INT32
  shape: [4, 1]
gpu_id: 0
input_tensor_mem_type: GpuCuda
lidar_data_from: [DS3D::LidarXYZI_0, DS3D::LidarXYZI_1, DS3D::LidarXYZI_2, DS3D::LidarXYZI_3]
output_features_tensor_key: DS3D::LidarFeatureTensor
output_coords_tensor_key: DS3D::LidarCoordTensor
output_num_tensor_key: DS3D::LidarPointNumTensor
DS3D libnvds_3d_lidar_preprocess_datafilter 自定义库#

属性

描述

类型和范围

示例

mem_pool_size

内存缓冲区池大小

整数

mem_pool_size: 4

filter_input_datamap_key

指定输入激光雷达数据键名

字符串

filter_input_datamap_key: DS3D::LidarXYZI_0

model_inputs

指定模型输入层信息

字典

请参阅 deepstrem-3d-lidar-sensor-fusion/ds3d_lidar_video_sensor_v2xfusion.yml 中的示例

gpu_id

指定 GPU ID

整数

gpu_id: 0

input_tensor_mem_type

指定模型输入张量内存类型

字符串,从 [GpuCuda, CpuCuda] 中选择值

input_tensor_mem_type: GpuCuda

lidar_data_from

指定激光雷达数据键名

字符串列表

lidar_data_from: [DS3D::LidarXYZI_0]

output_features_tensor_key

指定输出激光雷达特征张量键名

字符串

DS3D::LidarFeatureTensor

output_coords_tensor_key

指定输出激光雷达坐标张量键名

字符串

output_coords_tensor_key: DS3D::LidarCoordTensor

output_num_tensor_key

指定输入张量的激光雷达数据数量的键名

字符串

output_num_tensor_key: DS3D::LidarPointNumTensor

自定义数据加载器 libnvds_lidarfileread 配置规范#

该库逐帧读取激光雷达数据文件,它为每帧创建一个新的 ds3d::datamap 并传递给下一个组件。源文件位于 /opt/nvidia/deepstream/deepstream/sources/libs/ds3d/dataloader/lidarsource

  • 激光雷达文件读取器 ds3d::dataloader 标头配置

    name: ds3d_lidar_file_source
    type: ds3d::dataloader
    out_caps: ds3d/datamap
    custom_lib_path: libnvds_lidarfileread.so
    custom_create_function: createLidarFileLoader
    
  • 配置主体规范

例如

config_body:
  data_config_file: lidar_nuscene_data_list.yaml
  points_num: 242180
  fixed_points_num: True
  lidar_datatype: FP32
  mem_type: gpu
  gpu_id: 0
  mem_pool_size: 6
  element_size: 4
  output_datamap_key: DS3D::LidarXYZI
  file_loop: True
DS3D libnvds_lidarfileread 自定义库#

属性

描述

类型和范围

示例

data_config_file

激光雷达数据列表文件路径

路径字符串或路径字符串列表

data_config_file: lidar_data_list.yaml

source_id

指定加载器实例的唯一源 ID

整数

source_id: 0

points_num

指定每帧的点数

整数

points_num: 70000

fixed_points_num

指示点数始终与 points_num 相同

布尔值

fixed_points_num: False

lidar_datatype

指定激光雷达数据类型

字符串,目前仅支持 FP32。

lidar_datatype: FP32

mem_type

指定处理数据的内存类型,支持 [cpu, gpu]

字符串, [cpu, gpu]

mem_type: gpu

mem_pool_size

指定为帧分配的缓冲区池大小

整数

mem_pool_size: 16

gpu_id

mem_type: gpu 的情况下指定 GPU ID

整数

gpu_id: 0

element_size

指定每个点将读取多少个元素。 3 表示 XYZ,4 表示 XYZI。

整数

element_size: 4

element_stride

指定 2 个连续点之间的元素步幅。例如,XYZI,步幅:4,XYZIT,5

整数

element_stride: 4

file_loop

指示是否循环文件列表而不带 EOS

布尔值

file_loop: True

output_datamap_key

指定输出帧键名到 ds3d::datamap

字符串或字符串列表

output_datamap_key: DS3D::LidarXYZI_0

  • 激光雷达数据配置文件

该库从 data_config_file 读取帧,这是一个单独的文件容器,包含多个激光雷达文件。每个激光雷达文件都是一个单独的激光雷达帧文件,这些文件在 source-list 内部列出。每个项目的键名是激光雷达帧的时间戳(毫秒)。

data_config_file 的示例。

source-list:
  - 0: /opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-3d-lidar-sensor-fusion/data/nuscene/LIDAR_TOP/000000-LIDAR_TOP.bin
  - 50: /opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-3d-lidar-sensor-fusion/data/nuscene/LIDAR_TOP/000001-LIDAR_TOP.bin
  - 100: /opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-3d-lidar-sensor-fusion/data/nuscene/LIDAR_TOP/000002-LIDAR_TOP.bin

自定义数据加载器 libnvds_3d_dataloader_realsense 配置规范#

Realsense Dataloader 标头配置

name: realsense_dataloader
type: ds3d::dataloader
out_caps: ds3d/datamap
custom_lib_path: libnvds_3d_dataloader_realsense.so
custom_create_function: createRealsenseDataloader

libnvds_3d_dataloader_realsense.so 需要您安装 librealsense2 SDK。 对于 x86,请按照 IntelRealSense/librealsense 中的说明进行操作。 对于 Jetson 平台,请按照 IntelRealSense/librealsense 中的说明进行操作。

libnvds_3d_dataloader_realsense config_body 字段#

属性

含义

类型和范围

示例

streams

指定要启用的流

List[String],从 [color, depth] 中选择

streams: [color, depth]

aligned_image_to_depth

指示颜色图像是否与深度对齐

布尔值

aligned_image_to_depth: False

自定义数据过滤器 libnvds_3d_depth2point_datafilter 配置规范#

将 2D 深度数据转换为 3D 点云 (XYZ) 数据到 ds3d::datamap

  • 深度到点标头配置

name: depth2points
type: ds3d::datafilter
in_caps: ds3d/datamap
out_caps: ds3d/datamap
custom_lib_path: libnvds_3d_depth2point_datafilter.so
custom_create_function: createDepth2PointFilter
libnvds_3d_depth2point_datafilter config_body 字段#

属性

含义

类型和范围

示例

streams

指定要启用的流

List[String],从 [color, depth] 中选择

streams: [color, depth]

max_points

指示要分配的最大 3D 点数

Uint32

max_points: 407040

mem_pool_size

指示最大缓冲区池大小

Uint32

mem_pool_size: 8

自定义数据渲染器 libnvds_3d_gles_ensemble_render 配置规范#

使用 OpenGL ES (GLES) 渲染 3D 场景,其中包含各种元素(纹理、LiDAR 点、边界框),从而实现灵活的布局自定义。用户可以将窗口拆分为多个视图,并将来自 ds3d::datamap 的每个张量数据或帧投影到单独的视图或同时投影到多个视图中。如果多个帧渲染到单个视图位置重叠,它也可能支持叠加,这取决于渲染图顺序。

  • 配置标头

name: ds3d_sensor_fusion_render
type: ds3d::datarender
in_caps: ds3d/datamap
custom_lib_path: libnvds_3d_gles_ensemble_render.so
custom_create_function: NvDs3D_CreateGlesEnsembleRender
  • 配置主体

具有 render_graph 的多视图配置示例。在同一个 ds3d::datamap 内渲染了 2 个视图。2D 彩色图像由 texture3d_render 渲染到视图区域 [0, 0, 640, 360] 中;LiDAR 数据由 lidar3d_render 渲染到视图区域 [640, 0, 1280, 360] 中。

config_body:
  window_width: 1280 # window size
  window_height: 360 # window size
  color_clear: true
  window_title: DS3D-Lidar-6-Cameras-BEVFusion
  render_graph:
    - texture3d_render: # 2D texture view
        layout: [0, 0, 640, 360] # layout [x0, y0, x1, y1]
        max_vertex_num: 6
        color_clear: false
        texture_frame_key: DS3D::ColorFrame_2 # image data key
    - lidar3d_render: # lidar top view
        layout: [640, 0, 1280, 360] # layout [x0, y0, x1, y1]
        color_clear: false
        view_position: [0, 0, 30]
        view_target: [0, 0, 0]
        view_up: [0, 1, 0]
        lidar_color: [0, 0, 255]
        lidar_data_key: DS3D::LidarXYZI
        lidar_bbox_key: DS3D::Lidar3DBboxRawData
        element_size: 4
libnvds_3d_gles_ensemble_render config_body 字段#

属性

含义

类型和范围

示例

window_title

指定窗口标题

字符串

window_title: DS3D-Lidar-6-Cameras-BEVFusion

window_width

指定窗口宽度

uint32

window_width: 1920

window_height

指定窗口高度

uint32

window_height: 1080

color_clear

指定当新帧到达时是否清除整个窗口

布尔值

color_clear: true

render_graph

指定不同视图中多个渲染器的列表

List[Dict]

render_graph:
 - texture3d_render:
    layout: [0, 0, 640, 360]
    color_clear: false
    texture_frame_key: DS3D::ColorFrame
 - lidar3d_render:
    layout:  [640, 0, 1280, 360]
    color_clear: false
    lidar_data_key: DS3D::LidarXYZI
  • 渲染图 render_graph

它支持 2 种不同的视图模式

  • texture3d_render,它将 2D 图像数据渲染到指定的视图区域。

  • lidar3d_render,它将激光雷达数据和 3D 边界框数据渲染到指定的视图区域。

每种模式都可以在同一个 render_graph 中配置多次。单个 ds3d::datamap 内的多个摄像头数据可以配置到不同的视图区域。类似地,同一个 ds3d::datamap 内的多个激光雷达数据也可以在不同的视点(顶视图、前视图、侧视图)配置到不同的视图区域。

  • texture3d_render 的配置规范

libnvds_3d_gles_ensemble_render texture3d_render 字段#

属性

含义

类型和范围

示例

layout

指定 [x0, y0, x1, y1] 的视图位置

List[Float]

layout: [0, 0, 640, 360] x0 = 0; y0 = 0; x1 = 640; y1 = 360;

color_clear

指示在新帧到来之前是否清除此视图。

布尔值

color_clear: false

texture_frame_key

ds3d::datamap 指定纹理图像键名

字符串

texture_frame_key: DS3D::ColorFrame_1+1

max_vertex_num

指定用于纹理绘制的 vertex_num,默认值为 6

uint32

max_vertex_num: 6

texture_vetex_key

ds3d::datamap 指定 3D 顶点键名,它用于纹理绘制,默认情况下有 6 个值。

字符串

texture_vetex_key: DS3D::TextureVertexKey

texture_coord_key

ds3d::datamap 指定纹理坐标键名,它用于纹理绘制,默认情况下有 6 个值。

字符串

texture_coord_key: DS3D::TextureCoordKey

  • lidar3d_render 的配置规范

libnvds_3d_gles_ensemble_render lidar3d_render 字段#

属性

含义

类型和范围

示例

layout

指定 [x0, y0, x1, y1] 的视图位置

List[Float]

layout: [0, 0, 640, 360] x0 = 0; y0 = 0; x1 = 640; y1 = 360;

color_clear

指示在新帧到来之前是否清除此视图。

布尔值

color_clear: false

lidar_color

指定激光雷达数据颜色 RGB

list[uint8]

lidar_color: [0, 0, 255]

lidar_data_key

ds3d::datamap 指定激光雷达数据键名

字符串

lidar_data_key: DS3D::LidarXYZI+0

element_size

指定激光雷达数据元素大小。从 [3, 4] 中选择,默认值 4 用于 xyzi。值 3 用于 xyz。

uint32

element_size: 4

lidar_bbox_key

ds3d::datamap 指定 3D 检测边界框键名

字符串

lidar_bbox_key: DS3D::Lidar3DBboxRawData

project_lidar_to_image

指示是否需要将激光雷达数据和边界框投影到相机图像中,默认值:false

布尔值

project_lidar_to_image: false

intrinsics_mat_key

ds3d::datamap 指定相机内参矩阵键名,当 project_lidar_to_image: true 时需要此项

intrinsics_mat_key: DS3D::Cam2_IntrinsicMatrix

extrinsics_mat_key

ds3d::datamap 指定激光雷达外参矩阵键名

extrinsics_mat_key: DS3D::LidarToCam2_ExtrinsicMatrix

image_width

指定原始相机内参图像宽度,当 project_lidar_to_image: true 时需要此项

image_width: 1600

image_height

指定原始相机内参图像高度,当 project_lidar_to_image: true 时需要此项

image_height: 900

view_position

指定视图位置 [x, y, z] 坐标

List[Float]

view_position: [0, 0, -1]

view_target

指定视图目标 [x, y, z] 坐标

List[Float]

view_target: [0, 0, 1]

view_up

指定视图向上方向 [x, y, z] 坐标

List[Float]

view_up: [0, -1.0, 0]

perspective_near

指定透视投影近平面

浮点数

perspective_near: 0.1

perspective_far

指定透视投影远平面

浮点数

perspective_far: 10.0

perspective_fov

指定透视投影视场,角度

浮点数

perspective_fov: 40.0

perspective_ratio

指定宽度/高度的透视比率。默认值 0.0f 表示视图宽度/视图高度

浮点数

perspective_ratio: 0.0

enable_label

指示是否启用标签文本渲染。默认值:false

布尔值

enable_label: true

自定义数据渲染器 libnvds_3d_gl_datarender 配置规范#

libnvds_3d_gl_datarender 的通用标头配置

name: depth-point-render
type: ds3d::datarender
in_caps: ds3d/datamap
custom_lib_path: libnvds_3d_gl_datarender.so

通用部分的配置主体

libnvds_3d_gl_datarender config_body 通用字段#

属性

含义

类型和范围

示例

title

指定窗口标题

字符串

title: ds3d-point-cloud-test

streams

指示要渲染的流。深度渲染必须具有 [depth],3D 点渲染必须具有 [points]

List[String],从 [color, depth, points] 中选择

streams: [color, depth]

width

指定窗口宽度

UINT32

width: 1280

height

指定窗口高度

UINT32

height: 720

block

指示渲染线程作为阻塞模式

布尔值

block: True

  • 点云渲染的配置标头

name: point-3D-render
type: ds3d::datarender
in_caps: ds3d/datamap
custom_lib_path: libnvds_3d_gl_datarender.so
custom_create_function: createPointCloudDataRender # specific function for 3D point rendering
  • 激光雷达数据渲染的配置标头

name: lidar-data-render
type: ds3d::datarender
in_caps: ds3d/datamap
custom_lib_path: libnvds_3d_gl_datarender.so
custom_create_function: createLidarDataRender # specific function for Lidar point cloud rendering
  • 3D 点云和激光雷达渲染部分的配置主体

有关 3D 坐标系的更多详细信息,请参阅 https://learnopengl.com/Getting-started/Coordinate-Systems。要了解 view_positionview_targetview_up 的值含义,请参阅 gluLookAthttps://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluLookAt.xml。要了解 nearfarfov 的值含义,请参阅 gluPerspectivehttps://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml

libnvds_3d_gl_datarender 点云渲染 config_body 字段#

属性

含义

类型和范围

示例

view_position

指定视图位置 [x, y, z] 坐标

List[Float]

view_position: [0, 0, -1]

view_target

指定视图目标 [x, y, z] 坐标

List[Float]

view_target: [0, 0, 1]

view_up

指定视图向上方向 [x, y, z] 坐标

List[Float]

view_up: [0, -1.0, 0]

near

指定透视投影近平面

浮点数

near: 0.01

far

指定透视投影远平面

浮点数

far: 10.0

fov

指定透视投影视场,角度

浮点数

fov: 40.0

coord_y_opposite

指定纹理贴图 V 方向,Realsense 坐标与 GLES 默认坐标不同

布尔值

coord_y_opposite: False

positive_z_only

指定是否显示负深度值

布尔值

positive_z_only: False

  • 激光雷达渲染特定部分的配置主体

libnvds_3d_gl_datarender 激光雷达渲染额外 config_body 字段#

属性

含义

类型和范围

示例

view_position

指定视图位置 [x, y, z] 坐标

List[Float]

view_position: [0, 0, -1]

view_target

指定视图目标 [x, y, z] 坐标

List[Float]

view_target: [0, 0, 1]

view_up

指定视图向上方向 [x, y, z] 坐标

List[Float]

view_up: [0, -1.0, 0]

near

指定透视投影近平面

浮点数

near: 0.01

far

指定透视投影远平面

浮点数

far: 10.0

fov

指定透视投影视场,角度

浮点数

fov: 40.0

lidar_color

指定用于显示的激光雷达数据颜色

List[Uint32]

lidar_color: [0, 255, 0]

element_size

指定激光雷达数据元素大小。例如,XYZI 为 4,XYZ 为 3

Uint32

element_size: 4

lidar_data_key

指定 datamap 中的激光雷达数据帧,默认值为 DS3D::LidarXYZI

字符串

lidar_data_key: DS3D::LidarXYZI

lidar_bbox_key

指定 datamap 中的激光雷达 3D 边界框数据,默认值为 DS3D::Lidar3DBboxRawData

字符串

lidar_bbox_key: DS3D::Lidar3DBboxRawData

  • 深度和彩色 2D 渲染的配置标头

name: depth-2D-render
type: ds3d::datarender
in_caps: ds3d/datamap
custom_lib_path: libnvds_3d_gl_datarender.so
custom_create_function: createDepthStreamDataRender # specific function for 2D depth rendering
  • 深度和彩色 2D 特定部分的配置主体

libnvds_3d_gl_datarender 2D 深度渲染 config_body 字段#

属性

含义

类型和范围

示例

min_depth

指定最小深度值。小于此值的其他值将在渲染中移除

浮点数

min_depth: 0.3

max_depth

指定最大深度值。小于此值的其他值将在渲染中移除

浮点数

max_depth: 2.0

min_depth_color

指定最小深度渲染颜色,格式为 [R, G, B]

List[Uint32]

min_depth_color: [255, 128, 0]

max_depth_color

指定最大深度渲染颜色,格式为 [R, G, B]

浮点数

max_depth_color: [0, 128, 255]

libnvds_3d_depth_datasource 深度文件源特定配置规范#

配置标头

name: depthfilesource
type: ds3d::dataloader
out_caps: ds3d/datamap, framerate=30/1
custom_lib_path: libnvds_3d_depth_datasource.so
custom_create_function: createDepthColorLoader

配置主体

libnvds_3d_depth_datasource 深度文件源 config_body 字段#

属性

含义

类型和范围

示例

depth_source

指定深度源的文件路径

字符串

depth_source: depth_uint16_640x480.bin

color_source

指定彩色图像源的文件路径

字符串

color_source: color_rgba_1920x1080.bin

depth_scale

指示每个深度值的深度单位,单位为米

浮点数

depth_scale: 0.0010

depth_datatype

指示深度数据类型,此版本仅支持 [uint16]

字符串,值必须为 uint16

depth_datatype: uint16

depth_size

指示深度分辨率,格式为 [宽度, 高度]

List[Uint32],必须为 [宽度, 高度]

depth_size: [640, 480]

color

指示颜色格式。仅支持 rgba

字符串。值必须为 rgba

color: rgba

color_size

指示颜色分辨率,格式为 [宽度, 高度]

List[Uint32],必须为 [宽度, 高度]

color_size: [1920, 1080]

depth_intrinsic

指示深度传感器内参参数组

内参配置组

depth_intrinsic

width: 848 height: 480 centerX: 424.06073 centerY: 237.75032 fx: 422.513062 fy: 422.513062

color_intrinsic

指示彩色传感器内参参数组

内参配置组

color_intrinsic

width: 1920 height: 1080 centerX: 964.288086 centerY: 533.287354 fx: 1358.21423 fy: 1358.2533

depth_to_color_extrinsic

指示从深度传感器到彩色传感器的外参参数

外参配置组

depth_to_color_extrinsic

rotation: [1, -0.0068, 0.0010, 0.0068, 1, 0, -0.0010, 0, 1] translation: [0.01481, -0.0001, 0.0002]

内参参数的配置主体

libnvds_3d_depth_datasource 深度文件源中的内参参数 config_body 字段#

属性

含义

类型和范围

示例

width

指定传感器宽度,单位为像素

Uint32

width: 848

height

指定传感器高度,单位为像素

Uint32

height: 480

centerX

指定水平方向的坐标轴位置,单位为像素

浮点数

centerX: 424.06

centerY

指定垂直方向的坐标轴位置,单位为像素

浮点数

centerY: 533.28

fx

指定 X 方向的焦距,单位为像素

浮点数

fx: 1358.21

fy

指定 Y 方向的焦距,单位为像素

浮点数

fy: 1358.25

外参参数的配置主体

libnvds_3d_depth_datasource 深度文件源中的外参参数 config_body 字段#

属性

含义

类型和范围

示例

rotation

指定用于旋转的外参 3x3 矩阵。值采用列优先顺序

List[Float],值采用列优先顺序

rotation: [1, -0.0068, 0.0010, 0.0068, 1, 0, -0.0010, 0, 1]

translation

指定用于平移的外参 3x1 矩阵。值采用列优先顺序

List[Float],值采用列优先顺序

translation: [0.01481, -0.0001, 0.0002]