1. 为什么要在Win10上折腾Labelme
搞计算机视觉这行的,没人能绕开数据标注这个环节。不管你是做目标检测、语义分割还是实例分割,手头没有一批标注好的数据,模型再牛也跑不起来。Labelme就是在这个场景下被反复提起的一个工具——它是MIT开源的一款图像标注工具,支持多边形、矩形、圆形、线段、点等多种标注形式,输出的是JSON格式的标注文件,可以很方便地转换成COCO、VOC、YOLO等主流训练框架需要的格式。
我第一次接触Labelme是在一个语义分割项目里,当时手头有几百张场景图像需要做像素级标注,试过几个标注工具,要么是网页版上传数据不方便,要么是客户端功能太简陋。Labelme的本地化部署和灵活的多边形标注能力最终让我留了下来。这篇文章就是把我这些年在Win10环境下安装、配置、使用Labelme的经验完整梳理一遍,从环境准备到批量转换,从快捷键操作到踩过的坑,尽量讲透。
这篇文章适合谁看?如果你是刚入门计算机视觉的学生或者开发者,手头有标注任务但不知道从哪下手,这篇可以当操作手册用。如果你已经用过Labelme但总觉得效率不高,或者转换格式时老出问题,这篇里的实操细节和避坑经验应该能帮到你。我下面讲的所有操作都是在Win10环境下验证过的,Python版本以3.8到3.10为主,更高版本理论上兼容但个别依赖可能会有小问题,后面会具体说。
2. 安装前的环境准备与方案选型
2.1 Python环境的选择与版本考量
Labelme本质上是一个Python包,所以第一步得把Python环境搞定。Win10下装Python有好几种方式,我推荐用Miniconda或者Anaconda来管理环境,原因很简单:Labelme的依赖比较多,包括PyQt5、numpy、Pillow等,如果直接装在系统Python里,很容易和你其他项目的依赖打架。用conda创建一个独立环境,用完删掉就行,干净利落。
Python版本怎么选?Labelme官方在PyPI上发布的版本对Python的要求是3.6以上,但我实测下来,3.8到3.10是最稳的区间。3.11和3.12在某些PyQt5的wheel包上可能会遇到编译问题,尤其是你没有装Visual C++ Build Tools的时候,pip会尝试从源码编译,那个过程相当折磨。所以我的建议是直接用3.9或3.10,省心。
创建环境的命令如下:
conda create -n labelme python=3.9 conda activate labelme这两行下去,你就有了一个干净的Python 3.9环境。后面所有操作都在这个环境里进行,不会污染系统环境。
2.2 安装方式的对比:pip还是conda
Labelme的安装主要有两条路:pip install labelme或者conda install labelme。两者有什么区别?pip走的是PyPI源,版本更新更快,但依赖解析有时候会出问题;conda走的是conda-forge频道,依赖管理更严格,但版本可能滞后。
我个人的习惯是优先用pip,因为Labelme的GitHub仓库更新比较活跃,pip能拿到最新的修复。但如果你的网络环境访问PyPI比较慢,可以换国内镜像源:
pip install labelme -i https://pypi.tuna.tsinghua.edu.cn/simple如果你用conda安装,命令是:
conda install -c conda-forge labelme两种方式我都试过,功能上没差别,选一个能跑通的就行。有一点需要注意:不管你用哪种方式,安装完成后在命令行输入labelme,如果能看到GUI窗口弹出来,说明安装成功了。如果提示“不是内部或外部命令”,那多半是环境变量的问题,检查一下你的conda环境是否激活,或者Python的Scripts目录是否在PATH里。
2.3 安装过程中常见的依赖问题
安装Labelme时最容易卡住的地方是PyQt5。PyQt5是一个GUI框架,Labelme的界面全靠它。在Win10下,pip install PyQt5通常会直接下载预编译的wheel包,几百兆的大小,下载速度取决于你的网络。如果下载中断,重新执行pip install labelme即可,pip会断点续传。
另一个常见问题是numpy的版本冲突。如果你之前在这个环境里装过其他包,可能会有一个旧版本的numpy,Labelme要求numpy>=1.20,版本太低会报错。解决办法很简单:
pip install --upgrade numpy还有一个坑是Pillow的版本。Labelme处理图像依赖Pillow,某些旧版本在处理大尺寸图像时会内存溢出。建议直接装最新版:
pip install --upgrade Pillow注意:如果你在公司内网环境下安装,pip可能无法直接访问外网。这种情况下需要配置代理或者使用内网镜像源,具体方式取决于你所在网络的策略,这里不展开。
3. Labelme的核心功能与操作界面拆解
3.1 界面布局与核心功能区
第一次打开Labelme,你会看到一个不算复杂但功能齐全的界面。顶部是菜单栏,左边是工具栏,中间是图像显示区,右边是标注对象列表和标签列表。我逐个说一下各个区域的作用。
菜单栏里最常用的几个选项:File菜单下的Open Dir用于打开一个包含所有待标注图像的文件夹,Save Automatically建议勾选上,这样每标注完一张图切换到下一张时会自动保存,避免忘记保存导致工作白费。Edit菜单下的Undo和Redo就不用多说了,标注过程中画错了随时撤销。View菜单下可以调整亮度对比度,对于标注暗光图像很有用。
工具栏上的按钮从左到右依次是:打开文件、打开文件夹、上一张/下一张、保存、删除当前标注、创建多边形、创建矩形、创建圆形、创建线段、创建点、创建AI多边形(这个需要额外配置模型)、编辑标注、撤销、放大缩小、适应窗口。
右侧面板分两块:上面是当前图像中已经标注的多边形列表,每个多边形有一个标签和一组点坐标;下面是标签管理区,你可以在这里添加、删除、重命名标签,也可以给不同标签分配不同的颜色,方便视觉区分。
3.2 标注类型的选择逻辑
Labelme支持五种标注类型,每种适用于不同的任务场景。选错了标注类型,后面转换格式时会很麻烦,所以这里我把选择逻辑讲清楚。
多边形(Polygon):这是Labelme最核心的功能,用于语义分割和实例分割。你沿着目标物体的边缘逐点点击,最后回到起点闭合,就形成了一个多边形标注。适合标注不规则形状的物体,比如人、动物、道路、建筑物等。
矩形(Rectangle):用于目标检测任务,画一个框把目标框住就行。速度快,但精度不如多边形。如果你只是做检测任务,不需要像素级分割,用矩形就够了。
圆形(Circle):适用于标注圆形或近似圆形的物体,比如细胞、硬币、轮胎等。用两个点确定圆心和半径。
线段(Line):用于标注线性结构,比如车道线、裂缝、血管等。两个点确定一条线段。
点(Point):用于标注关键点,比如人脸关键点、人体姿态关键点等。单击一下就是一个点。
我个人的经验是:如果你的任务最终需要做分割,那就老老实实用多边形,虽然标注速度慢一些,但数据质量高。如果只是做检测,矩形完全够用,标注效率能提升好几倍。
3.3 快捷键体系与效率提升
Labelme的快捷键设计得相当合理,熟练之后标注速度能提升至少一倍。我把最常用的快捷键整理成表格:
| 快捷键 | 功能 | 使用场景 |
|---|---|---|
| Ctrl+O | 打开文件 | 打开单张图像 |
| Ctrl+U | 打开文件夹 | 打开整个目录 |
| Ctrl+S | 保存 | 手动保存当前标注 |
| Ctrl+Z | 撤销 | 撤销上一步操作 |
| Ctrl+Y | 重做 | 恢复撤销的操作 |
| D | 下一张 | 切换到下一张图像 |
| A | 上一张 | 切换到上一张图像 |
| W | 创建多边形 | 开始画多边形 |
| E | 编辑标注 | 修改已有标注 |
| Delete | 删除选中标注 | 删除当前选中的多边形 |
| Ctrl+滚轮 | 缩放 | 放大缩小图像 |
| Ctrl+0 | 适应窗口 | 图像缩放到合适大小 |
| Ctrl+Shift+滚轮 | 调整亮度 | 调整图像亮度 |
| Ctrl+Shift+滚轮 | 调整对比度 | 调整图像对比度 |
这些快捷键里,D和A是我用得最多的,标注完一张图直接按D切下一张,手不用离开键盘。W和E配合使用,画完一个多边形按E进入编辑模式微调顶点位置,再按W继续画下一个。
提示:Labelme默认的快捷键可以在设置里修改,如果你觉得某个键位不顺手,可以在Edit菜单下的Preferences里调整。
4. 从零开始完成一次完整标注任务
4.1 数据准备与目录组织
在开始标注之前,先把数据整理好。我建议的目录结构是这样的:
dataset/ ├── images/ # 存放所有待标注的图像 │ ├── 001.jpg │ ├── 002.jpg │ └── ... ├── labels/ # 存放标注生成的JSON文件 └── labels_converted/ # 存放转换后的格式文件把所有待标注图像放在images文件夹里,Labelme打开这个文件夹后会自动加载所有图像。标注生成的JSON文件默认和图像在同一目录,你可以在保存时指定到labels文件夹,或者标注完成后统一移动。
图像格式方面,Labelme支持JPG、PNG、BMP、TIFF等常见格式。如果你的图像是TIFF格式且包含多通道,Labelme可能无法正确显示,建议先转换成PNG或JPG。图像尺寸方面,Labelme对超大图像(比如超过10000像素)的处理会比较卡,如果手头有这样的图像,建议先切分再标注。
4.2 标注流程的详细操作步骤
打开Labelme后,点击Open Dir选择你的images文件夹。界面左侧会显示图像列表,点击任意一张开始标注。
第一步,观察图像,确定需要标注的目标类别。比如你在做一个街景分割任务,需要标注人、车、道路、建筑、树木等类别。在右侧标签管理区添加这些标签,每个标签分配一个颜色。
第二步,按W键进入多边形绘制模式。沿着目标物体的边缘逐点点击,点与点之间的距离不要太远,否则边缘会不够精确。对于曲线边缘,点要密一些;对于直线边缘,两个端点就够了。画完一圈后,点击起点闭合多边形,或者直接按Enter键闭合。
第三步,闭合后会弹出一个对话框让你选择标签。选择对应的标签,这个多边形就标注完成了。如果标签列表里没有你想要的,可以直接在对话框里输入新标签名,Labelme会自动添加到标签列表。
第四步,重复第二步和第三步,把图像中所有需要标注的目标都标完。一张图可能有几十个甚至上百个目标,耐心是关键。
第五步,按Ctrl+S保存,或者如果开启了自动保存,直接按D切换到下一张。JSON文件会保存在图像同目录下,文件名和图像名一致,后缀是.json。
4.3 标注质量的自我检查方法
标注完成后,怎么检查质量?我通常用几个方法。
一是视觉检查。在Labelme里按E进入编辑模式,逐个点击多边形,看看顶点是否贴合物体边缘。如果发现某个顶点偏了,拖动它调整位置。如果整个多边形都偏了,可以整体拖动。
二是用脚本检查。写一个简单的Python脚本,读取JSON文件,统计每个标签的多边形数量和面积占比。如果某个标签的数量明显异常(比如一张图里出现了几百个“人”),那多半是标注时误操作了。
import json import os from collections import Counter label_dir = "labels" label_counter = Counter() for json_file in os.listdir(label_dir): if not json_file.endswith(".json"): continue with open(os.path.join(label_dir, json_file), "r", encoding="utf-8") as f: data = json.load(f) for shape in data["shapes"]: label_counter[shape["label"]] += 1 for label, count in label_counter.most_common(): print(f"{label}: {count}")这个脚本能快速统计所有标注文件中各个标签的出现次数,帮你发现异常。
三是可视化检查。把JSON文件转换成掩膜图像,叠加在原图上,直观地看标注是否准确。这个后面讲转换格式时会提到。
5. 标注文件的格式转换与批量处理
5.1 JSON格式的结构解析
Labelme生成的JSON文件结构其实很简单,我拿一个实际例子来说明:
{ "version": "5.3.1", "flags": {}, "shapes": [ { "label": "person", "points": [[100, 200], [150, 200], [150, 300], [100, 300]], "group_id": null, "shape_type": "polygon", "flags": {} } ], "imagePath": "001.jpg", "imageData": null, "imageHeight": 480, "imageWidth": 640 }关键字段说明:shapes是一个列表,每个元素代表一个标注对象;label是标签名;points是多边形的顶点坐标列表,每个点是[x, y]格式;shape_type是标注类型,可以是polygon、rectangle、circle、line、point;imagePath是图像文件名;imageHeight和imageWidth是图像尺寸。
注意imageData字段,如果它是null,说明JSON文件里没有嵌入图像数据,只保存了标注信息。如果它是一长串base64编码的字符串,说明图像数据被嵌入了JSON文件,这会导致JSON文件体积很大。Labelme默认不嵌入图像数据,但如果你在设置里勾选了“Save Image Data”,就会嵌入。我建议不要勾选,保持JSON文件轻量。
5.2 转换为COCO格式的完整方案
COCO格式是目标检测和实例分割最常用的格式之一,很多训练框架都支持。Labelme官方提供了一个转换脚本labelme2coco.py,但那个脚本功能比较基础,我一般自己写一个更灵活的版本。
转换的核心逻辑是:遍历所有JSON文件,把每个多边形的顶点坐标转换成COCO的segmentation格式,同时计算边界框。下面是一个完整的转换脚本:
import json import os import numpy as np from PIL import Image def labelme_to_coco(json_dir, image_dir, output_file): coco = { "info": {}, "licenses": [], "images": [], "annotations": [], "categories": [] } categories = {} annotation_id = 1 json_files = [f for f in os.listdir(json_dir) if f.endswith(".json")] for image_id, json_file in enumerate(json_files, start=1): json_path = os.path.join(json_dir, json_file) with open(json_path, "r", encoding="utf-8") as f: data = json.load(f) image_name = data["imagePath"] height = data["imageHeight"] width = data["imageWidth"] coco["images"].append({ "id": image_id, "file_name": image_name, "height": height, "width": width }) for shape in data["shapes"]: label = shape["label"] points = shape["points"] if label not in categories: categories[label] = len(categories) + 1 coco["categories"].append({ "id": categories[label], "name": label, "supercategory": "" }) xs = [p[0] for p in points] ys = [p[1] for p in points] x_min, x_max = min(xs), max(xs) y_min, y_max = min(ys), max(ys) segmentation = [coord for point in points for coord in point] area = (x_max - x_min) * (y_max - y_min) coco["annotations"].append({ "id": annotation_id, "image_id": image_id, "category_id": categories[label], "segmentation": [segmentation], "bbox": [x_min, y_min, x_max - x_min, y_max - y_min], "area": area, "iscrowd": 0 }) annotation_id += 1 with open(output_file, "w", encoding="utf-8") as f: json.dump(coco, f, ensure_ascii=False, indent=2) print(f"转换完成,共处理 {len(json_files)} 张图像,{annotation_id - 1} 个标注") labelme_to_coco("labels", "images", "coco_annotations.json")这个脚本会生成一个标准的COCO格式JSON文件,可以直接用于训练。注意area的计算方式,我这里用的是边界框面积,如果你需要精确的多边形面积,可以用shapely库来计算。
5.3 转换为YOLO格式的注意事项
YOLO格式和COCO格式差别很大。YOLO需要的是归一化的中心点坐标和宽高,每个图像对应一个txt文件,每行一个目标,格式是:类别索引 中心x 中心y 宽 高。
转换时需要注意几点:一是类别索引要从0开始连续编号,不能有跳号;二是坐标要归一化到0到1之间,除以图像宽高;三是YOLO不支持多边形,如果你的标注是多边形,需要先转成边界框。
import json import os def labelme_to_yolo(json_dir, output_dir, class_list): os.makedirs(output_dir, exist_ok=True) class_to_idx = {name: idx for idx, name in enumerate(class_list)} for json_file in os.listdir(json_dir): if not json_file.endswith(".json"): continue with open(os.path.join(json_dir, json_file), "r", encoding="utf-8") as f: data = json.load(f) height = data["imageHeight"] width = data["imageWidth"] lines = [] for shape in data["shapes"]: label = shape["label"] if label not in class_to_idx: continue points = shape["points"] xs = [p[0] for p in points] ys = [p[1] for p in points] x_min, x_max = min(xs), max(xs) y_min, y_max = min(ys), max(ys) cx = (x_min + x_max) / 2 / width cy = (y_min + y_max) / 2 / height w = (x_max - x_min) / width h = (y_max - y_min) / height lines.append(f"{class_to_idx[label]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}") txt_name = json_file.replace(".json", ".txt") with open(os.path.join(output_dir, txt_name), "w") as f: f.write("\n".join(lines)) labelme_to_yolo("labels", "labels_yolo", ["person", "car", "road"])这个脚本会把每个JSON文件转换成一个同名的txt文件,放在labels_yolo目录下。class_list需要你根据实际标注的类别来定义,顺序要和训练时的类别顺序一致。
6. 常见问题排查与避坑经验
6.1 安装与启动阶段的典型问题
问题一:pip install labelme报错“Microsoft Visual C++ 14.0 is required”
这个错误通常出现在Python 3.11以上版本,因为某些依赖包没有预编译的wheel,pip尝试从源码编译,需要C++编译器。解决办法有两个:一是降级到Python 3.9或3.10,二是安装Visual C++ Build Tools。我推荐第一个方案,省事。
问题二:启动labelme后界面显示乱码
这是PyQt5的字体问题,在Win10下偶尔会出现。解决办法是在启动前设置环境变量:
set QT_AUTO_SCREEN_SCALE_FACTOR=1 labelme或者在Python代码里设置:
import os os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"问题三:打开文件夹后图像列表为空
检查文件夹路径是否包含中文或特殊字符。Labelme对中文路径的支持不太好,建议把图像放在纯英文路径下。另外,确认图像格式是Labelme支持的格式,比如JPG、PNG、BMP。
6.2 标注过程中的操作问题
问题四:画多边形时点错了位置,怎么撤销?
按Ctrl+Z可以撤销上一个点。如果已经闭合了多边形,按Ctrl+Z可以撤销整个多边形。注意撤销的层级,Labelme的撤销栈是全局的,不只是针对当前多边形。
问题五:标注完发现标签名写错了,怎么批量修改?
Labelme本身没有批量修改标签的功能,但你可以直接编辑JSON文件。用文本编辑器打开JSON文件,把错误的标签名替换成正确的,保存即可。如果文件很多,写个Python脚本批量替换:
import json import os def rename_label(json_dir, old_label, new_label): for json_file in os.listdir(json_dir): if not json_file.endswith(".json"): continue path = os.path.join(json_dir, json_file) with open(path, "r", encoding="utf-8") as f: data = json.load(f) changed = False for shape in data["shapes"]: if shape["label"] == old_label: shape["label"] = new_label changed = True if changed: with open(path, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) print(f"已修改: {json_file}") rename_label("labels", "persn", "person")问题六:标注大图像时界面卡顿
Labelme在处理超过4000x4000像素的图像时会明显卡顿。解决办法是在标注前把图像缩小到合适尺寸,标注完成后再把坐标映射回原始尺寸。或者用Labelme的“Fit Window”功能,让图像适应窗口大小,减少渲染压力。
6.3 格式转换中的高频错误
问题七:转换后的COCO格式在训练时报“segmentation格式错误”
COCO的segmentation字段要求是列表的列表,每个子列表是一个多边形的坐标序列。如果你直接传了一个扁平的坐标列表,就会报错。检查你的转换脚本,确保segmentation是[[x1, y1, x2, y2, ...]]这种嵌套结构。
问题八:YOLO格式的类别索引和训练配置不一致
YOLO训练时需要指定类别数量和类别名称文件。如果你的转换脚本里类别索引是从0开始的,但训练配置里写的是从1开始,就会导致类别错乱。建议在转换前先确定好类别列表,转换脚本和训练配置用同一个列表。
问题九:JSON文件中的imagePath和实际文件名不一致
有时候你移动了图像文件,但JSON文件里的imagePath还是旧路径。转换格式时如果依赖imagePath来匹配图像,就会找不到文件。解决办法是在转换脚本里用JSON文件名来匹配图像,而不是用imagePath字段。
6.4 常见问题速查表
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| 安装时报C++编译错误 | Python版本过高 | 降级到3.9或3.10 |
| 启动后界面乱码 | 字体缩放问题 | 设置QT_AUTO_SCREEN_SCALE_FACTOR=1 |
| 打开文件夹无图像 | 路径含中文或格式不支持 | 改用英文路径,转换图像格式 |
| 标注时卡顿 | 图像尺寸过大 | 缩小图像或使用Fit Window |
| 转换后训练报错 | 格式不符合要求 | 检查segmentation嵌套结构 |
| 类别索引错乱 | 转换和训练配置不一致 | 统一类别列表 |
| JSON文件过大 | 嵌入了图像数据 | 关闭Save Image Data选项 |
7. 提升标注效率的进阶技巧
7.1 预标注与半自动标注思路
纯手工标注几百张图像是一件很痛苦的事。我后来摸索出一个半自动的流程:先用一个预训练模型对图像做推理,把推理结果转换成Labelme的JSON格式,然后在Labelme里加载这些JSON文件,人工只需要修正错误的标注,而不是从零开始画。这个流程能把标注效率提升三到五倍。
具体做法是:用YOLO或Mask R-CNN等模型对图像做推理,得到边界框或多边形,然后写一个脚本把推理结果转换成Labelme的JSON格式。转换时注意坐标格式要和Labelme一致,shape_type设为polygon或rectangle,label设为模型预测的类别名。
import json def create_labelme_json(image_path, image_height, image_width, detections): data = { "version": "5.3.1", "flags": {}, "shapes": [], "imagePath": image_path, "imageData": None, "imageHeight": image_height, "imageWidth": image_width } for det in detections: shape = { "label": det["label"], "points": det["points"], "group_id": None, "shape_type": "polygon", "flags": {} } data["shapes"].append(shape) return data这个思路的关键是预标注模型的精度要过得去,如果模型预测得一塌糊涂,人工修正的时间可能比重新标注还长。建议用一个在你数据分布上表现还不错的模型来做预标注。
7.2 多人协作标注的目录管理
如果标注任务量大,需要多人协作,目录管理就很重要。我通常这样组织:
project/ ├── raw_images/ # 原始图像,只读 ├── annotator_A/ # 标注员A的工作目录 │ ├── images/ # 软链接或复制一份图像 │ └── labels/ # A标注的JSON文件 ├── annotator_B/ # 标注员B的工作目录 │ ├── images/ │ └── labels/ └── merged_labels/ # 合并后的标注文件每个标注员在自己的目录里工作,互不干扰。标注完成后,把labels文件夹合并到merged_labels里。合并时要注意文件名冲突,如果两个标注员标了同一张图,需要决定保留哪一份或者做交叉验证。
7.3 标注规范的制定与执行
多人协作时,标注规范不统一是最大的坑。比如“人”这个类别,有人标了全身,有人只标了上半身;有人把被遮挡的人也算上,有人不算。这些不一致会直接影响模型训练效果。
我的建议是在标注开始前,先制定一份详细的标注规范文档,包括:每个类别的定义和边界、遮挡情况的处理方式、最小标注尺寸、是否标注截断目标等。然后找几张典型图像做试标,所有人一起讨论,统一标准后再全面铺开。
提示:标注规范不是一成不变的,标注过程中如果发现新的边界情况,及时补充到规范里,并通知所有标注员。
8. 我踩过的那些坑与最后的小技巧
说几个我实际踩过的坑,希望能帮你省点时间。
第一个坑是自动保存。Labelme的自动保存默认是关闭的,我有一次标了整整一个下午,结果软件崩溃,所有工作白费。从那以后我第一件事就是打开自动保存,并且养成按Ctrl+S的习惯。另外,Labelme在切换图像时会自动保存当前标注,但如果你直接关闭窗口,可能来不及保存,所以关闭前手动按一下Ctrl+S。
第二个坑是标签名的大小写。Labelme的标签是区分大小写的,“Person”和“person”会被当成两个不同的类别。转换格式时如果没注意,就会多出一个类别。建议在标注前统一标签命名规范,全部用小写或者全部用驼峰,别混着来。
第三个坑是JSON文件的编码。Labelme默认用UTF-8编码保存JSON文件,但如果你用某些文本编辑器打开后另存为其他编码,再加载时就会报错。建议不要手动编辑JSON文件,如果非要编辑,确保保存为UTF-8编码。
最后分享一个小技巧:Labelme支持在标注时按Ctrl+Shift+滚轮调整图像的亮度和对比度。这个功能在标注暗光或者过曝图像时特别有用,能让你看清物体边缘。调整后的显示效果不会影响原始图像,只是临时改变显示,放心用。
还有一个技巧是善用“编辑标注”模式。按E进入编辑模式后,你可以拖动多边形的顶点来微调形状,也可以在边上双击添加新顶点,或者右键删除顶点。对于边缘复杂的物体,先粗略画一个多边形,再进入编辑模式精修,比一次性画准要快得多。
这个工具本身不复杂,但细节很多,用熟了之后标注效率会有质的提升。希望这篇东西能帮你少走点弯路。