3. 标注工具选型与搭建:开源工具对比与私有化部署
标注工具选型这件事,说实话,我踩过不少坑。刚开始做项目时,总觉得「随便找个工具先用着」,结果数据量一上来,团队协作一团糟,格式不统一,返工成本高得吓人。后来我学乖了——工具选对了,训练流程就顺了一半。
今天咱们就聊聊市面上主流的几款开源标注工具,以及怎么把它们部署到自己的服务器上。嗯,我会结合我自己的项目经验,帮你避开那些我当年踩过的坑。
3.1 三大开源工具横向对比
目前工业界用得最多的,就是 LabelImg、CVAT 和 Supervisely 这三款。我分别说说它们的优缺点。
| 工具 | 适用场景 | 优点 | 缺点 | 我个人的建议 |
|---|---|---|---|---|
| LabelImg | 小团队、快速原型、单机标注 | 轻量、安装简单、支持 Pascal VOC / YOLO 格式 | 无协作功能、不支持视频、无 Web 界面 | 适合 1-3 人小项目,快速出活 |
| CVAT | 中大型团队、多人在线协作 | 功能全面、支持视频标注、有自动标注插件 | 部署稍复杂、资源占用高 | 我目前主力推荐,尤其是团队协作场景 |
| Supervisely | 企业级、需要完整 MLOps 流程 | 内置模型训练、插件生态丰富、API 完善 | 社区版功能受限、学习曲线陡 | 适合预算充足、需要端到端管线的团队 |
我的经验之谈: 如果你只是做几百张图片的快速验证,LabelImg 就够了。但一旦数据量超过 5000 张,或者需要多人同时标注,我建议直接上 CVAT。Supervisely 虽然强大,但社区版限制太多,我一般只在客户有明确预算时才推荐。
3.2 私有化部署方案
为什么要私有化部署?说白了,数据安全是第一位的。尤其是医疗、金融、自动驾驶这些领域,数据绝对不能出公司内网。我去年帮一家医院做项目,光数据合规就折腾了两周——嗯,从那以后我特别重视私有化部署。
3.2.1 CVAT 私有化部署(推荐)
CVAT 的部署其实不复杂,但有几个坑要注意。我直接给出一份我验证过的部署脚本:
# 1. 克隆仓库
git clone https://github.com/opencv/cvat.git
cd cvat
# 2. 修改 docker-compose.yml,关闭不必要的服务
# 我习惯只保留 cvat_app、cvat_db、cvat_redis 三个核心服务
# 3. 启动服务
docker compose up -d
# 4. 创建管理员账号
docker exec -it cvat_app bash -c \
"python3 manage.py createsuperuser"
# 5. 访问 http://localhost:8080 即可使用
避坑指南: 我曾经因为没配置数据持久化,重启容器后所有标注数据全丢了……后来我强制要求团队在 docker-compose.yml 里加上 volumes 映射。另外,生产环境一定要用 HTTPS,不然标注数据在传输过程中是明文的。
3.2.2 LabelImg 的「伪」私有化
LabelImg 本身是桌面应用,没有服务端。但你可以把它和 NAS 或 Git 仓库结合:
- 把标注文件(XML/JSON)统一存到 NAS 共享目录
- 用 Git 做版本管理,每次标注完提交一次
- 配合 CI/CD 自动校验标注格式
这个方法虽然简陋,但胜在零成本。我早期做小项目时就这么干,效果还不错。
3.2.3 Supervisely 社区版部署
Supervisely 社区版部署相对重一些,但如果你需要内置模型训练功能,可以考虑:
# 官方推荐方式
git clone https://github.com/supervisely/supervisely.git
cd supervisely/deploy/docker
docker compose up -d
注意: Supervisely 社区版限制最多 5 个用户同时在线,且不支持 GPU 加速。如果你团队超过 5 人,要么付费,要么换 CVAT。
3.3 标注工具 API 对接
工具部署好了,怎么和你的训练流程打通?说白了,就是通过 API 把标注数据拉出来,喂给模型训练脚本。我一般用 Python 写一个中间层,统一处理不同工具的导出格式。
3.3.1 CVAT API 对接示例
CVAT 提供了 RESTful API,我最常用的是获取任务标注数据:
import requests
import json
# 配置
CVAT_URL = "http://localhost:8080"
API_TOKEN = "你的API Token" # 在 CVAT 后台生成
headers = {
"Authorization": f"Token {API_TOKEN}"
}
# 获取指定任务的标注数据
task_id = 123
response = requests.get(
f"{CVAT_URL}/api/tasks/{task_id}/annotations",
headers=headers
)
if response.status_code == 200:
annotations = response.json()
# 保存为 COCO 格式
with open(f"task_{task_id}_annotations.json", "w") as f:
json.dump(annotations, f, indent=2)
print(f"成功导出 {len(annotations['shapes'])} 个标注框")
else:
print(f"请求失败: {response.status_code}")
我踩过的坑: 第一次对接 CVAT API 时,我直接用了默认的 Token,结果发现 Token 有效期只有 24 小时。后来我改用 JWT Token,并写了个自动刷新逻辑。另外,CVAT 的 API 返回的坐标是归一化的,记得转成绝对坐标再喂给模型。
3.3.2 Supervisely API 对接
Supervisely 的 API 更完善,但学习成本也更高。我一般只用它的数据导出功能:
import supervisely as sly
# 初始化 API
api = sly.Api(server_address="http://localhost:8080", token="你的Token")
# 获取项目信息
project = api.project.get_info_by_id(project_id=456)
# 下载标注数据到本地
sly.download_project(
api=api,
project_id=project.id,
dest_dir="./supervisely_data",
save_image_urls=False,
save_annotations=True
)
print(f"项目 {project.name} 下载完成,共 {project.items_count} 张图片")
3.3.3 统一数据格式转换
不同工具导出的格式不一样,我习惯统一转成 COCO 格式,这样训练脚本只需要写一次:
def convert_to_coco(source_format, source_path, output_path):
"""
统一转换函数
source_format: 'cvat', 'supervisely', 'labelimg'
"""
if source_format == 'cvat':
# 调用 CVAT 的转换工具
from cvat.apps.dataset_manager.bindings import TaskData
# ... 具体转换逻辑
pass
elif source_format == 'supervisely':
# 使用 Supervisely SDK 转换
pass
elif source_format == 'labelimg':
# 直接解析 XML 文件
import xml.etree.ElementTree as ET
# ... 解析逻辑
pass
else:
raise ValueError(f"不支持的格式: {source_format}")
print(f"转换完成,保存至 {output_path}")
3.4 本章知识体系总览
下面这张图是我自己画的,帮你理清标注工具选型与搭建的核心逻辑:
我的建议: 别一上来就追求最全的工具。先想清楚你的数据量、团队规模、安全要求。我见过太多团队花两周部署 Supervisely,结果只用到了标注功能——说白了,杀鸡用牛刀。从 CVAT 起步,等业务量上来了再考虑升级,这是最稳妥的路径。
好了,这一章的内容就到这里。工具选型没有银弹,关键是要匹配你的实际场景。下一章咱们聊聊标注质量控制——嗯,那才是真正考验工程能力的地方。