# 概述

X-AnyLabeling 的视频分类器是面向动作识别和视频片段分类数据集的独立标注窗口。它支持加载视频、维护类别标签、在时间轴上创建片段、为每个片段分配类别、预览帧，并可导出按类别整理的视频片段或抽帧数据。

<video src="https://github.com/user-attachments/assets/33a57390-683d-4a24-b0cf-3668af5f7a13" width="100%" controls>
</video>

# 启动

可以从主窗口工具栏打开视频分类器，也可以使用配置中的快捷键：

- Windows/Linux：`Ctrl` + `5`
- macOS：`⌘` + `5`

打开窗口后，可以将视频拖入窗口，或点击预览区底部的打开视频按钮加载文件。常见视频格式如 `mp4`、`avi`、`mov`、`mkv`、`webm` 均可使用。

预览区右上角的教程图标会打开 GitHub 上的当前教程，旁边的快捷键图标会在窗口内弹出快捷键对照表。

# 教程

视频分类器主要由三块区域组成：

- 左侧预览区：显示当前视频帧、播放控制、AI 自动切分、保存当前帧、预览缩放、快捷键说明、教程入口和数据集导出入口。
- 右侧面板：管理标签、片段列表和片段描述。
- 底部时间轴：显示缩略图、时间刻度、播放头以及可编辑的标注片段。

## 标签

开始标注前，建议先在右侧的 Labels 面板准备好本次任务需要的类别。每个标签都会分配一个颜色，后续在时间轴和片段列表中都会沿用这套颜色，浏览长视频时更容易看出不同类别的分布。

点击添加按钮可以新增标签；如果需要重命名、调整颜色、批量导入或删除标签，可以进入标签设置。前十个标签会在名称后显示 `(0)` 到 `(9)`，标注时按对应数字键即可快速切换当前标签。

创建片段时会使用当前选中的标签。如果删除某个标签，已经使用该标签的片段也会一并删除，请在确认不再需要这些片段后再操作。

> [!TIP]
> 如果类别较多，可以提前准备一个 `classes.txt` 文件，每行写一个类别名称。进入右侧 Labels 面板的标签设置后，点击上传即可一次性导入。

## 创建片段

片段从时间轴标尺区域创建：

1. 在 Labels 面板中选择目标标签。
2. 将鼠标移动到时间轴上方的标尺区域。
3. 按住鼠标右键拖动到目标时间范围，松开后创建片段。
4. 新片段会使用当前选中的标签。

如果当前没有选中标签，软件会提示先选择或创建标签。

也可以使用 `I` 和 `O` 标记入点与出点，然后按 `Enter` 根据标记范围创建片段。

## AI 配置

视频分类器中的 AI 自动切分和片段描述生成功能共用 [Chatbot](../zh_cn/chatbot.md) 中配置的模型。首次使用前，请先打开 Chatbot（Windows/Linux：`Ctrl` + `1`，macOS：`⌘` + `1`），在右侧设置 API Key、服务商、接口地址和当前模型。

以阿里云百炼的 `qwen3.6-flash` 为例，可以在 Chatbot 中选择 Qwen 提供商，填写百炼 API Key，并将当前模型设置为 `qwen3.6-flash`。如果通过 Custom 提供商接入兼容 OpenAI API 的端点，请确保接口地址与服务商要求一致，例如百炼兼容模式通常使用：

```text
https://dashscope.aliyuncs.com/compatible-mode/v1
```

> [!NOTE]
> 请自行确认当前选择的模型是否支持视频理解。不同服务商、不同模型对视频文件大小、时长、帧率、输入方式和计费方式的限制可能不同；以阿里云百炼为例，可以参考 [图像与视频理解](https://help.aliyun.com/zh/model-studio/vision?userCode=okjhlpr5#006b533c6cc0) 文档查看视频相关限制。

## AI 自动切分

如果已经在 Chatbot 中配置好支持视频理解的模型，可以点击预览区底部的魔法棒按钮，让 AI 根据视频内容自动生成片段。弹窗中会显示当前使用的模型，并提供可编辑的 Prompt。界面语言为中文时会默认填充中文模板，其他语言下会默认填充英文模板。

AI 自动切分支持两种输入范围：

- 选中片段时，默认只把当前选中片段发送给模型，并用模型返回的新片段替换该片段。
- 勾选 `Use full video` 时，会把整段视频发送给模型。若当前视频已经存在片段，继续前会提示确认，确认后会用 AI 生成的片段覆盖现有片段。

模型需要返回 JSON，例如：

```json
{
  "events": [
    {
      "start_time": "00:00:00",
      "end_time": "00:00:05",
      "event": "人物手持一个纸箱走向桌子，并将纸箱放在桌上。"
    }
  ]
}
```

其中 `start_time` 和 `end_time` 使用 `HH:mm:ss` 格式，`event` 会写入片段描述。若当前已经选中某个标签，生成片段会使用该标签；如果没有选中标签，则会自动使用 `片段1`、`片段2` 这样的内置标签名称。

## 编辑片段

已有片段可以直接在时间轴或片段列表中编辑。

| 操作 | 结果 |
|------|------|
| 单击片段 | 选中片段，并跳转播放帧到片段起始位置 |
| 双击片段 | 修改标签类别和片段描述 |
| 鼠标左键按住片段并拖动 | 移动片段 |
| 拖动片段左边缘或右边缘 | 调整片段起止时间 |
| Delete/Backspace | 删除选中的片段 |
| 剪刀按钮 | 在播放头位置切分选中的片段 |
| 撤销/重做 | 回退或恢复片段编辑 |

Segments 列表会与时间轴保持同步。点击某个片段时，播放帧会自动跳转到该片段的起始位置。

当光标位于片段区域时，界面会提示双击可编辑标签和描述，鼠标左键按住可拖动片段。

选中片段后，可以在右侧 Description 面板中编辑描述。Description 标题右侧的魔法棒按钮可以调用 Chatbot 中配置的 AI 模型，为当前片段自动生成描述。生成前会弹出 Prompt 编辑窗口，用户可以查看当前模型并调整 Prompt；生成过程中可以取消等待。该功能只修改当前片段的描述，不会改变片段的起止时间或标签。

## 播放与导航

可以使用底部控制按钮或快捷键进行逐帧检查。同样的快捷键对照表也可以从预览区右上角的快捷键图标打开。

| 快捷键 | 功能 |
|--------|------|
| Space | 播放或暂停 |
| Left/Right | 向后/向前移动一帧 |
| Shift + Left/Right | 向后/向前跳转一秒 |
| `,`/`.` | 跳转到上一个或下一个片段 |
| I/O | 标记入点/出点 |
| Enter | 根据入点和出点创建片段 |
| Delete/Backspace | 删除选中的片段 |
| Ctrl+S 或 ⌘+S | 保存 sidecar 标注文件 |
| Ctrl+Z 或 ⌘+Z | 撤销 |
| Ctrl+Shift+Z 或 ⌘+Shift+Z | 重做 |
| 0-9 | 选择对应编号的标签 |

时间轴支持缩放按钮，也支持在时间轴上使用 `Ctrl` + 鼠标滚轮缩放。长视频可以通过底部水平滚动条查看不同时间段。

将光标移动到时间轴标尺区域时，会显示按住鼠标右键拖动并释放以创建片段的提示。该提示只会出现在时间轴交互区域，不会覆盖缩略图片轴。

## 导出

完成片段标注后，点击预览区底部的 Export dataset 可以导出当前视频的标注结果。导出内容会按类别整理，便于后续检查、打包或接入自己的训练流程。

导出窗口中的选项含义如下：

| 选项 | 说明 |
|------|------|
| `Output` | 选择导出目录。默认会在视频所在目录下创建与当前视频 basename 同名的文件夹，例如 `sample.mp4` 默认导出到 `sample/`。 |
| `Video clips` | 将每个片段导出为 `.mp4` 文件，并按标签名称放入对应类别目录。 |
| `Raw frame sequences` | 将每个片段导出为 `img_00001.jpg` 形式的图片序列。 |
| `RawFrames FPS` | 设置抽帧帧率。填 `0` 表示使用源视频帧率。 |
| `Re-encode clips` | 重新编码片段，导出速度会慢一些，但起止位置更准确；关闭后会优先使用更快的 stream copy。 |
| `Pack output as .zip` | 导出完成后，在输出目录旁生成同名 zip 压缩包。 |

输出目录结构如下：

```bash
sample/
├── videos/
│   ├── label_a/
│   │   ├── sample_s000001.mp4
│   │   └── sample_s000002.mp4
│   └── label_b/
│       └── sample_s000003.mp4
├── rawframes/
│   ├── label_a/
│   │   └── sample_s000001/
│   │       ├── img_00001.jpg
│   │       └── img_00002.jpg
│   └── label_b/
│       └── sample_s000003/
│           ├── img_00001.jpg
│           └── img_00002.jpg
├── label_map.txt
└── metadata.json
```

视频片段切分和抽帧都由 `ffmpeg` 完成。X-AnyLabeling 会优先使用系统中的 `ffmpeg`，如果未检测到，也会尝试使用 `imageio-ffmpeg` 提供的可执行文件；两者都不可用时，导出功能无法继续。

# 数据格式

视频标注会保存为与视频同名的 sidecar JSON 文件。例如，`sample.mp4` 对应 `sample.json`。

```json
{
  "version": "1.0.0",
  "type": "video_classification",
  "video": "sample.mp4",
  "fps": 30.0,
  "duration_ms": 120000,
  "width": 1920,
  "height": 1080,
  "labels": ["run", "walk"],
  "label_colors": {
    "run": "#ff7f0e",
    "walk": "#1f77b4"
  },
  "segments": [
    {
      "id": "s1234567890",
      "label": "run",
      "start_ms": 1000,
      "end_ms": 3500,
      "start_frame": 30,
      "end_frame": 105,
      "description": "人物听到哨声后开始奔跑。"
    }
  ]
}
```
