> ## Documentation Index
> Fetch the complete documentation index at: https://dragonwingdocs.qualcomm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# qtiobjtracker

> 实时多目标跟踪插件

# 概述

`qtiobjtracker` 是一个 GStreamer 插件，通过在连续视频帧之间关联检测到的目标，并为每个目标分配持久的**跟踪 ID**，提供**实时多目标跟踪**功能。

该插件基于上游推理或后处理元素产生的目标检测元数据运行。对于每个检测到的目标，它分析跨帧的时间连续性，并使用跟踪信息更新元数据，从而使同一目标能够随时间被一致地识别。

### 主要职责

`qtiobjtracker` 的主要目的是：

* 使用持久的跟踪 ID 在帧间保持稳定的目标身份
* 基于检测结果随时间跟踪目标运动
* 提高目标级分析的时间一致性
* 使下游组件能够执行更高级的视频分析、事件处理和行为分析。

`qtiobjtracker` 本身**不**执行目标检测。它依赖上游管道元素生成目标检测结果及相关元数据。跟踪器消费这些元数据，执行帧到帧的关联，并为目标元数据添加跟踪 ID 供下游使用。

<img src="https://mintlify.s3.us-west-1.amazonaws.com/qualcomm-prod/zh/SDKs/IMSDK/plugin-reference/images/qtiobj1.png" alt="" />

## 示例管道

<Steps>
  <Step title="下载所需文件">
    | 文件            | 下载                                                                                                                           | 保存为                         |
    | ------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------------------- |
    | YOLOX W8A8 模型 | [Qualcomm AI Hub — YOLOX](https://aihub.qualcomm.com/iot/models/yolox)                                                       | `yolo_x_w8a8.tflite`        |
    | 检测标签          | <a href="/SDKs/IMSDK/labels/yolov8.json" download="yolov8.json">yolov8.json</a>                                              | `yolov8.json`               |
    | 示例视频          | <a href="https://github.com/qualcomm/sample-apps-for-qualcomm-linux/raw/refs/heads/main/artifacts/videos/video.mp4">输入视频</a> | `Draw_1080p_180s_30FPS.mp4` |

    <Note>
      如果下载的任何文件是 `.zip` 压缩包，请在复制前先在主机上解压：
      `unzip filename.zip`
    </Note>
  </Step>

  <Step title="将文件复制到设备">
    <CodeGroup>
      ```bash SCP (SSH) theme={null}
      # Replace $HOME to the appropriate device path before running the commands.
      # For QLI:    /root
      # For Ubuntu: /home/ubuntu
      # Modify this based on your platform and ensure files are copied to the correct location on the device.
      # Run from your host machine — replace <user> and <device-ip>

      ssh <user>@<device-ip> "mkdir -p $HOME/{models,labels,media,media/output}"
      scp yolo_x_w8a8.tflite           <user>@<device-ip>:$HOME/models/
      scp yolov8.json                  <user>@<device-ip>:$HOME/labels/
      scp Draw_1080p_180s_30FPS.mp4    <user>@<device-ip>:$HOME/media/
      ```
    </CodeGroup>
  </Step>

  <Step title="连接到设备">
    <CodeGroup>
      ```bash SCP (SSH) theme={null}
      # Run from your host machine — replace <user> and <device-ip>
      ssh <user>@<device-ip>
      ```
    </CodeGroup>
  </Step>

  <Step title="设置环境变量">
    在设备上运行以下命令

    ```bash theme={null}
    export MODEL_NAME=yolo_x_w8a8.tflite
    export LABELS_NAME=yolov8.json
    export SRC_VIDEO_NAME=Draw_1080p_180s_30FPS.mp4
    ```
  </Step>

  <Step title="运行管道">
    ```bash theme={null}
    gst-launch-1.0 -e --gst-debug=2 \
    filesrc location=$HOME/media/$SRC_VIDEO_NAME ! qtdemux ! h264parse ! \
    v4l2h264dec capture-io-mode=4 output-io-mode=4 ! video/x-raw,format=NV12 ! queue ! \
    tee name=t ! qtimetamux name=obj_mux ! qtivoverlay ! waylandsink fullscreen=true sync=false \
    t. ! queue ! qtimlvconverter ! queue ! \
    qtimltflite model=$HOME/models/$MODEL_NAME delegate=external external-delegate-path=libQnnTFLiteDelegate.so \
      external-delegate-options="QNNExternalDelegate,backend_type=htp,log_level=(string)1;" ! queue ! \
    qtimlpostprocess module=yolov8 labels=$HOME/labels/$LABELS_NAME \
      settings="{\"confidence\": 51.0}" ! text/x-raw ! queue ! obj_mux.
    ```
  </Step>
</Steps>

# 层级结构

[GObject](https://docs.gtk.org/gobject/)<br />
   <Icon icon="arrow-turn-down-right" iconType="solid" />[GstObject](https://gstreamer.freedesktop.org/documentation/gstreamer/gstobject.html?gi-language=c)<br />
      <Icon icon="arrow-turn-down-right" iconType="solid" />[GstElement](https://gstreamer.freedesktop.org/documentation/gstreamer/gstelement.html?gi-language=c)<br />
         <Icon icon="arrow-turn-down-right" iconType="solid" />qtiobjtracker

# Pad 模板

### sink

| 能力            |                |
| ------------- | -------------- |
| `video/x-raw` | `format: ANY`  |
| `text/x-raw`  | `format: utf8` |
| 可用性：*Always*  |                |
| 方向：*sink*     |                |

### src

| 能力            |                |
| ------------- | -------------- |
| `video/x-raw` | `format: ANY`  |
| `text/x-raw`  | `format: utf8` |
| 可用性：*Always*  |                |
| 方向：*source*   |                |

# 元素属性

| 属性           | 描述                                                                                                                                                                                                |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `algo`       | 用于目标跟踪器的算法名称。<br /><br />`Type: Enum` <br />`Default: 0, "bytetrack"`<br />`Flags: readable/writable (changeable in NULL, READY, PAUSED, PLAYING)` <br /> `Example: algo="bytetrack" (or) algo=0` |
| `parameters` | 所选目标跟踪算法使用的参数，采用 GstStructure 字符串格式。仅适用于部分算法。<br /><br />`Type: String`<br />`Default: NULL`<br />`Flags: readable/writable`                                                                      |

# 内部架构详情

### 可插拔跟踪后端架构

`qtiobjtracker` 采用模块化跟踪架构设计，将 GStreamer 插件框架与底层跟踪算法实现分离。该插件公开一个通用的跟踪接口，同时允许不同的跟踪算法独立于核心元素进行实现、选择和维护。

每种跟踪算法被打包为单独的共享库，称为**跟踪后端**。`qtiobjtracker` 元素负责：

* 管理 GStreamer 元素生命周期
* 与管道集成
* 接收和转发检测元数据
* 加载所选的跟踪后端并与之交互

跟踪逻辑本身完全在后端库中实现。

**运行时算法选择**

跟踪算法通过 `algo` 属性在运行时选择。`qtiobjtracker` 根据配置的值动态加载相应的后端库并初始化所选的实现。

这种设计提供了以下优势：

* **运行时灵活性** — 可以针对每个管道或用例选择跟踪行为
* **关注点分离** — 算法实现与插件核心保持独立
* **可维护性** — 跟踪后端可以独立开发和更新
* **可扩展性** — 可以在不更改公共插件接口的情况下添加新的跟踪算法

只有与所选算法关联的后端会被加载和执行。

**后端职责**

每个跟踪后端实现一个通用接口，并负责：

* 在连续帧之间关联检测结果
* 创建、更新和终止跟踪轨迹
* 应用运动预测和/或空间匹配
* 维护内部跟踪状态

后端仅基于检测元数据（如边界框、类别标签和置信度分数）运行。它们不执行目标检测。

基于后端的架构使 `qtiobjtracker` 能够在一致的插件接口内支持多种跟踪策略。这使得针对不同工作负载调整跟踪行为、评估替代算法以及针对特定硬件或应用需求优化实现变得更加容易。

### 输入和输出格式

`qtiobjtracker` 完全基于目标检测元数据及相关坐标运行。它不检查、分析或修改视频帧的像素数据。跟踪决策仅基于从上游元素接收的检测元数据。

因此，`qtiobjtracker` 必须放置在一个或多个生成目标检测并附加相应元数据的元素的下游。

### 支持的检测元数据格式

`qtiobjtracker` 支持两种检测目标的输入格式。两者在基于 GStreamer 的 AI 管道中都很常用。

**1. 结构化文本元数据（`text/x-raw`）**

在此模式下，检测结果作为结构化文本数据与视频缓冲区分开传输。

* 缓冲区 caps：`text/x-raw`
* 检测结果存储在缓冲区负载中
* 负载包含检测目标的结构化描述
* 文本表示可以与 `GstStructure` 相互转换
* 边界框坐标在 `[0.0, 1.0]` 范围内归一化
* 坐标与分辨率无关

这种格式允许在不同分辨率的流（包括缩放或调整大小的视频分支）之间复用相同的检测数据。

**2. 视频缓冲区上的 ROI 元数据（`GstROIMeta`）**

在此模式下，检测结果作为 ROI 元数据直接附加到视频缓冲区。

* 检测结果以 `GstROIMeta` 元数据的形式附加到原始视频缓冲区
* 每个 ROI 条目代表一个检测到的目标
* 边界框坐标以视频帧的坐标空间表示（绝对坐标，与分辨率相关）

# 跟踪行为与格式处理

`qtiobjtracker` 与底层视频内容无关，仅依赖检测元数据进行跟踪。它同时支持结构化文本元数据和 ROI 元数据，无需在两种格式之间转换。

该插件在整个处理过程中保留输入元数据的表示形式。输出格式始终与输入格式一致：

* 如果输入是 `text/x-raw`，输出仍为 `text/x-raw`
* 如果输入使用 `GstROI` 元数据，输出仍为附加到同一视频缓冲区的 ROI 元数据

`qtiobjtracker` 不会在基于文本的元数据和基于 ROI 的元数据之间进行转换。

### 输出跟踪信息

`qtiobjtracker` 保留所有输入检测元数据，并为每个检测到的目标添加一个跟踪属性：

* **唯一跟踪 ID（Unique Track ID）** — 用于在连续帧之间关联同一目标的持久标识符。

所有现有的检测属性，包括边界框、类别标签、置信度分数和坐标表示，都会原样传递。该插件不会修改或扩展任何其他目标属性。

输出元数据格式始终与输入格式一致。如果检测以 `text/x-raw` 形式接收，跟踪结果以相同格式输出。如果检测以视频缓冲区上的 ROI 元数据形式提供，更新后的跟踪信息将附加到相同的元数据表示中。

# 用法

### 为每个检测到的目标附加跟踪 ID

此示例演示了对实时摄像头流上运行的 AI 推理管道所检测目标的实时跟踪。推理结果以 `MLMeta` 形式附加到每个 `GstBuffer`，随后 `qtiobjtracker` 跨帧跟踪检测到的目标，并将持久的跟踪 ID 添加到元数据中。包含跟踪信息的最终 AI 元数据随后使用 [`qtimlmetaparser`](qtimetaparser) 序列化为 JSON，并通过 [`qtiredissink`](qtiredissink) 插件发布到 Redis 服务器。

<img src="https://mintlify.s3.us-west-1.amazonaws.com/qualcomm-prod/zh/SDKs/IMSDK/plugin-reference/images/qtiobj3.png" alt="" />

<Steps>
  <Step title="下载所需文件">
    | 文件            | 下载                                                                              | 保存为                 |
    | ------------- | ------------------------------------------------------------------------------- | ------------------- |
    | YOLOX W8A8 模型 | [Qualcomm AI Hub — YOLOX](https://aihub.qualcomm.com/iot/models/yolox)          | `yolox_w8a8.tflite` |
    | 检测标签          | <a href="/SDKs/IMSDK/labels/yolov8.json" download="yolov8.json">yolov8.json</a> | `yolov8.json`       |

    <Note>
      如果下载的任何文件是 `.zip` 压缩包，请在复制前先在主机上解压：
      `unzip filename.zip`
    </Note>
  </Step>

  <Step title="将文件复制到设备">
    <CodeGroup>
      ```bash SCP (SSH) theme={null}
      # Run from your host machine — replace <user> and <device-ip>
      ssh <user>@<device-ip> "mkdir -p $HOME/{models,labels}"
      scp yolox_w8a8.tflite   <user>@<device-ip>:$HOME/models/
      scp yolov8.json         <user>@<device-ip>:$HOME/labels/
      ```
    </CodeGroup>
  </Step>

  <Step title="连接到设备">
    <CodeGroup>
      ```bash SCP (SSH) theme={null}
      # Run from your host machine — replace <user> and <device-ip>
      ssh <user>@<device-ip>
      ```
    </CodeGroup>
  </Step>

  <Step title="设置环境变量">
    在设备上运行以下命令

    ```bash theme={null}
    export MODEL_NAME=yolox_w8a8.tflite
    export LABELS_NAME=yolov8.json
    ```
  </Step>

  <Step title="运行管道">
    ```bash Run the pipeline theme={null}
    gst-launch-1.0 --gst-debug=2 \
    qtimlvconverter name=stage_01_preproc \
    qtimltflite model=$HOME/models/$MODEL_NAME delegate=external external-delegate-path=libQnnTFLiteDelegate.so \
      external-delegate-options="QNNExternalDelegate,backend_type=htp,log_level=(string)1;" name=stage_01_inference \
    qtimlpostprocess name=stage_01_postproc results=10 module=yolov8 labels=$HOME/labels/$LABELS_NAME \
    qticamsrc ! video/x-raw,format=NV12,width=1920,height=1080,framerate=30/1 ! queue ! tee name=t \
    t. ! queue ! metamux. \
    t. ! queue ! stage_01_preproc. stage_01_preproc. ! queue ! stage_01_inference. stage_01_inference. ! queue ! stage_01_postproc. stage_01_postproc. ! text/x-raw ! queue ! metamux. \
    qtimetamux name=metamux ! queue ! qtiobjtracker algo=bytetrack ! queue ! qtimlmetaparser module=json ! queue ! qtiredissink host=127.0.0.1 port=6379 channel=ml_results

    #Listen to the published data with Redis CLI from another shell:
    redis-cli SUBSCRIBE ml_results
    ```
  </Step>
</Steps>

### 附加跟踪 ID 并传播到下一阶段 AI 推理

此示例演示了在实时摄像头流上运行的实时多阶段 AI 管道。第一个推理阶段执行目标检测，并将结果以 `MLMeta` 形式附加到每个 `GstBuffer`。`qtiobjtracker` 随后跨帧关联检测到的目标，并将持久的跟踪 ID 添加到元数据中。视频帧连同增强后的元数据一起被传递到后续的姿态估计阶段进行进一步推理。最后，[`qtimetamux`](qtimetamux) 合并所有阶段的元数据，叠加阶段渲染合并后的结果——包括边界框、跟踪 ID 和估计的姿态——用于实时显示。

<img src="https://mintlify.s3.us-west-1.amazonaws.com/qualcomm-prod/zh/SDKs/IMSDK/plugin-reference/images/qtiobj4.png" alt="" />

<Steps>
  <Step title="下载所需文件">
    | 文件                | 下载                                                                                                                                    | 保存为                            |
    | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ |
    | 人体/足部检测模型         | [Qualcomm AI Hub — Person Foot Detection](https://aihub.qualcomm.com/iot/models/foot_track_net)                                       | `foot_track_net_w8a8.tflite`   |
    | 人体检测标签            | <a href="/SDKs/IMSDK/labels/foot_track_net.json" download="foot_track_net.json">foot\_track\_net.json</a>                             | `foot_track_net.json`          |
    | Foot track net 设置 | <a href="/SDKs/IMSDK/labels/foot_track_net_settings.json" download="foot_track_net_settings.json">foot\_track\_net\_settings.json</a> | `foot_track_net_settings.json` |
    | HRNet 姿态模型        | [Qualcomm AI Hub — HRNet Pose](https://aihub.qualcomm.com/iot/models/hrnet_pose)                                                      | `hrnet_pose_w8a8.tflite`       |
    | 姿态标签              | <a href="/SDKs/IMSDK/labels/hrnet.json" download="hrnet.json">hrnet.json</a>                                                          | `hrnet.json`                   |
    | HRNet 设置          | <a href="/SDKs/IMSDK/labels/hrnet_settings.json" download="hrnet_settings.json">hrnet\_settings.json</a>                              | `hrnet_settings.json`          |

    <Note>
      如果下载的任何文件是 `.zip` 压缩包，请在复制前先在主机上解压：
      `unzip filename.zip`
    </Note>
  </Step>

  <Step title="将文件复制到设备">
    <CodeGroup>
      ```bash SCP (SSH) theme={null}
      # Replace $HOME to the appropriate device path before running the commands.
      # For QLI:    /root
      # For Ubuntu: /home/ubuntu
      # Modify this based on your platform and ensure files are copied to the correct location on the device.
      # Run from your host machine — replace <user> and <device-ip>

      ssh <user>@<device-ip> "mkdir -p $HOME/{models,labels}"
      scp foot_track_net_w8a8.tflite         <user>@<device-ip>:$HOME/models/
      scp foot_track_net.json                <user>@<device-ip>:$HOME/labels/
      scp foot_track_net_settings.json       <user>@<device-ip>:$HOME/labels/
      scp hrnet_pose_w8a8.tflite             <user>@<device-ip>:$HOME/models/
      scp hrnet.json                         <user>@<device-ip>:$HOME/labels/
      scp hrnet_settings.json                <user>@<device-ip>:$HOME/labels/
      ```
    </CodeGroup>
  </Step>

  <Step title="连接到设备">
    <CodeGroup>
      ```bash SCP (SSH) theme={null}
      # Run from your host machine — replace <user> and <device-ip>
      ssh <user>@<device-ip>
      ```
    </CodeGroup>
  </Step>

  <Step title="设置环境变量">
    在设备上运行以下命令

    ```bash theme={null}
    export MODEL_NAME_1=foot_track_net_w8a8.tflite
    export LABELS_NAME_1=foot_track_net.json
    export LABELS_NAME_2=foot_track_net_settings.json
    export MODEL_NAME_2=hrnet_pose_w8a8.tflite
    export LABELS_NAME_3=hrnet.json
    export LABELS_NAME_4=hrnet_settings.json
    ```
  </Step>

  <Step title="运行管道">
    ```bash Run the pipeline theme={null}
    gst-launch-1.0 -e --gst-debug=2 \
    qtimlvconverter name=stage_01_preproc mode=image-batch-non-cumulative \
    qtimltflite name=stage_01_inference delegate=external external-delegate-path=libQnnTFLiteDelegate.so external-delegate-options="QNNExternalDelegate,backend_type=htp;" model=$HOME/models/$MODEL_NAME_1 \
    qtimlpostprocess name=stage_01_postproc results=10 module=qpd labels=$HOME/labels/$LABELS_NAME_1 settings=$HOME/labels/$LABELS_NAME_2 \
    qtimlvconverter name=stage_02_preproc image-disposition=centre mode=roi-batch-cumulative \
    qtimltflite name=stage_02_inference delegate=external external-delegate-path=libQnnTFLiteDelegate.so external-delegate-options="QNNExternalDelegate,backend_type=htp,htp_performance_mode=(string)2;" model=$HOME/models/$MODEL_NAME_2 \
    qtimlpostprocess name=stage_02_postproc results=1 module=hrnet labels=$HOME/labels/$LABELS_NAME_2 settings=$HOME/labels/$LABELS_NAME_4 \
    qticamsrc ! video/x-raw,format=NV12,width=1920,height=1080,framerate=30/1 ! queue ! tee name=t_split_1 \
    t_split_1. ! queue ! metamux_1. \
    t_split_1. ! queue ! stage_01_preproc. stage_01_preproc. ! queue ! stage_01_inference. stage_01_inference. ! queue ! stage_01_postproc. stage_01_postproc. ! text/x-raw ! queue ! metamux_1. \
    qtimetamux name=metamux_1 ! queue ! qtiobjtracker algo=bytetrack ! queue ! tee name=t_split_2 \
    t_split_2. ! queue ! metamux_2. \
    t_split_2. ! queue ! stage_02_preproc. stage_02_preproc. ! queue ! stage_02_inference. stage_02_inference. ! queue ! stage_02_postproc. stage_02_postproc. ! text/x-raw ! queue ! metamux_2. \
    qtimetamux name=metamux_2 ! queue ! qtivoverlay ! queue ! waylandsink fullscreen=true sync=false async=false
    ```
  </Step>
</Steps>
