Python 示例应用和绑定源码详情#

示例应用程序源码详情#

下表显示了 Python 示例应用程序在 NVIDIA-AI-IOT/deepstream_python_apps 下的位置。

Python 示例应用程序源码详情#

参考测试应用程序

GitHub 仓库内的路径

描述

简单测试应用程序 1

apps/­deepstream-test1

如何为单个 H.264 流使用 DeepStream 元素的简单示例:filesrc → decode → nvstreammux → nvinfer (主要检测器) → nvdsosd → renderer。

简单测试应用程序 2

apps/­deepstream-test2

如何为单个 H.264 流使用 DeepStream 元素的简单示例:filesrc → decode → nvstreammux → nvinfer (主要检测器) → nvtracker → nvinfer (二级分类器) → nvdsosd → renderer。

简单测试应用程序 3

apps/­deepstream-test3

基于 deepstream-test1(简单测试应用程序 1)构建,演示如何

  • 在 pipeline 中使用多个源

  • 使用 uridecodebin 接受任何类型的输入 (例如 RTSP/File)、任何 GStreamer 支持的容器格式以及任何编解码器

  • 配置 Gst-nvstreammux 以生成一批帧并在其上进行推理,以获得更好的资源利用率

  • 提取流元数据,其中包含有关批处理缓冲区中帧的有用信息

简单测试应用程序 4

apps/­deepstream-test4

基于 deepstream-test1 构建,用于单个 H.264 流:filesrc、decode、nvstreammux、nvinfer、nvdsosd、renderer,以演示如何

  • 在 pipeline 中使用 Gst-nvmsgconv 和 Gst-nvmsgbroker 插件

  • 创建 NVDS_META_EVENT_MSG 类型元数据并将其附加到缓冲区

  • 将 NVDS_META_EVENT_MSG 用于不同类型的对象,例如车辆和人

  • 如果通过 extMsg 字段扩展元数据,则实现“copy”和“free”函数以供使用

USB 摄像头源应用程序

apps/­deepstream-test1-usbcam

修改后的简单测试应用程序 1,用于处理来自 USB 摄像头的单个流。

RTSP 输出应用程序

apps/­deepstream-test1-rtsp-out

修改后的简单测试应用程序 1,用于通过 RTSP 输出可视化流。

图像数据访问应用程序

apps/­deepstream-imagedata-multistream

基于简单测试应用程序 3 构建,演示如何

  • 在 pipeline 中将解码帧作为 NumPy 数组访问

  • 检查检测到的对象的检测置信度(需要 DBSCAN 或 NMS 聚类)

  • 修改帧并查看 pipeline 中下游反映的更改

  • 使用 OpenCV 注释帧并将它们保存到文件

SSD 检测器输出解析器应用程序

apps/­deepstream-ssd-parser

演示如何为来自 Triton Inference Server 的推理输出执行自定义后处理

  • 在 Triton Inference Server 上使用 SSD 模型进行对象检测

  • 通过配置文件设置启用 Triton Inference Server 的自定义后处理和原始张量导出

  • 在 pipeline 中访问推理输出张量,以便在 Python 中进行后处理

  • 将检测到的对象添加到元数据

  • 将 OSD 可视化输出到 MP4 文件

光流应用程序

apps/deepstream-opticalflow

演示如何获取光流元数据,并演示如何

  • 将光流向量作为 numpy 数组访问

  • 使用获取的流向量和 OpenCV 可视化光流

分割应用程序

apps/deepstream-segmentation

演示如何获取分割元数据,并演示如何

  • 访问分割掩码作为 numpy 数组

  • 使用获取的掩码和 OpenCV 可视化分割

分析应用程序

apps/deepstream-nvdsanalytics

演示如何使用 nvdsanalytics 插件并获取分析元数据

运行时源添加/删除应用程序

apps/runtime_source_add_delete

演示如何在运行时添加和删除输入源

面部编辑应用程序

apps/deepstream-imagedata-multistream-redaction

演示如何访问图像数据并执行面部编辑

RTSP 输入/输出应用程序

apps/deepstream-rtsp-in-rtsp-out

具有 RTSP 输入和输出的多流 pipeline

预处理应用程序

apps/deepstream-preprocess-test

演示如何使用 nvdspreprocess 插件并在提供的 ROI 上执行自定义预处理

解复用器应用程序

apps/deepstream-demux-multi-in-multi-out

基于 deepstream-test3 构建,演示如何使用 nvstreamdemux 插件来拆分批次并输出单独的缓冲区/流。

CuPy 应用程序

apps/deepstream-imagedata-multistream-cupy

演示如何在多流源中将 GPU 缓冲区作为 CuPy 数组访问,并在适当位置修改图像。

Segmask 应用程序

apps/deepstream-segmask

演示如何从流元数据中提取 NvOSD_MaskParams,以及如何调整大小和二值化掩码数组以获得可解释的分割掩码。

自定义绑定应用程序

apps/deepstream-custom-binding-test

演示如何使用 NvDsUserMeta 将 Python 绑定中编写的自定义数据结构附加到缓冲区/从缓冲区中提取。

Python 绑定和应用程序开发#

本节提供有关在 Python 中进行 DeepStream 应用程序开发的详细信息。Python 绑定在此处可用: NVIDIA-AI-IOT/deepstream_python_apps 。在此处阅读有关 Pyds API 的更多信息 here

先决条件#

  • Ubuntu 22.04

  • DeepStream SDK 7.0 或更高版本

  • Python 3.10

  • Gst Python v1.20.3

如果 Jetson 上缺少 Gst python 安装,请按照 bindings readme 中的说明进行操作。

运行示例应用程序#

  1. 克隆 deepstream_python_apps 仓库到 <DeepStream ROOT>/sources

    git clone https://github.com/NVIDIA-AI-IOT/deepstream_python_apps
    
  2. 这将创建以下目录

    <DeepStream ROOT>/sources/deepstream_python_apps
    
  3. Python 应用程序位于 apps 目录下。进入每个应用程序目录并按照 README 中的说明进行操作。

    注意

    应用程序配置文件包含模型的相对路径。

Pipeline 构建#

DeepStream pipeline 可以使用 Gst Python(GStreamer 框架的 Python 绑定)构建。请参阅示例应用程序主函数以获取 pipeline 构建示例。

元数据访问#

DeepStream 元数据包含推理结果和分析中使用的其他信息。元数据附加到每个 pipeline 组件接收的 Gst Buffer。SDK 元数据文档和 API 指南中详细描述了元数据格式。SDK 元数据库是在 C/C++ 中开发的。Python 绑定提供从 Python 应用程序访问元数据的功能。请在 NVIDIA-AI-IOT/deepstream_python_apps 中查找 Python 绑定源码和软件包。

内存管理#

元数据的内存由 Python 和 C/C++ 代码路径共享。例如,元数据项可以由 Python 中编写的 probe 函数添加,并且需要由 C/C++ 中编写的下游插件访问。deepstream-test4 应用程序包含此类用法。Python 垃圾回收器无法查看 C/C++ 中的内存引用,因此无法安全地管理此类共享内存的生命周期。由于这种复杂性,Python 对元数据内存的访问通常通过引用来实现,而不声明所有权。

分配#

当在 Python 中分配元数据对象时,绑定提供分配函数以确保对象的正确内存所有权。如果使用构造函数,则当其 Python 引用终止时,该对象将被垃圾回收器回收。但是,下游的 C/C++ 代码仍然需要访问该对象,因此该对象必须在这些 Python 引用之外持续存在。示例:要分配 NvDsEventMsgMeta 实例,请使用此

msg_meta = pyds.alloc_nvds_event_msg_meta() *# get reference to allocated instance without claiming memory ownership*

而不是此

msg_meta = NvDsEventMsgMeta() *# memory will be freed by the garbage collector when msg_meta goes out of scope in Python*

分配器可用于以下结构

  • NvDsVehicleObject: alloc_nvds_vehicle_object()

  • NvDsPersonObject: alloc_nvds_person_object()

  • NvDsFaceObject: alloc_nvds_face_object()

  • NvDsEventMsgMeta: alloc_nvds_event_msg_meta()

  • NvDsEvent: alloc_nvds_event()

  • NvDsPayload: alloc_nvds_payload()

  • 通用 buffer: alloc_buffer(size)

字符串访问#

某些元数据结构包含字符串字段。以下部分提供有关访问它们的详细信息。

设置字符串字段#

设置字符串字段会导致在底层 C++ 代码中分配字符串缓冲区。

obj.type = "Type"

这将导致分配内存缓冲区,并将字符串“TYPE”复制到其中。此内存归 C 代码所有,稍后将被释放。要在 Python 代码中释放缓冲区,请使用

pyds.free_buffer(obj.type)

注意

NvOSD_TextParams.display_text 字符串现在在分配新字符串时自动释放。

读取字符串字段#

直接读取字符串字段会以 int 形式返回字段的 C 地址,例如

obj = pyds.NvDsVehicleObject.cast(data);
print(obj.type)

这将打印一个 int,表示 C 中 obj.type 的地址(它是 char*)。要检索此字段的字符串值,请使用 pyds.get_string(),例如

print(pyds.get_string(obj.type))

类型转换#

某些元数据实例以 GList 形式存储。要访问 GList 节点中的数据,需要将数据字段强制转换为适当的结构。此强制转换通过目标类型的 cast() 成员函数完成

NvDsBatchMeta.cast
NvDsFrameMeta.cast
NvDsObjectMeta.cast
NvDsUserMeta.cast
NvDsClassifierMeta.cast
NvDsDisplayMeta.cast
NvDsLabelInfo.cast
NvDsEventMsgMeta.cast
NvDsVehicleObject.cast
NvDsPersonObject.cast

在 v0.5 版本中,提供了独立的 cast 函数。这些函数现在已弃用,并被上面的 cast() 函数取代

glist_get_nvds_batch_meta
glist_get_nvds_frame_meta
glist_get_nvds_object_meta
glist_get_nvds_user_meta
glist_get_nvds_classifier_meta
glist_get_nvds_display_meta
glist_get_nvds_label_info
glist_get_nvds_event_msg_meta
glist_get_nvds_vehicle_object
glist_get_nvds_person_object

示例

l_frame = batch_meta.frame_meta_list
frame_meta = pyds.NvDsFrameMeta.cast(l_frame.data)

回调函数注册#

添加到 NvDsUserMeta 的自定义元数据需要自定义复制和释放函数。元数据库依赖于这些自定义函数来执行自定义结构的深层复制,并释放已分配的资源。这些函数在 NvDsUserMeta 结构中注册为回调函数指针。回调函数使用以下函数注册

pyds.set_user_copyfunc(NvDsUserMeta_instance, copy_function)
pyds.set_user_releasefunc(NvDsUserMeta_instance, free_func)

注意

在应用程序退出之前,需要使用 bindings 库取消注册回调。bindings 库当前保留对已注册函数的全局引用,并且这些引用不能在 bindings 库卸载之后持续存在,而 bindings 库卸载发生在应用程序退出时。使用以下函数取消注册所有回调

pyds.unset_callback_funcs()

有关回调注册和注销的示例,请参阅 deepstream-test4 示例应用程序。

限制:bindings 库目前仅支持每个应用程序的一组回调函数。将使用最后注册的函数。

优化和实用程序#

Python 解释通常比运行编译后的 C/C++ 代码慢。为了提供更好的性能,某些操作在 C 中实现,并通过 bindings 接口公开。这目前是实验性的,并且会随着时间的推移而扩展。以下优化函数可用

  • pyds.NvOSD_ColorParams.set(double red, double green, double blue, double alpha)

    这是一个简单的函数,其执行的操作与以下操作相同

    txt_params.text_bg_clr.red = red
    txt_params.text_bg_clr.green = green
    txt_params.text_bg_clr.blue = blue
    txt_params.text_bg_clr.alpha = alpha
    

    这些操作在 deepstream_test_4.py 中的每个对象上执行,导致聚合处理时间减慢 pipeline 的速度。将此函数推送到 C 层有助于提高性能。

  • generate_ts_rfc3339 (buffer, buffer_size)

    此函数使用根据 RFC3339 生成的时间戳填充输入缓冲区:%Y-%m-%dT%H:%M:%S.nnnZ\0

图像数据访问#

解码后的图像可以通过 get_nvds_buf_surface 函数作为 NumPy 数组访问。此函数在 API 指南中记录。有关图像数据用法的示例,请参阅 deepstream-imagedata-multistream 示例应用程序。