Skip to main content
Qualcomm® 智能多媒体 (IM) SDK 是一组 GStreamer 插件,可让您在 Dragonwing 开发板的 GPU 上运行计算机视觉操作;并可以创建完全运行在 GPU 和 NPU 上的 AI 流水线,而无需回到 CPU(零拷贝)。综合来看,这使您能够获得比自己用 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. 现在运行此应用程序:
    OK!模型现在在 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 错误:
可以通过运行以下命令释放摄像头: