Files
4-2-image-labeling/README.md

737 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 4-2 图像标注实战Label Studio
## 学习目标
1. 掌握 Label Studio 的安装、启动与界面使用
2. 学会配置三种图像标注类型(分类、目标检测、语义分割)
3. 独立完成边界框、多边形、关键点的标注
4. 理解 VOC / YOLO / COCO 三种导出格式的区别
---
## 1. Label Studio 简介
### 1.1 一句话定义
**Label Studio**:一个开源的、**多模态**数据标注平台,支持图像、文本、语音、视频等几乎所有数据类型的标注与团队协作。
### 1.2 为什么选它
我们这门课统一用 Label Studio 的原因:
| 需求 | Label Studio 对应能力 |
|------|---------------------|
| 多种数据类型 | 图像 / 文本 / 语音 / 视频 / 时序,一站式 |
| 不用写代码 | 通过 XML 标签可视化配置标注界面 |
| 团队协作 | 内置成员管理、角色权限、任务分配 |
| 格式灵活 | 内置 YOLO、COCO、VOC、JSON、CSV 导出 |
| 本地部署 | 数据不出学校,开源免费 |
```
传统方案(多工具切换):
图像 → LabelImg
文本 → Doccano
语音 → Audacity / ELAN
协作 → Excel 邮件
Label Studio 一站式:
图像 / 文本 / 语音 / 协作 → Label Studio
```
### 1.3 与其他工具的对比
| 工具 | 类型 | 适用场景 | 本课程 |
|------|------|---------|--------|
| **Label Studio** | 开源/多模态 | 课程学习 / 中小团队 / 综合项目 | 主选 |
| LabelImg | 开源/图像 | 极简目标检测 | 仅做对比 |
| CVAT | 开源/图像视频 | 大型分割、视频跟踪 | 了解 |
| Doccano | 开源/文本 | 简单文本分类 | 已弃用 |
| Scale AI | 商业 | 企业级标注 | 了解 |
---
## 2. Label Studio 安装与启动
### 2.1 环境要求
- Python 3.8 及以上
- 浏览器Chrome / Edge / Firefox
- 建议 8G 以上内存
### 2.2 pip 安装(推荐)
```bash
# 在命令行中执行
pip install label-studio
# 启动 Label Studio
label-studio
```
启动后命令行会显示:
```
[INFO] Label Studio is running at http://localhost:8080
[INFO] Open it in your browser to start labeling
```
### 2.3 第一次打开
1. 浏览器访问 `http://localhost:8080`
2. 第一次进入需要 **Sign Up** 注册管理员账号(用你的邮箱 + 密码)
3. 注册后自动登录到主界面
```
┌────────────────────────────────────────────────────────┐
│ Label Studio │
│ Sign Up │
├────────────────────────────────────────────────────────┤
│ │
│ Email: [___________________________] │
│ Username: [___________________________] │
│ Password: [___________________________] │
│ │
│ [ Create Account ] │
│ │
└────────────────────────────────────────────────────────┘
```
### 2.4 安装常见问题
| 问题 | 解决 |
|------|------|
| 端口 8080 被占用 | `label-studio --port 8001` |
| 启动报错找不到模块 | `pip install --upgrade label-studio` |
| 中文乱码 | 系统区域设置改为 UTF-8 |
| 浏览器无法打开 | 检查防火墙、放行端口 |
---
## 3. 主界面导览
登录后看到的主界面:
```
┌──────────────────────────────────────────────────────────────┐
│ [Label Studio] Projects Members Settings [用户头像] │
├──────────────────────────────────────────────────────────────┤
│ │
│ My Projects │
│ │
│ ┌────────────────────────────────────────────────┐ │
│ │ + Create Project │ │
│ └────────────────────────────────────────────────┘ │
│ │
│ 没有任何项目,点上面按钮开始 │
│ │
└──────────────────────────────────────────────────────────────┘
```
**主要功能区**
- **Projects**:项目列表,每个项目对应一个标注任务
- **Members**:成员管理(管理员可见)
- **Settings**:个人设置
---
## 4. 创建第一个项目:图像分类
### 4.1 任务说明
**任务**:对 10 张动物图片进行分类类别有cat / dog / bird
### 4.2 创建项目
1. 点击 `+ Create Project`
2. 填写:
- **Project Name**`animal_classification`
- **Description**:动物图片三分类
3. 点击 `Save`
### 4.3 配置标注界面
进入项目后,先点 `Settings``Labeling Interface``Code`
```xml
<View>
<Image name="image" value="$image"/>
<Choices name="label" toName="image" choice="single">
<Choice value="cat"/>
<Choice value="dog"/>
<Choice value="bird"/>
</Choices>
</View>
```
**逐行解释**
```
<View> ← 整个标注界面的根标签
<Image ...> ← 显示图像($image 是任务数据里的字段名)
<Choices ...> ← 单选/多选控件
<Choice/> ← 一个选项
</View>
```
**关键参数**
- `toName="image"`:告诉 Label Studio这个控件是对上面 `Image` 控件的结果
- `choice="single"`:单选(可选 `single-radio``multiple`
保存后点 `Label All Tasks` 就能看到标注界面。
### 4.4 导入数据
在项目页 → `Settings``Data Import`
**方式 A上传本地文件**
```
1. 准备文件夹
images/
├── cat_001.jpg
├── cat_002.jpg
├── dog_001.jpg
└── bird_001.jpg
2. 拖拽到上传区域
或点击 Upload Files 选中文件夹
```
**方式 B上传 CSV / JSONL推荐标签稳定**
`tasks.csv`
```csv
image
images/cat_001.jpg
images/cat_002.jpg
images/dog_001.jpg
images/bird_001.jpg
```
**方式 C粘贴 URL**
```csv
image
https://example.com/cat_001.jpg
https://example.com/dog_001.jpg
```
上传完后点 `Save` → 任务列表里就会看到每一张图对应一行任务。
### 4.5 开始标注
1. 点击 `Label All Tasks`
2. 进入标注界面:
- 上面是图片
- 下面是三个单选按钮
3. 选中正确类别
4. 点击右下角 `Submit` 进入下一张
5. 全部完成后回到项目页,可以看到完成进度
```
┌──────────────────────────────────────────────────┐
│ Project: animal_classification │
├──────────────────────────────────────────────────┤
│ Tasks: 10 total / 7 done / 3 skipped │
│ Progress: ████████████░░░░░░ 70% │
└──────────────────────────────────────────────────┘
```
### 4.6 导出数据
项目页 → `Export`
- 格式选 `JSON`
- 下载得到 `project-1-at-2024-05-20.json`
导出内容示例:
```json
[
{
"id": 1,
"data": {"image": "images/cat_001.jpg"},
"annotations": [{
"result": [{
"from_name": "label",
"to_name": "image",
"type": "choices",
"value": {"choices": ["cat"]}
}]
}]
}
]
```
---
## 5. 创建第二个项目:目标检测(边界框)
### 5.1 任务说明
**任务**:对 10 张街景图进行目标检测,标出每张图中的 `person``car``bicycle`
### 5.2 项目配置 XML
```xml
<View>
<Image name="image" value="$image"/>
<RectangleLabels name="label" toName="image" strokeWidth="3">
<Label value="person" background="#FF0000"/>
<Label value="car" background="#00FF00"/>
<Label value="bicycle" background="#0000FF"/>
</RectangleLabels>
</View>
```
**新增标签**
- `<RectangleLabels>`:矩形框 + 标签Label Studio 专门用于目标检测)
- `<Label value="..." background="...">`:每个标签的颜色
- `strokeWidth="3"`:边框线宽
### 5.3 标注操作
进入标注界面后:
```
┌──────────────────────────────────────────────────┐
│ [image] │
│ ┌────────┐ │
│ │ 人 │ ← 拖动鼠标画框 │
│ └────────┘ │
│ ┌─────────┐ │
│ │ 车 │ │
│ └─────────┘ │
├──────────────────────────────────────────────────┤
│ 标签栏: │
│ [ person ] [ car ] [ bicycle ] │
└──────────────────────────────────────────────────┘
```
**操作步骤**
1. 选中上方标签(点击 person/car/bicycle 之一)
2. 在图片上 **按住鼠标左键拖动**,画矩形框
3. 松开后,框会自动带上刚才选中的标签
4. 继续选下一个标签,再画下一个框
5. 同一张图可以有多个框
6. 标完后点 `Submit`
### 5.4 快捷键速查
| 快捷键 | 功能 |
|--------|------|
| `Ctrl + Enter` | 提交当前任务 |
| `H` | 切换显示已画框 |
| `Ctrl + Z` | 撤销上一个框 |
| `Delete` | 删除选中的框 |
| 数字 `1-9` | 快速选择第 N 个标签 |
| `+ / -` | 缩放图像 |
| 滚轮 | 上下滚动 |
### 5.5 边界框标注规范
**基本规则**
```
正确(紧贴目标) 错误(框太大) 错误(截断)
┌──────────┐ ┌────────────────┐ ┌──────────
│ ▓▓▓▓▓▓▓ │ │ ▓▓▓▓▓▓▓▓▓▓▓▓▓ │ │ ▓▓▓▓▓▓▓ │
│ ▓ 人 ▓▓ │ │ ▓ 人 ▓▓▓▓▓▓ │ │ ▓ 人 ▓▓ │
│ ▓▓▓▓▓▓▓ │ │ ▓▓▓▓▓▓▓▓▓▓▓▓▓ │ │ ▓▓▓▓▓▓▓ │
└──────────┘ └────────────────┘ └──────────┘
```
**多目标处理**
- 一张图有几个就标几个,每个独立画框
- 互相重叠的目标也要分别标
- 远处很小的目标可以标 "difficult" 标记
**遮挡处理**
```
情况1目标被部分遮挡
→ 标可见部分(标框框住能看到的人)
情况2目标被严重遮挡< 20% 可见)
→ 建议不标(标记为非标注目标)
情况3多人重叠
→ 每个独立标,画框按可见边界
```
### 5.6 YOLO 格式导出
项目页 → `Export` → 选 `YOLO`
下载得到压缩包,解压后结构:
```
project-1-at-2024-05-20-yolo/
├── images/
│ ├── street_001.jpg
│ └── street_002.jpg
├── labels/
│ ├── street_001.txt
│ └── street_002.txt
├── classes.txt
└── notes.json
```
`classes.txt`(类别映射):
```
0: person
1: car
2: bicycle
```
`street_001.txt`(一张图的标注):
```
# 格式: <class_id> <x_center> <y_center> <width> <height>
# 所有值都是相对图片尺寸的归一化值 (0-1)
0 0.35 0.45 0.18 0.55
1 0.75 0.50 0.30 0.20
```
**逐字段解释**
```
0 → 类别 ID0=person
0.35 → 框中心点 x / 图片宽度
0.45 → 框中心点 y / 图片高度
0.18 → 框宽度 / 图片宽度
0.55 → 框高度 / 图片高度
```
### 5.7 Pascal VOC 格式导出
项目页 → `Export` → 选 `PascalVOC`
`street_001.xml`
```xml
<?xml version="1.0" encoding="UTF-8"?>
<annotation>
<filename>street_001.jpg</filename>
<size>
<width>1920</width>
<height>1080</height>
<depth>3</depth>
</size>
<object>
<name>person</name>
<bndbox>
<xmin>134</xmin>
<ymin>216</ymin>
<xmax>478</xmax>
<ymax>810</ymax>
</bndbox>
</object>
<object>
<name>car</name>
<bndbox>
<xmin>1100</xmin>
<ymin>450</ymin>
<xmax>1680</xmax>
</bndbox>
</object>
</annotation>
```
注意 VOC 用的是**绝对像素坐标**xmin、ymin、xmax、ymax而 YOLO 是**归一化坐标**0-1
### 5.8 COCO 格式导出
项目页 → `Export` → 选 `COCO`
`result.json`
```json
{
"images": [
{"id": 1, "file_name": "street_001.jpg", "width": 1920, "height": 1080},
{"id": 2, "file_name": "street_002.jpg", "width": 1920, "height": 1080}
],
"categories": [
{"id": 0, "name": "person"},
{"id": 1, "name": "car"},
{"id": 2, "name": "bicycle"}
],
"annotations": [
{
"id": 1, "image_id": 1, "category_id": 0,
"bbox": [134, 216, 344, 594],
"area": 204336,
"iscrowd": 0
}
]
}
```
注意 COCO 的 `bbox` 格式是 `[x_min, y_min, width, height]`**前两个是左上角,后两个是宽高**),和 VOC 略有区别。
### 5.9 三种格式对比
| 特性 | VOC | YOLO | COCO |
|------|-----|------|------|
| 文件类型 | 每个图一个 XML | 每个图一个 TXT | 所有图一个 JSON |
| 坐标系 | 绝对像素 (xmin,ymin,xmax,ymax) | 归一化 0-1中心点+宽高)| 绝对像素 (x,y,w,h) |
| 多目标 | 一个 object 一对 bndbox | 一行一个目标 | 一个 annotation 一个目标 |
| 适用框架 | Faster R-CNN, SSD | YOLO 系列 | Mask R-CNN, Detectron2 |
| 优缺点 | 直观但文件多 | 紧凑、YOLO 专用 | 强大、适合大项目 |
| 人类可读 | ⭐⭐⭐ | ⭐ | ⭐⭐ |
**怎么选**
- 学 YOLO 模型 → 导 YOLO
- 用 MMDetection / Detectron2 → 导 COCO
- 通用、自己写训练脚本 → 导 VOC 或 JSON
---
## 6. 创建第三个项目:语义分割(多边形)
### 6.1 任务说明
**任务**:对 5 张街景图做**像素级**语义分割类别road、building、sky、vegetation
### 6.2 项目配置 XML
```xml
<View>
<Image name="image" value="$image"/>
<PolygonLabels name="label" toName="image" strokeWidth="2">
<Label value="road" background="#808080"/>
<Label value="building" background="#A52A2A"/>
<Label value="sky" background="#87CEEB"/>
<Label value="vegetation" background="#228B22"/>
</PolygonLabels>
</View>
```
`<PolygonLabels>`:多边形 + 标签,专门用于语义分割。
### 6.3 标注操作
1. 选中标签(点击 road / building / sky / vegetation
2. 在图像上**连续点击多个点**画出多边形
3. **双击或按回车**结束当前多边形
4. 一个类别画完,再选下一个类别继续
5. 一张图可能有很多个多边形
```
标注过程示意:
点 1 ──→ 点 2
点 4 ←── 点 3
(双击结束)
┌──────────────────┐
│ │
│ 1────────2 │
│ │ │ │
│ │ 区域 │ │
│ │ │ │
│ 4────────3 │
│ │
└──────────────────┘
```
### 6.4 分割标注注意事项
| 情况 | 处理 |
|------|------|
| 两个区域紧贴 | 各画一个多边形,不要合成一个 |
| 区域很小 | 至少 3 个点画出三角形 |
| 形状不规则 | 多点描边,越细越准 |
| 类别不确定 | 选最接近的,宁可错记也不要漏 |
### 6.5 导出多边形
项目页 → `Export` → 选 `JSON`
```json
{
"id": 1,
"data": {"image": "street_001.jpg"},
"annotations": [{
"result": [{
"from_name": "label",
"to_name": "image",
"type": "polygonlabels",
"value": {
"points": [[0.1, 0.8], [0.9, 0.8], [0.9, 1.0], [0.1, 1.0]],
"polygonlabels": ["road"]
}
}]
}]
}
```
`points` 数组里每个点都是 `[x, y]` 的归一化坐标0-1是按顺时针或逆时针排列的多边形顶点。
> 💡 想转成 mask像素级 PNG 图)?需要用 `label-studio-converter` 工具,详见 4-4 节。
---
## 7. 课堂演示Python SDK
### 7.1 简介
Label Studio 提供 `label-studio-sdk`,可以用 Python 编程式管理项目、查询任务、写入预标注。
### 7.2 安装
```bash
pip install label-studio-sdk
```
### 7.3 常用代码
```python
from label_studio_sdk import Client
# 连接本地服务
ls = Client(url='http://localhost:8080', api_key='YOUR_API_KEY')
# 获取 API Key
# Label Studio → Settings → Account → Access Token
# 列出所有项目
projects = ls.list_projects()
for p in projects:
print(p.id, p.title)
# 获取某个项目的任务
project = ls.get_project(id=1)
tasks = project.get_tasks()
print(f"项目里有 {len(tasks)} 个任务")
# 导入新任务
project.import_tasks([
{"image": "images/new_001.jpg"},
{"image": "images/new_002.jpg"}
])
# 导出标注
project.export_tasks(export_type='JSON')
```
> 这一节以了解为主,详细用法 4-4 节会展开。
---
## 8. 实战练习
### 8.1 任务一:图像分类(必做)
**任务**:在 Label Studio 创建项目 `fruit_classification`
**步骤**
1. 准备 10 张水果图片apple、banana、orange
2. 启动 Label Studio创建项目
3. 配置 `<Choices>` 三分类界面
4. 上传 10 张图
5. 完成 10 张标注
6. 导出 JSON 并截图
### 8.2 任务二:目标检测(必做)
**任务**:创建项目 `vehicle_detection`
**步骤**
1. 准备 10 张街景图
2. 配置 `<RectangleLabels>` 目标检测界面
3. 类别person / car / bicycle / traffic_light
4. 标完所有目标
5. 导出 YOLO 格式
6. 检查导出的 .txt 文件坐标是否正确
### 8.3 任务三(选做):语义分割
**任务**:创建项目 `scene_segmentation`
**步骤**
1. 准备 3-5 张风景图
2. 配置 `<PolygonLabels>` 分割界面
3. 类别sky / vegetation / road / building
4. 画多边形
5. 导出 JSON
### 8.4 标注自检清单
```
图像分类:
□ 类别选择是否正确
□ 是否有漏标的任务
□ 导出 JSON 是否完整
目标检测:
□ 边界框是否紧贴目标
□ 是否每个目标都标了
□ 框内类别是否正确
□ 导出 YOLO 格式后坐标值是否在 0-1 之间
□ classes.txt 是否齐全
语义分割:
□ 多边形顶点是否足够(至少 3 个)
□ 类别判断是否准确
□ 不同区域之间是否有遗漏
```
---
## 9. 本节知识小结
```
┌────────────────────────────────────────────────────────────┐
│ 4-2 图像标注实战Label Studio
├────────────────────────────────────────────────────────────┤
│ │
│ 📌 Label Studio 是多模态标注平台,一站式解决图像/文本/语音 │
│ │
│ 📌 安装: │
│ pip install label-studio │
│ label-studio │
│ 浏览器访问 http://localhost:8080 │
│ │
│ 📌 三种图像标注类型: │
│ 分类 → <Choices> │
│ 目标检测 → <RectangleLabels> │
│ 语义分割 → <PolygonLabels> │
│ │
│ 📌 三种导出格式: │
│ VOC → XML像素绝对坐标 │
│ YOLO → TXT归一化 0-1 坐标 │
│ COCO → JSON[x,y,w,h] 像素坐标 │
│ │
│ 📌 标注规范:框要紧贴目标、不多不少 │
│ │
└────────────────────────────────────────────────────────────┘
```
---
## 课后任务
1. 安装 Label Studio截图证明能正常打开
2. 完成"任务一"图像分类 10 张图
3. 完成"任务二"目标检测 10 张图,导出 YOLO 格式
4. (选做)完成"任务三"语义分割
---
## 下节预告
下一节我们将学习 **4-3 文本标注与语音标注Label Studio**
- 文本分类、NER 命名实体识别
- 意图识别与槽位标注
- 语音转写 ASR
- 说话人分离与音频分类