Skip to main content
Qualcomm® Intelligent Multimedia (IM) SDK 是一组 GStreamer 插件,可让您在 Dragonwing 开发板的 GPU 上运行计算机视觉操作;并且可以创建完全在 GPU 和 NPU 上运行、无需回到 CPU 的 AI 流水线(零拷贝)。这些特性结合在一起,使您可以实现比自己用 OpenCV + TFLite 等实现 AI 计算机视觉流水线高得多的吞吐率。

那么……GStreamer 流水线是什么?

IM SDK 构建在 GStreamer 之上。GStreamer 是一个多媒体框架,让您描述视频或音频的处理流水线,并负责按顺序运行每个步骤。在”普通 Python”中,您可能会编写 OpenCV 代码:从网络摄像头抓取一帧、调整大小和裁剪、调用推理函数、在结果上绘制边界框,然后再次输出或显示该帧——除非您自己显式接入 GPU/NPU API,否则每一步都在 CPU 上运行。使用 GStreamer + IM SDK,您可以在一个流水线字符串中声明相同的处理序列,框架会为您将帧流式传输通过整条处理链。 IM SDK 在 Qualcomm 硬件上增加的能力是让这些步骤可以被透明加速:调整大小/裁剪和绘制边界框可以在 GPU 上运行,推理可以在 NPU 上运行,整条操作链(例如裁剪 → 调整大小 → 神经网络推理)可以在从不回到 CPU 的情况下执行(零拷贝)。在您的应用程序中,您只需配置流水线;底层框架负责逐帧调度、同步和加速器卸载。 IM SDK 提供了使这一切成为可能的专用 GStreamer 插件。例如,qtivtransform 将颜色转换、裁剪和调整大小卸载到 GPU,而 qtimltflite 负责在 NPU 上进行推理。这样,您用标准 GStreamer 编写的同样的高级流水线现在几乎可以完全在专用加速器上运行,以最小的 CPU 负载实现实时吞吐。

设置 GStreamer 和 IM SDK

好的,让我们开始使用 IM SDK 构建一些应用程序。
  1. 安装 GStreamer、IM SDK 以及本示例中需要的一些额外依赖项。打开开发板上的终端,或与开发板建立 SSH 会话,然后运行:
  2. 获取 python 示例,解压后创建 venv,并安装其依赖项:
  3. 您需要一个摄像头(内置摄像头,如 RB3 Gen 2 Vision Kit 上的,或 USB 网络摄像头)。
    • 如果您想使用 USB 网络摄像头:
      1. 找出设备 ID:
      2. 设置环境变量(我们将在示例中使用它):
    • 如果您使用的是 RB3 Gen 2 Vision Kit 并想使用内置摄像头:

示例 1:在 GPU 与 CPU 上进行调整大小和裁剪

让我们展示在 GPU 上处理相比 CPU 能快多少。如果您有一个需要 224x224 RGB 输入的神经网络,则需要预处理数据:首先,从网络摄像头抓取帧(例如原生分辨率为 1980x1080),然后裁剪为 1/1 宽高比(例如裁剪为 1080x1080),再调整为所需分辨率(224x224),最后由像素创建一个 Numpy 数组。
  1. 创建一个新文件 ex1.py,并添加:
  2. 启动这个 python 脚本。此流水线在 CPU 上运行(使用原生 GStreamer 组件):
    可以看到调整大小/裁剪需要 22ms(在 IQ9 上使用 USB 摄像头测得)。
  3. 现在让我们改为在 GPU 上运行……将:
    替换为:
    以下是完整文件 ex1_imsdk.py
  4. 再次运行:
    🚀 您现在只用两行代码就将裁剪/调整大小操作从约 22ms 加速到了约 6ms!

示例 2:分流(Tee)与多路输出

在上面的流水线中,您已经看到了一些与您自己的代码交互时会用到的元素:
  • Identity 元素(例如 identity name=frame_ready_webcam silent=false)。这些可用于调试流水线中的时序。它们被触发时的时间戳会被保存,并在流水线结束时通过 marks 元素返回(键值对,键为 identity 名称,值为时间戳)。
  • Appsink 元素(例如 appsink name=frame)。这些用于将数据从 GStreamer 流水线发送到您的应用程序。这里 appsink 之前的元素是 video/x-raw,format=RGB,width=224,height=224——所以我们会向 Python 发送一个 224x224 的 RGB 数组。您会在 frames_by_sink 元素中收到这些数据(键值对,键为 appsink 名称,值为数据)。
每个流水线可以有多个 appsink。例如,您可能还想获取原始的 1920x1080 图像。在这种情况下,您可以在 identity name=frame_ready_webcam 之后将流水线分成两部分:一部分发送到新的 appsink,另一部分通过调整大小/裁剪流水线。
  1. 创建一个新文件 ex2.py 并添加:
  2. 运行此 python 脚本:
    out/ 目录包含最后处理的帧,包括原始分辨率和调整大小后的分辨率)
好了!这样您就从单个流水线得到了两个输出。现在您知道如何在单个流水线中构建更复杂的应用程序了。

示例 3:运行神经网络

现在我们已经能以正确的分辨率从网络摄像头流式获取图像,让我们加入神经网络。
以下工作流仅适用于 Ubuntu Server 版本,不适用于 Ubuntu Desktop 操作系统。

3.1:在 Python 中运行神经网络和图像合成

  1. 首先我们做一个”常规”实现:从 IM SDK 流水线获取调整大小后的帧,然后使用 LiteRT 运行模型(在 NPU 上)。之后,我们将在图像上绘制最高置信度的预测并写入磁盘。创建一个新文件 ex3_from_python.py 并添加:
  2. 现在运行此应用程序:

    带叠加层的图像分类模型

    相当不错,但让我们看看能否做得更好……

3.2:使用 IM SDK 运行神经网络

让我们将神经网络推理转移到 IM SDK 中。您可以通过三个插件来实现:
  • qtimlvconverter——将帧转换为输入张量。
  • qtimltflite——运行神经网络(LiteRT 格式)。如果您通过 appsink 发送这些结果,您会得到与之前完全相同的张量(只是不再需要经过 CPU 来调用推理引擎)。
  • 类似 qtimlpostprocess 的元素来解释输出。这里该插件适用于输出形状为 (1, n) 的图像分类用例(如我们使用的 SqueezeNet 模型)。该插件输出文本(包含预测结果)或叠加层(用于绘制到原始图像上)。
注意: 该元素有特定的标签格式(见下文)。
  1. 创建一个新文件 ex3_nn_imsdk.py 并添加:
NV12: 我们在这里(qtivtransform 之后)将 RGB 格式切换为 NV12 格式,因为 qtimltflite 需要紧凑排列的缓冲区——而 RGB 输出使用行跨距(row-stride)填充。这些问题可能非常难调试。在命令前添加 GST_DEBUG=3(例如 GST_DEBUG=3 python3 ex3_nn_imsdk.py),并将流水线和错误信息输入 ChatGPT 等 LLM,有时可以帮助您排查问题。 module=mobilenet-softmax: qtimlpostprocess 将其用于输出为 FLOAT32 1×N logits 向量的分类模型。它应用 Softmax 将 logits 归一化为概率。
  1. 现在运行此应用程序:
    好!模型现在在 IM SDK 流水线内部的 NPU 上运行。如果您想获得前 5 个输出(就像 3.1 中那样),可以在 qtimltflite 元素之后对流进行 tee 分流,并将原始输出张量也发送回应用程序。

3.3:叠加层

为了模拟 3.1 中的输出,我们还需要绘制一个叠加层。先用一个静态叠加图像来演示。
  1. 下载一张半透明图像(来源):
  2. 创建一个新文件 ex3_overlay.py 并添加:
  3. 运行此应用程序:

    在网络摄像头图像上叠加静态图层

3.4:将神经网络与叠加层结合

您现在已经了解了如何在 IM SDK 流水线中运行神经网络,也了解了如何绘制叠加层。让我们将它们合并到一个流水线中,把预测结果叠加到图像上——全程无需经过 CPU。
  1. 创建一个新文件 ex3_from_imsdk.py 并添加:
  2. 运行此应用程序:
    太棒了!整条流水线现在都在 IM SDK 中运行。您可以在 out/imsdk-webcam-nn-overlay.mp4 中找到输出文件。

    由 IM SDK 渲染叠加层的图像分类模型

故障排除

流水线没有任何输出

如果您没有看到任何输出,添加 GST_DEBUG=3 以查看更详细的调试信息。

QMMF Recorder StartCamera Failed / Failed to Open Camera

如果您看到类似以下的 QMMF 错误:
您可以通过运行以下命令释放摄像头: