1. 项目背景与整体方案设计1.1 为什么用Labelme做数据标注做深度学习方向的项目尤其是语义分割、目标检测、实例分割这几类任务逃不开一个环节给图片画框或者画轮廓。市面上的标注工具有很多像LabelImg、CVAT、RectLabel、SuperAnnotate但我个人在本地小规模数据集上最常用的还是Labelme。Labelme是麻省理工学院计算机科学与人工智能实验室开源的图像标注工具基于Python编写。它最大的特点就是灵活。标注结果直接落盘为JSON文件JSON本身就是一种通用性极强的数据交换格式你可以在后端随意解析、转换成自己需要的格式。不管你是要做二分类的分割mask还是做目标检测的bounding box甚至做OCR场景的文字框标注Labelme都能胜任。另一个选它的理由是轻量。它不需要部署服务端不需要注册账号不需要联网pip安装后本地启动就能干活。对于个人开发者、学生党、小团队来说这是最省事的一条路径。这个标题之所以把标注和json生成Ground Truth放在一起是因为很多新手卡在了后半段标注完成了json文件也有了但不知道如何把json里的坐标信息变成模型训练真正需要的label文件。我在实际项目中见过太多同学拿着一张全黑的mask图来问为什么训练不了。所以这篇文章的重点会放在json转Ground Truth的完整流程上把每一个坑都摊开讲。适合谁来读如果你准备用自己的图片训练一个分割模型或者想给数据集加上像素级标注又或者已经用Labelme标注了一部分数据但不知道怎么转成mask这篇文章可以帮你省下一两天的摸索时间。1.2 数据集的目录规划与命名规范动手标注之前我强烈建议先规划好目录结构。很多人在标注到一半的时候才想起来文件管理混乱返工成本非常高。推荐的结构是这样的dataset/ ├── images/ # 原始图片所有待标注图片放在这里 ├── labels/ # Labelme生成的json文件 ├── masks/ # 转换后的Ground Truth mask图 └── config/ └── labels.txt # 类别标签清单每个目录的作用非常明确images放原图labels放标注结果masks放最终生成的训练文件。这个结构一眼就能看懂将来做拆分训练集、验证集的时候也方便操作。命名规范上有两点必须提醒。第一图片文件名不要含中文和空格尽量用序号或者英文命名比如img_001.jpg。原因是Labelme保存的json里会记录文件名如果文件名带中文后面做数据读取时会有编码问题。第二json文件名会自动和图片名保持一致所以不要在标注过程中随意改文件名否则json和图片对不上到时候解析会报错。还有一个容易忽略的细节如果在标注过程中发现图片本身有问题模糊、重复、内容错误要么直接删除并在标注进度表里标记要么先把图片移出images目录再重新拷贝一张新图片进入。不要直接在原目录里覆盖同名文件因为Labelme的json里记录的图片路径是相对的覆盖后json的内容可能和图片对不上。1.3 标注目标类型的选择分割、检测、还是OCRLabelme支持的标注形状包括多边形、矩形、圆形、线段、点。你在开始之前就要想清楚你最终要的是什么任务类型语义分割用多边形Polygon标注出目标的轮廓最后生成像素级的mask。目标检测用矩形Rectangle标注目标的边界框转换成YOLO或VOC格式的txt/xml。实例分割也是用多边形但每个目标单独标注mask中每个实例的像素值不同。OCR检测用矩形框或四边形框标注文字区域配合识别任务使用。关键点检测用点标注关键位置比如人脸关键点、人体骨架点。不同的任务对应不同的Ground Truth格式。我们这篇文章主要聚焦在分割任务上也就是把JSON转换成像素级的mask图因为这是Labelme最典型的应用场景。2. 环境准备与Labelme安装全流程2.1 安装Python与基础环境Labelme是Python包所以第一步是确保你的机器上有可用的Python环境。我建议使用Python 3.8到3.10版本我自己在3.9和3.10上都跑得很稳。如果你没装Python去官网下载安装包安装时注意把Add Python to PATH勾选上这个是很多新手栽跟头的地方。安装完成后可以在命令行里验证python --version pip --version能正常输出版本号说明环境OK。有条件的强烈建议用虚拟环境避免污染系统级的Python环境。我习惯的做法是python -m venv labelme_env # Windows激活 labelme_env\Scripts\activate # Linux/Mac激活 source labelme_env/bin/activate虚拟环境相当于在你的机器里开辟一个独立的隔间里面装什么包都不影响外面。我遇到过太多次因为globally安装包版本冲突导致的项目崩溃用虚拟环境后这种问题基本绝迹了。2.2 Labelme安装与启动安装Labelme本身很简单pip install labelme但如果你在国内网络环境下直接pip install大概率会遇到下载超时。这种情况有两个解决办法一是用清华镜像源pip install labelme -i https://pypi.tuna.tsinghua.edu.cn/simple二是如果系统提示某个依赖包需要编译导致安装失败可以先检查一下是不是需要安装特定版本的pyqt5_sip。我整理过一套最稳的安装组合pip install pyqt55.15.10 -i https://pypi.tuna.tsinghua.edu.cn/simple pip install labelme5.5.1 -i https://pypi.tuna.tsinghua.edu.cn/simple这个组合我实测在Windows 11、Windows 10、Ubuntu 20.04上都能正常启动。装完以后命令行输入labelme正常的话会弹出Labelme的主界面。如果弹不出来大概率是PyQt5的库冲突或者显卡驱动兼容问题后面常见问题部分我会专门说。启动之后在菜单栏File里选择Open Dir打开你的images文件夹就可以开始标注了。建议同时打开File - Save As设置json保存路径指向labels目录。2.3 配置类别清单文件很多教程不会提这点但我强烈建议你在标注前先写好categories文件。Labelme支持进入标注模式时选择一个标签label如果标签列表是空的你每次都要手动输入一个名字非常影响效率。在config目录下创建一个labels.txt内容大概是__ignore__ _background_ person car dog这里有个小细节Labelme会自动把__ignore__和_background_当作特殊标签处理。你可以不写这两个但在我们自己写转换脚本的时候背景就是像素值为0的部分所以上面这个清单里的_background_其实对应mask里的0值区域后面的类别从1开始编号。后续转换脚本里用到的类别列表是以此为准的。3. 标注实操与重要细节3.1 多边形标注的基本操作启动Labelme之后点击左侧工具栏的Create Polygons按钮然后用鼠标左键在图像上逐一单击勾勒出目标轮廓。每单击一个点多边形就会多一个顶点轮廓自然会跟着成形。勾勒完整个目标边缘后回到起点附近双击或点击右键就会弹出标签选择框。选择对应的类别标注就完成了。标注过程中你会用到一些高频快捷键CtrlZ撤销上一个标注点对就是用来撤销点错的CtrlS保存当前图片的标注生成jsonCtrlD复制当前标注到下一张图片适合多张图片里有相同目标的情况Delete删除当前选中的标注多边形实操中有一个小技巧标注轮廓时不要贪婪地打特别多的点来描边。点的数量越多json文件越大而且模型训练时处理多边形坐标的开销也越大。对于大多数目标几十个点已经能勾勒出很光滑的轮廓了。锚点太少会导致形状失真锚点太多会引入标注噪声我的经验是在曲线变化大的地方加密在直线部分少点。3.2 一张图多个目标的处理方式一个图像里通常会有多个目标比如道路场景里同时有行人、汽车、红绿灯。你可以连续创建多个多边形每个目标独立标注标签可以相同比如三辆车都标成car也可以不同。语义分割任务中同一类别的多个目标最终在mask里的像素值是一样的实例分割任务中则需要区分开每个目标。区分方式有两种一种是在json转mask的时候把每个多边形当成独立的连通域编号另一种是使用Labelme自带的group_id字段。给同类别目标设置不同group_id的方法如下标注完第一个多边形后在左侧的Label List面板中右键点击该标签选择Edit Group ID。如果所有目标都要区分就把1、2、3这样递增的编号填进去。这步很有用尤其当你后面要跑Mask R-CNN这类实例分割模型时Ground Truth就需要区分每个实例。如果你明确做的是语义分割那就不用管group_id直接生成单通道mask图即可。3.3 整个标注过程中最容易翻车的细节第一标注必须闭合。Labelme的多边形在做json转换时底层会去读每个多边形区域的顶点列表然后用类似多边形填充的方式生成区域。如果你标注的轮廓有交叉或者没闭合填充出来的区域会和你预期的完全不一样。第二留意图片原始尺寸。后续json转mask的时候图像尺寸必须和原图一致。如果你把原图缩放后再标注json里只存了多边形顶点坐标不会自动做等比缩放转换出来的mask就会错位。标注时的图片尺寸要原封不动地用于转换。第三保存json后顺手检查一下文件大小。如果一张图标注完成后的json居然只有几百字节十有八九是保存出了问题或者多边形数据没有正常写入。打开json看看里面一般会包含imageData字段图片的base64以及shapes数组。一个正常的多边形标注json通常在几KB到几十KB不等具体取决于图片大小和标注复杂度。4. 解析Labelme生成的JSON结构4.1 JSON文件的字段含义打开一个标注好的json大概是下面这个样子{ version: 5.5.1, flags: {}, shapes: [ { label: car, points: [ [323.5, 210.0], [425.2, 213.0], [485.1, 312.5], [310.3, 320.2] ], group_id: null, shape_type: polygon, flags: {} } ], imagePath: img_001.jpg, imageData: /9j/4AAQSkZJRgABAQAAAQABAAD..., imageHeight: 1080, imageWidth: 1920 }各字段的含义我整理成了表格字段含义是否必用versionLabelme版本号可选flags图片级全局标签按需shapes标注对象数组每个元素是一个标注多边形核心shapes[].label当前多边形的类别标签核心shapes[].points多边形顶点坐标格式是[[x1,y1],[x2,y2],...]核心shapes[].group_id分组ID用于区分实例可选shapes[].shape_type形状类型通常是polygon/rectangle/circle/line核心imagePath图片文件名相对路径核心imageData图片的base64编码字符串可选imageHeight/imageWidth图片的高宽参考imageData字段是最大的坑。这个字段是base64编码的整张原始图片会占很多额外空间。如果你用Labelme生成、不做任何处理就丢给团队使用这个字段会让手头的json文件极大。而转换Ground Truth时其实基本不需要它只要知道图片路径和shapes里的坐标就够了。如果确实想让json瘦身可以在标注时用Labelme的File - Save Automatically选项并配合把图像数据从json中去掉的方式比如保存成不包含imageData的精简模式。但这个操作会丢失json自包含的信息一旦照片移动位置就找不到原图了。我个人习惯保留imageData毕竟目前磁盘不稀缺但如果你正在做一个超大数据集建议尽早制定精简策略。4.2 坐标体系的说明Points数组里的坐标是相对原图的像素坐标以图片左上角为原点x轴向右y轴向下。这和大多数图像处理库保持一致所以在用OpenCV或者numpy进行处理时不需要做坐标转换。注意这里的坐标是浮点数代表标注时鼠标所在的亚像素位置。转换成mask的时候用整数坐标填充区域即可不会有精度损失。这个概念对后续生成mask非常关键因为很多人会纠结json里的坐标是小数是不是需要精度处理其实完全不用。5. JSON转Ground Truth的完整代码实现5.1 单张JSON转二值Mask的工具方法现在到关键环节了。用一个Python脚本把单个json转成单通道mask图。我先把完整的核心函数写出来再逐行解释。import json import numpy as np import cv2 from PIL import Image import os # 定义类别映射表注意顺序背景固定为0 CLASS_MAPPING { background: 0, person: 1, car: 2, dog: 3 } def json_to_mask(json_path, output_mask_path, class_mappingNone): 将Labelme的json文件转换为单通道语义分割mask图 json_path: json文件路径 output_mask_path: 输出mask的路径png格式 class_mapping: 类别名字到像素值的映射字典如果为None则使用内置默认 if class_mapping is None: class_mapping CLASS_MAPPING with open(json_path, r, encodingutf-8) as f: label_data json.load(f) # 获取图像尺寸 height label_data[imageHeight] width label_data[imageWidth] # 创建全0的mask背景自动为0 mask np.zeros((height, width), dtypenp.uint8) shapes label_data[shapes] for shape in shapes: # 仅处理多边形如果想兼容矩形可加别的分支 if shape[shape_type] ! polygon: print(f警告跳过 {shape[shape_type]} 类型的标注) continue label_name shape[label] if label_name not in class_mapping: print(f警告标签 {label_name} 未在类别映射表中已跳过) continue class_value class_mapping[label_name] # 将坐标转换成整数形式 points np.array(shape[points], dtypenp.int32) # 用OpenCV填充多边形区域 cv2.fillPoly(mask, [points], colorclass_value) # 保存为png格式避免jpg压缩带来的像素值漂移 cv2.imwrite(output_mask_path, mask) return mask这个函数的核心逻辑并不复杂读取json、获取图像尺寸、创建全零mask、遍历所有多边形并填充对应类别的像素值。为什么要用dtypeuint8因为大多数分割模型的标签图都是单通道8位图类别数不超过255时完全够用。如果类别数超过255一般不可能可以改用uint16。为什么保存为png而不是jpg因为jpg是有损压缩格式会在像素级别产生微小的颜色偏移这对普通图片无所谓但对mask图是致命的。试想你把像素值255的背景压缩成了254模型的交叉熵损失直接爆炸。PNG是无损压缩保存像素值不会有一丝一毫的改变。fillPoly之后多边形内部值被设置为class_value外部保持0。多个多边形重叠时后画的会覆盖先画的。如果你的数据集里存在遮挡关系建议在后标注的目标后画这样在mask中它才能压住被遮挡目标的像素。5.2 批量转换目录下所有JSON单张函数写好后批量处理是水到渠成的事。下面这段脚本遍历labels目录下的所有json生成对应的mask图到masks目录def batch_json_to_mask(labels_dir, masks_dir, class_mappingNone): 批量将labels目录下的所有json文件转换成mask图 os.makedirs(masks_dir, exist_okTrue) for filename in os.listdir(labels_dir): if not filename.endswith(.json): continue json_path os.path.join(labels_dir, filename) mask_name filename.replace(.json, .png) output_mask_path os.path.join(masks_dir, mask_name) print(f正在处理{filename}) try: json_to_mask(json_path, output_mask_path, class_mapping) except Exception as e: print(f处理失败 {filename}{e}) continue print(批量转换完成) if __name__ __main__: labels_dir dataset/labels masks_dir dataset/masks batch_json_to_mask(labels_dir, masks_dir)这里有一个非常有必要的设计每个文件用try-except包裹。因为标注的过程中可能有个别json损坏如果不用try-except一个文件出错整个脚本就崩了。加上try-except至少能保证其他好的文件正常处理损坏的文件会被记录到日志里回头单独排查。批量转换完成后可以用一小段代码快速验证mask是否和原图对得上def visualize_overlay(image_path, mask_path, alpha0.5): image cv2.imread(image_path) mask cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE) # 生成彩色mask便于可视化 colored_mask np.zeros((mask.shape[0], mask.shape[1], 3), dtypenp.uint8) colored_mask[mask 1] [0, 0, 255] # 类别1红色 colored_mask[mask 2] [0, 255, 0] # 类别2绿色 colored_mask[mask 3] [255, 0, 0] # 类别3蓝色 overlay cv2.addWeighted(image, 1 - alpha, colored_mask, alpha, 0) cv2.imshow(overlay, overlay) cv2.waitKey(0)这个可视化步骤非常推荐每转一小批就抽查几张看mask是否和原图轮廓吻合。很多看起来没有问题的地方实际错误就藏在细节里。5.3 多类别合并与RLE编码处理实际项目里除了生成单通道mask还可能需要RLE编码。RLERun-Length Encoding是COCO数据集使用的编码方式它用长度 像素值的方式压缩二值mask比PNG存储更紧凑。看一个简单的RLE编码样例import numpy as np def mask_to_rle(mask): 将二值mask0/1转换为COCO格式的RLE 输入: 二维数组值为0或1 输出: RLE字典包含size和counts flattened mask.flatten(orderF) # 按列优先展平与COCO一致 counts [] current_val flattened[0] run_length 1 for value in flattened[1:]: if value current_val: run_length 1 else: counts.append(current_val) counts.append(run_length) current_val value run_length 1 counts.append(current_val) counts.append(run_length) # 如果第一个元素不是0需要在counts前面加0因为COCO规定必须从0开始 if counts[0] ! 0: counts [0] counts rle {size: [mask.shape[0], mask.shape[1]], counts: counts} return rleRLE编码要求按列优先展开这和平时习惯的行优先展开不一样经常有人在这里出错。如果你要做COCO格式的数据集必须用列优先否则验证mAP的时候会莫名其妙所有指标都是0。当然实际项目中更推荐直接用pycocotools自带的mask转换工具它对边缘情况的处理比我上面这个简易版本要严谨得多。但是理解手动实现的过程能帮你更清楚COCO RLE的底层逻辑。6. 实操过程中遇到的高频问题与排查思路6.1 安装运行时的高频错误问题1pip install labelme总是卡在PyQt5相关依赖上现象安装过程中提示ERROR: Could not build wheels for pyqt5-sip或者干脆超时。原因PyQt5在部分Python版本和系统环境下没有预编译的wheel包需要本地源码编译但编译环境又缺东西。解决办法先单独固定版本安装pyqt5库再装labelmepip install pyqt55.15.10 -i https://pypi.tuna.tsinghua.edu.cn/simple pip install labelme5.5.1 -i https://pypi.tuna.tsinghua.edu.cn/simple如果还报错试试升级pip和setuptoolspython -m pip install --upgrade pip setuptools wheel问题2输入labelme后弹窗报错Failed to load platform plugin xcb现象这个问题多发于Linux环境。启动时Qt找不到图形平台插件。解决办法通常是缺少X11相关的依赖库。以Ubuntu为例sudo apt-get install libxcb-xinerama0如果屏幕分辨率有缩放问题可以设置环境变量export QT_AUTO_SCREEN_SCALE_FACTOR1 labelme问题3标注过程中点击保存json文件是空的现象json文件存在但打开是{}或者只含有version字段。原因常见的原因是保存时没有选中任何已标注的多边形或者程序在写入前崩溃了。排查建议标注完一张图后先检查左侧Label List里是否有内容再点保存。养成标注完立刻保存的习惯并且设置File - Save Automatically让Labelme在切换图片时自动保存能大幅降低丢失标注数据的概率。6.2 转换阶段常见问题的排查转换阶段的问题我整理了下面这份排查速查表现象可能原因解决方案生成的mask全黑类别映射表里没有对应label或填充颜色值被设为0检查class_mapping里是否包含了json中所有label确认类别值从1开始编号mask轮廓和原图错位标注后图片尺寸被修改过重新检查json中的imageWidth和imageHeight是否与当前图片一致不一致时按当前图片尺寸重标多边形填充后区域有空洞多边形自相交或顶点顺序混乱删除该多边形用Labelme重新标注注意顶点顺序应为顺时针或逆时针不能有交叉转换报错KeyError: shapes保存的json是不完整文件检查json文件大小重标这张图多类别mask分割识别不了背景背景像素值设置错误确认背景像素值为0前景从1开始转换后无法用cv2.imshow查看窗口不同可能会无法显示大图改用PIL打开或者把mask缩小后再显示内存不足超大图片或超大json分批转换或先缩放原图到统一尺寸后再标注合并两个mask时值被覆盖两张mask使用了相同的类别编号合并前检查类别映射表是否有冲突6.3 多类别场景下常见的值冲突问题这里有一个非常典型案例。你标注了一个数据集里面有两个labelperson和riding_person。你原本把person映射为1riding_person映射为2。但你后来又有一个场景需要把两者合并成一个类别直接在映射表里把riding_person改成1。这时候只要这两张mask没有同时出现单看没问题一旦某张图里两个类别共存riding_person就会覆盖person的像素整个mask会错乱。解决办法是类别映射表一旦确定就不要中途随意改动。如果非要合并务必重新跑一遍转换脚本而不是靠后处理去修补mask。另外一个常见坑是OpenCV读取PNG时默认是BGR通道而mask是单通道灰度图用cv2.imread读mask时要加上cv2.IMREAD_GRAYSCALE参数。如果用默认参数读mask会被读成三通道后续和你写的处理代码维度对不上。6.4 如何快速定位损坏的JSON文件批量转换时我建议打印出每一个处理的文件名这样一旦出错马上能定位到具体是哪张图。实际操作中可以加一个小工具函数def validate_json(json_path): 检查json文件是否完整有效 try: with open(json_path, r, encodingutf-8) as f: data json.load(f) if shapes not in data: return False, 缺少shapes字段 if not isinstance(data[shapes], list): return False, shapes字段不是列表 # 检查shapes中是否有有效坐标 valid_polygons 0 for shape in data[shapes]: if shape.get(points): valid_polygons 1 if valid_polygons 0: return False, 该json没有任何有效多边形 return True, OK except json.JSONDecodeError as e: return False, fJSON解析失败: {e} except Exception as e: return False, str(e)这个函数在批量转换前跑一遍可以把异常json提前筛掉。否则转换到一半再停下来去修等待时间会非常漫长。7. 转换后的验证与下一步衔接7.1 像素值统计抽检转换完成后建议对每一张mask做一次像素值分布统计import collections def inspect_mask(mask_path): mask cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE) unique_values np.unique(mask) print(fmask {mask_path} 包含像素值: {unique_values.tolist()}) print(fmask尺寸: {mask.shape}) return unique_values如果某张mask里出现了类别映射表中不存在的值比如出现了6而映射表只有0到3那就说明转换逻辑有bug可能是某个类别的编号写错了。这种问题如果不在早期发现到了训练时会以loss不收敛的形式暴露到那时再去定位就非常痛苦。7.2 与模型训练的衔接mask生成之后的用途很多取决于你要跑什么模型。以目标检测为例你可能并不需要像素级mask而是需要把polygon坐标转换成YOLO格式的txt文件。这里给一个简化的俯角YOLO格式要求的是归一化的中心坐标和宽高具体是class x_center y_center width height。用Labelme的矩形标注结果可以方便地转换def rectangle_to_yolo(json_path, output_txt_path, class_mapping_reverse): with open(json_path, r) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] with open(output_txt_path, w) as f: for shape in data[shapes]: if shape[shape_type] ! rectangle: continue label shape[label] if label not in class_mapping_reverse: continue class_id class_mapping_reverse[label] x1, y1 shape[points][0] x2, y2 shape[points][1] xmin, xmax min(x1, x2), max(x1, x2) ymin, ymax min(y1, y2), max(y1, y2) x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h width (xmax - xmin) / img_w height (ymax - ymin) / img_h f.write(f{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n)如果你要喂给分割模型比如U-Net、DeepLab、Mask R-CNN那么前面讲的单通道mask图就是标准输入。需要注意的是训练时建议把mask里的像素值当作类别索引而不是RGB颜色值。在PyTorch的数据加载器里可以用torch.from_numpy(mask).long()把uint8数组转成long型张量这就是交叉熵损失函数接收的target格式。7.3 划分训练集、验证集、测试集有了图片和mask之后需要把数据划分成训练集、验证集和测试集。最简单的方式是按文件list进行划分import random from glob import glob image_paths glob(dataset/images/*.jpg) random.seed(42) random.shuffle(image_paths) train_ratio 0.7 val_ratio 0.15 test_ratio 0.15 train_files image_paths[:int(len(image_paths) * train_ratio)] val_files image_paths[int(len(image_paths) * train_ratio):int(len(image_paths) * (train_ratio val_ratio))] test_files image_paths[int(len(image_paths) * (train_ratio val_ratio)):] # 写入txt索引文件 def write_file_list(file_list, output_path): with open(output_path, w) as f: for path in file_list: f.write(path \n) write_file_list(train_files, dataset/train.txt) write_file_list(val_files, dataset/val.txt) write_file_list(test_files, dataset/test.txt)这里有一个关键点划分时一定要用固定的随机种子否则每次运行脚本生成的文件列表都会不一样会导致模型在同一批数据上重复训练或者验证集不稳定结果不可复现。8. 从个人经验出发的几点补充建议8.1 标注时不要一边标一边改类别清单在项目启动前把类别清单想清楚尽量一次性定下来。标注过程中如果发现类别定义有歧义比如person和riding_person到底算不算两个类别先记录下来集中到一批标注完成之后再统一决定。如果边标边改后面还得重新核验大量json文件的label是否一致工作量会翻倍。8.2 定期备份标注结果标注数据是劳动密集型产物丢起来也是连锁反应——如果某张图的json坏了重新标注可能要花十几分钟如果一批都坏了那就是灾难。我习惯每隔一段时间把整个labels目录压缩一次扔到网盘或者本地备份盘。每隔一千张图片一个批次这样即使出问题也只会丢失很少的进度。8.3 小规模试跑验证最推荐的流程是先用十张图跑通全链路。这十张图完成标注 - json - mask - 模型训练 - 推理的完整流程后再大规模标注。因为只有在训练环节你才发现自己生成的Ground Truth是不是真的符合模型输入要求。像我之前有次以为自己生成了正确的mask结果训练的时候loss完全不下降排查了整整一天才发现是mask的像素值顺序写错了类别值和标签错位。先小规模验证能省下大量后续返工时间。我在实际项目中体会最深的点是Labelme这套工作流的好处在于它的每个环节都很透明数据的中间表示都是通用格式。前期花一点时间把流程理顺中间几乎不会出现什么幺蛾子。希望这篇内容能帮你少踩一些我踩过的坑顺利啃下标注到Ground Truth这一整条链路。
企业数字化 ERP 产品动态
相关推荐
投资顾问 Agent Harness 实战:用统一 Key 打通资产配置建议链路 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 8:31:01
Atlas 300V部署YOLO实战:昇腾推理卡从ONNX到OM全流程 写这篇内容之前,我先把这个月折腾 Atlas 300V 24G 的结论放在最前面:这张卡确确实实是一块运算加速卡,但它不是那种“插上去就能像 GPU 一样直接读 PyTorch 模型”的卡。它有 24GB 显存,支持 FP16 和 INT8 推理,官方定… · 2026/9/25 8:30:55
GSD 技能表面管理实战:用 `/gsd:surface` 在不重装的情况下按需开关技能集群 【免费下载链接】gsd-core Git. Ship. Done - Core 项目地址: https://gitcode.com/gh_mirrors/ge/gsd-core 点击查看 免费下载 /gsd:surface 是 GSD(Get. Ship. Done — Core)提供的运行时技能表面(skill surface)开… · 2026/9/25 8:30:49
minimaxH3实现360度旋转视频到三维高斯场景的端到端重建 1. 这不是“又一个AI视频工具”,而是三维内容生产链路的实质性突破最近在本地跑通minimaxH3生成360度定格旋转视频的完整流程后,我坐在显示器前盯着那个缓缓自转的茶杯模型——它不是贴图旋转,不是镜头绕行,而是真正由360个离散视… · 2026/9/25 9:12:05
Code Review总走过场?试试“开放式代码审查”的五个落地实践 1. 从一次深夜事故说起:为什么团队 review 必须"打开"上个月我们线上出了个不大不小的事故:一个配置项的值被人为改成了错误环境下的地址,代码看起来没问题,review 也过了,但一上线就把消息队列的流量导到了… · 2026/9/25 9:11:59
用影刀RPA自动填表,彻底告别重复性加班 被填表折磨过的打工人,大概率都动过同一个念头:如果电脑能自己把这些破事干完就好了。我之前在电商公司做运营,每天下午四点准时开始往后台系统里填商品信息、活动配置、客户报表,一填就是两三个小时,眼睛对着屏幕快瞎… · 2026/9/25 9:11:35
Word长文档高效排版:从样式体系到自动化操作全攻略 刚入行那几年,我最怕的不是写内容,而是接手别人发过来的 Word 文档。内容写得多好都跟我无关,我得先花一两个小时把乱七八糟的排版捋顺:标题一会儿宋体一会儿黑体,目录是手工敲的点线,页码从第 1 页开始不听… · 2026/9/25 9:11:35
杭州家速住环境科技体验好吗 一扇玻璃窗,藏着一个家庭的整个夏天杭州的七月,太阳落在西晒的落地窗上,客厅的温度总比其他房间高出几度。有人把空调开到最低档,窗边依然闷热难耐;有人心疼真皮沙发和木地板一天天褪色,却找不到办法挡住那道紫外线;低… · 2026/9/25 9:11:29
靠谱的专业包车企业推荐 中汇租车广受信赖 中汇汽车服务(广州)有限公司,简称中汇租车,是经广州市工商局正式批准成立的专业汽车租赁企业,2010年成立至今深耕广州汽车租赁行业十余年,始终聚焦各类组织及个人用户的多元出行需求,是广州本地兼具服务口碑与车队实力… · 2026/9/25 9:11:29
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37