5分钟搞定深度学习标注:Labelme、LabelImg、EISeg保姆级安装配置指南
深度学习数据标注实战:从零搭建Labelme、LabelImg与EISeg的高效工作流
最近在带几个实习生做计算机视觉项目,发现他们花在数据标注上的时间,往往比模型训练和调参还要多。不是工具装不上,就是格式转换出错,要么就是标注效率太低,反复折腾。这让我想起自己刚入门时踩过的那些坑——其实只要把标注环境搭建好,后续的工作会顺畅得多。
数据标注是深度学习项目里最基础、也最容易被低估的环节。一张图片标注得好不好,直接影响模型学习的上限。对于刚接触这个领域的新手来说,面对Labelme、LabelImg、EISeg这些工具,可能会感到无从下手。网上的教程要么过于简略,要么环境依赖复杂,跟着做总是报错。
这篇文章,我就结合自己这几年在多个实际项目中的标注经验,为你梳理一套开箱即用、避坑指南式的标注环境搭建方案。我们不只讲安装命令,更会深入每个工具的特点、适用场景,以及如何根据你的项目需求选择合适的工具链。无论你是要处理目标检测、实例分割还是简单的图像分类任务,这套流程都能帮你快速上手,把时间真正花在模型迭代上,而不是和环境配置较劲。
1. 标注工具全景图:如何根据任务选择你的“武器”
在开始安装之前,我们需要先搞清楚每个工具的核心定位。不同的标注工具擅长不同的任务,选对了工具,效率能提升好几倍。
LabelImg 是最经典的目标检测标注工具,它只支持矩形框标注,输出格式包括PASCAL VOC XML、YOLO txt和CreateML JSON。它的界面非常简洁,学习成本几乎为零。如果你做的是车辆检测、人脸识别这类标准的矩形框检测任务,LabelImg是首选。它的局限性也很明显:无法处理不规则形状的物体,比如医学图像中的病灶区域、遥感图像中的建筑物轮廓。
Labelme 由麻省理工学院计算机科学与人工智能实验室(MIT CSAIL)开发,它最大的优势是支持多边形标注,非常适合实例分割和语义分割任务。你可以用鼠标精确勾勒出物体的每一个边缘,生成精细的掩膜。Labelme默认输出JSON格式,这个格式包含了多边形的所有顶点坐标,信息非常丰富。不过,很多训练框架(如YOLO、MMDetection)需要特定的格式,因此通常需要额外的转换脚本。
EISeg 是百度飞桨团队推出的交互式智能分割标注工具。它最大的亮点是引入了AI辅助标注。你只需要在物体内部点一下,再在外部点一下,模型就能自动预测出完整的分割掩膜,大大减少了手动勾勒多边形的工作量。EISeg内置了通用、人像、遥感、医疗等多个预训练模型,对于专业领域的标注尤其高效。它支持导出COCO JSON和PaddleSeg格式。
为了更直观地对比,我整理了这三个工具的核心特性:
| 特性维度 | LabelImg | Labelme | EISeg |
|---|---|---|---|
| 主要标注类型 | 矩形框 | 多边形、矩形框 | 交互式分割(多边形) |
| 核心优势 | 简单、快速、稳定 | 标注精度高、灵活 | AI辅助、效率极高 |
| 典型输出格式 | XML (VOC), TXT (YOLO) | JSON | JSON (COCO), PaddleSeg格式 |
| 最适合任务 | 目标检测 | 实例/语义分割 | 复杂形状分割、大批量标注 |
| 学习曲线 | 极低 | 中等 | 中等(需理解交互逻辑) |
| 环境依赖复杂度 | 低 | 中等 | 较高(需安装PaddlePaddle) |
提示:对于全新的项目,我建议你先用少量图片(20-30张)在三个工具上都试一下。感受一下各自的标注速度、操作手感,再决定主力使用哪个。很多时候,工具的选择也和个人习惯有关。
在实际项目中,我经常混合使用这些工具。例如,先用LabelImg快速拉出所有物体的矩形框,完成初筛和分类;对于其中需要精细分割的类别,再导入Labelme或EISeg进行多边形标注。这种流水线作业能兼顾速度和精度。
2. 避坑安装指南:一次性搞定所有依赖
安装环节是新手最容易卡住的地方。网上很多教程的安装命令已经过时,或者忽略了系统环境的差异。下面我提供的步骤,在Windows 10/11和Ubuntu 20.04/22.04上都亲自验证过,尽可能绕开了常见的依赖冲突。
2.1 基础Python环境搭建
强烈建议使用Anaconda或Miniconda来管理Python环境。这能完美解决不同项目间包版本冲突的问题。如果你已经安装了Python,可以跳过这一步。
# 以Miniconda为例,下载安装脚本(Linux/macOS)
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh
# Windows用户可直接从官网下载.exe安装包
安装完成后,创建一个专用于标注工作的虚拟环境:
conda create -n label_env python=3.8 -y
conda activate label_env
这里选择Python 3.8是因为它在深度学习生态中兼容性最好,绝大多数库的稳定版本都支持3.8。
2.2 LabelImg:最稳定的矩形框标注器
LabelImg的安装其实很简单,但很多人卡在PyQt5的安装上。我们使用pip直接安装编译好的轮子(wheel)即可。
# 1. 安装必要的系统依赖(Ubuntu/Debian)
sudo apt-get update
sudo apt-get install -y libxcb-xinerama0 libgl1-mesa-glx
# 2. 安装Python依赖和LabelImg
pip install pyqt5 lxml
pip install labelImg
安装完成后,直接在终端输入 labelImg 命令即可启动。如果提示找不到命令,很可能是你的Python脚本目录没有加入系统PATH。可以尝试用模块方式启动:
python -m labelImg
第一次启动可能会稍慢。界面打开后,你可以通过 Open Dir 打开图片目录,Change Save Dir 设置标签保存目录。快捷键能极大提升效率,务必记住这几个最常用的:
W:创建矩形框Ctrl + S:保存当前图片的标注D:下一张图片A:上一张图片Ctrl + Shift + S:更改标注格式(在VOC XML、YOLO、CreateML之间切换)
注意:在保存YOLO格式时,LabelImg需要你预先准备一个
classes.txt文件,里面按行写入所有类别名称。把这个文件放在标签保存目录下,LabelImg会自动读取。
2.3 Labelme:多边形标注的瑞士军刀
Labelme的安装同样直接,但它对OpenCV的版本有一定要求。建议按照以下顺序安装:
# 1. 安装Labelme及其核心依赖
pip install labelme
# 2. 安装匹配的OpenCV(避免版本冲突)
pip install opencv-python==4.5.5.64
pip install opencv-contrib-python==4.5.5.64
安装后,运行 labelme 命令启动。它的界面比LabelImg稍复杂一些,但功能强大得多。除了多边形工具,还支持矩形、圆形、直线、点等多种标注类型。
Labelme工作流示例:
- 点击
Open Dir加载图片文件夹。 - 使用左侧工具栏的
Polygon(多边形)工具,沿着物体边缘依次点击,最后点击第一个点闭合多边形。 - 在弹出的对话框中输入类别标签。
- 标注完一张图的所有物体后,点击
Save,会生成一个同名的.json文件。
这个JSON文件包含了图片路径、图像尺寸以及每个多边形的顶点坐标和类别。它是后续格式转换的基础。
2.4 EISeg:当AI成为你的标注助手
EISeg的安装相对复杂,因为它依赖于百度的PaddlePaddle深度学习框架。但为了其强大的AI辅助能力,这点复杂度是值得的。我们一步步来。
首先,安装PaddlePaddle。根据你是否有GPU,选择不同的版本。有NVIDIA GPU且已安装CUDA的用户强烈建议安装GPU版本,因为EISeg的交互模型推理会快很多。
# 选项A:安装CPU版本(通用,速度较慢)
python -m pip install paddlepaddle -i https://mirror.baidu.com/pypi/simple
# 选项B:安装GPU版本(CUDA 11.2)
python -m pip install paddlepaddle-gpu==2.4.2.post112 -f https://www.paddlepaddle.org.cn/whl/linux/mkl/avx/stable.html
安装完PaddlePaddle后,再安装EISeg:
pip install eiseg
安装完成后,在终端输入 eiseg 启动。第一次启动时,软件会自动下载模型文件,或者提示你手动下载。建议根据你的标注场景选择合适的模型:
- 通用场景:选择
hrnet18_ocr64_cocolvis,精度和速度平衡。 - 人像分割:选择
hrnet18_ocr48_human,针对人像优化。 - 遥感图像:选择
hrnet18_ocr48_rs。 - 医疗图像:选择
hrnet18_ocr48_medical。
模型下载后,通过界面上的 加载模型 按钮导入。一个常见的报错是OpenMP库冲突(特别是Windows上),如果启动时看到 OMP: Error #15 之类的错误,可以在你的Python脚本或命令行中设置环境变量解决:
# 在启动eiseg前设置
set KMP_DUPLICATE_LIB_OK=TRUE # Windows
export KMP_DUPLICATE_LIB_OK=TRUE # Linux/macOS
或者更一劳永逸的方法是,找到EISeg的启动脚本或创建一个批处理文件,预先设置这个变量。
EISeg的使用体验非常直观:在想要分割的物体内部点击一下(正样本点),在物体外部背景处点击一下(负样本点),模型就会实时生成分割结果。你可以通过不断添加正负点来修正预测的掩膜,直到满意为止。
3. 格式转换实战:打通标注到训练的“最后一公里”
工具标注出的原始格式,很少能直接用于训练。这就是格式转换脚本大显身手的地方。很多人在这里放弃,其实只要理解逻辑,转换并不难。
3.1 Labelme JSON 转 YOLO TXT
YOLO格式的标签文件是一个 .txt 文件,每行代表一个物体,格式为:class_id x_center y_center width height。这里的坐标和宽高都是归一化后的值(即除以图片宽度和高度)。
Labelme的JSON里存储的是多边形的绝对坐标点。我们需要做的是:
- 将多边形顶点转换为一个最小的外接矩形。
- 计算这个矩形的中心点、宽度和高度。
- 将其归一化。
下面是一个我修改过的、更健壮的转换脚本:
import json
import os
import numpy as np
from pathlib import Path
def labelme_json_to_yolo_txt(json_path, output_dir, class_list):
"""
将单个Labelme JSON文件转换为YOLO格式的TXT文件。
Args:
json_path: Labelme JSON文件路径
output_dir: 输出TXT文件目录
class_list: 类别名称列表,如 ['person', 'car', 'dog']
"""
with open(json_path, 'r', encoding='utf-8') as f:
data = json.load(f)
img_height = data['imageHeight']
img_width = data['imageWidth']
txt_lines = []
for shape in data['shapes']:
label = shape['label']
points = np.array(shape['points'])
# 确保类别在列表中
if label not in class_list:
print(f"警告:在{json_path}中发现未知类别 '{label}',已跳过。")
continue
class_id = class_list.index(label)
# 计算多边形的最小外接矩形
x_coords = points[:, 0]
y_coords = points[:, 1]
x_min, x_max = np.min(x_coords), np.max(x_coords)
y_min, y_max = np.min(y_coords), np.max(y_coords)
# 计算中心点和宽高,并归一化
x_center = (x_min + x_max) / 2.0
y_center = (y_min + y_max) / 2.0
width = x_max - x_min
height = y_max - y_min
x_center_norm = x_center / img_width
y_center_norm = y_center / img_height
width_norm = width / img_width
height_norm = height / img_height
# 写入一行,保留6位小数
line = f"{class_id} {x_center_norm:.6f} {y_center_norm:.6f} {width_norm:.6f} {height_norm:.6f}"
txt_lines.append(line)
# 写入TXT文件
json_stem = Path(json_path).stem
txt_path = os.path.join(output_dir, f"{json_stem}.txt")
with open(txt_path, 'w') as f:
f.write('\n'.join(txt_lines))
print(f"已转换: {json_path} -> {txt_path}")
# 批量转换示例
if __name__ == '__main__':
json_dir = './labelme_annotations' # 你的JSON文件夹
output_dir = './yolo_labels' # 输出文件夹
classes = ['cat', 'dog', 'person'] # 你的类别,顺序很重要!
os.makedirs(output_dir, exist_ok=True)
for json_file in Path(json_dir).glob('*.json'):
labelme_json_to_yolo_txt(json_file, output_dir, classes)
这个脚本增加了错误处理(未知类别跳过)、更精确的浮点数格式,并且使用了 pathlib 模块,路径处理更安全。
3.2 Labelme JSON 转 VOC XML
PASCAL VOC格式是另一种常见的XML格式,被很多早期框架使用。转换逻辑类似,但需要构建XML树。使用Python的 xml.etree.ElementTree 可以方便地完成。
import xml.etree.ElementTree as ET
from xml.dom import minidom
def json_to_voc_xml(json_data, xml_save_path):
root = ET.Element('annotation')
# 添加文件夹、文件名、路径等基本信息
folder = ET.SubElement(root, 'folder')
folder.text = 'images'
filename_elem = ET.SubElement(root, 'filename')
filename_elem.text = json_data['imagePath']
size = ET.SubElement(root, 'size')
ET.SubElement(size, 'width').text = str(json_data['imageWidth'])
ET.SubElement(size, 'height').text = str(json_data['imageHeight'])
ET.SubElement(size, 'depth').text = '3' # 假设为RGB图像
for shape in json_data['shapes']:
obj = ET.SubElement(root, 'object')
ET.SubElement(obj, 'name').text = shape['label']
ET.SubElement(obj, 'pose').text = 'Unspecified'
ET.SubElement(obj, 'truncated').text = '0'
ET.SubElement(obj, 'difficult').text = '0'
bndbox = ET.SubElement(obj, 'bndbox')
points = np.array(shape['points'])
xmin, ymin = np.min(points[:, 0]), np.min(points[:, 1])
xmax, ymax = np.max(points[:, 0]), np.max(points[:, 1])
ET.SubElement(bndbox, 'xmin').text = str(int(round(xmin)))
ET.SubElement(bndbox, 'ymin').text = str(int(round(ymin)))
ET.SubElement(bndbox, 'xmax').text = str(int(round(xmax)))
ET.SubElement(bndbox, 'ymax').text = str(int(round(ymax)))
# 美化输出XML
rough_string = ET.tostring(root, 'utf-8')
reparsed = minidom.parseString(rough_string)
pretty_xml = reparsed.toprettyxml(indent=" ")
with open(xml_save_path, 'w', encoding='utf-8') as f:
f.write(pretty_xml)
3.3 EISeg COCO JSON 的转换与处理
EISeg可以导出COCO格式的JSON。COCO格式是一个集中式的标注文件,它包含了整个数据集的所有图片信息和标注信息,与Labelme的每图一个JSON不同。
处理COCO JSON时,我们通常需要根据任务需求进行拆分。例如,YOLO训练需要的是每张图片对应的TXT文件。我们可以使用 pycocotools 这个官方库来解析COCO JSON。
pip install pycocotools
然后使用下面的脚本片段进行提取和转换:
from pycocotools.coco import COCO
coco_anno_path = './eiseg_annotations/annotations.json'
coco = COCO(coco_anno_path)
# 获取所有图片ID
img_ids = coco.getImgIds()
for img_id in img_ids:
img_info = coco.loadImgs(img_id)[0]
ann_ids = coco.getAnnIds(imgIds=img_id)
annotations = coco.loadAnns(ann_ids)
# 针对每个annotation,提取bbox并转换为YOLO格式
# ... 转换逻辑与之前类似,注意COCO的bbox格式是 [x_top_left, y_top_left, width, height]
4. 高效标注心法与高级技巧
工具装好了,格式也会转了,接下来就是如何真正提升标注效率和质量。这部分是我在大量标注工作中总结出的“软技能”。
4.1 建立标准化的标注流程
混乱的文件夹结构是噩梦的开始。在开始任何标注项目前,先建立这样的目录结构:
your_project/
├── images/
│ ├── train/
│ ├── val/
│ └── test/
├── labels/ (或 annotations/)
│ ├── labelme_json/ # 存放Labelme原始JSON
│ ├── yolo_txt/ # 存放转换后的YOLO标签
│ └── voc_xml/ # 存放转换后的VOC XML
├── classes.txt # 统一的类别定义文件
└── scripts/ # 存放所有转换脚本
关键点:
- 图片和标签的对应关系必须清晰。通常通过相同的文件名(仅后缀不同)来关联。
classes.txt文件一旦确定,绝对不要中途更改类别顺序。否则所有已转换的标签文件中的类别ID都会错乱。- 对数据集进行训练集/验证集/测试集的划分,应该在标注完成之后、转换格式之前进行。你可以先划分好图片,然后分别对每个子集进行标注和转换。
4.2 多人协作标注的策略
当项目需要标注的数据量很大时,一个人无法完成,就需要团队协作。
- 统一标准会议:在开始前,召集所有标注人员,用一批示例图片进行标注演练。明确边界怎么划(例如,被遮挡的物体画到哪里?反光部分算不算?),类别如何定义(“SUV”和“轿车”要不要分开?)。
- 制作标注规范文档:将会议确定的标准写成文档,并配上正确和错误的标注示例图。这份文档是后续质检的依据。
- 使用中间格式:让所有人都使用同一种工具(如Labelme)进行标注,输出原始格式(JSON)。由专人负责统一进行格式转换和质量检查。这样可以避免每个人环境不同导致的格式混乱。
- 定期质检与校准:负责人定期抽查每个人的标注结果,发现问题及时反馈和纠正,防止错误标注大面积扩散。
4.3 利用预标注与主动学习
对于已有初步模型的项目,可以采用更智能的流程:
- 预标注:用现有的、哪怕精度不高的模型,对未标注的图片进行推理,生成初步的标注框或掩膜。
- 人工修正:标注员只需要在这些预标注的结果上进行修改和确认,而不是从零开始画。这通常能节省50%以上的时间。
- 主动学习:将模型预测不确定度高的那些图片(例如,置信度在0.3-0.7之间的)优先交给人工标注。用最少的人工干预,最大化地提升模型性能。
EISeg的交互式标注本身就是一种“微型的主动学习”,它把模型的预测和人工的修正实时结合在一起。
4.4 质量控制与常见陷阱
即使流程再规范,标注错误也难以完全避免。以下是一些高频陷阱和检查方法:
- 标签错位:最常见的问题。检查方法是写一个简单的可视化脚本,把标注框画回原图上看是否对齐。
- 类别混淆:特别是相似类别(如“狼”和“哈士奇”)。需要质检员重点复核。
- 漏标:尤其是小目标。可以通过训练一个简单模型,用模型在验证集上的“假阴性”(False Negative)结果来反查可能漏标的物体。
- 标注不一致:同一物体在不同图片中,有的标得紧贴边缘,有的留了白边。这会影响模型学习边界的精度。需要在规范中明确边缘的处理方式。
我习惯在转换格式后,随机抽取5%-10%的标签文件,用可视化脚本快速过一遍。花半小时做这个检查,能避免后续几天模型训练走弯路。
说到底,数据标注是一项需要耐心和细心的工作,但它绝不是毫无技术含量的重复劳动。选择合适的工具,建立高效的流程,运用一些智能化的技巧,你就能把这块“绊脚石”变成项目快速推进的“垫脚石”。当你看到自己亲手标注的数据训练出的模型,在真实场景中稳定工作时,那种成就感,和调出一个好模型是完全不同的。
更多推荐


所有评论(0)