YOLO标签可视化:目标检测标注质检与数据闭环实战

发布时间:2026/10/26 13:16:38
YOLO标签可视化:目标检测标注质检与数据闭环实战 开门见山地说做完一轮标注之后最省时间的质检动作不是写脚本算 mAP而是把 YOLO 格式的标签可视化出来一张张翻着看。我见过太多项目训练 loss 降得很漂亮结果推理时框的位置总是偏那么一点点回头一查标注文件里 y 坐标和 x 坐标写反了或者归一化的时候除错了边。这类问题在数字层面几乎看不出来但一旦画到图上半秒钟就能发现。YOLO 格式标签可视化这件事听起来像个边角料工具实际上它是整个数据闭环里性价比最高的一环几十行代码就能把标注错误、类别错位、坐标越界、图片标签错配这几类高频事故一网打尽。不管你是刚接手一份别人标好的数据集还是自己标了几千张想抽检又或者是想把标注结果拿去做汇报、做数据集说明文档这套东西都用得上。下面我按自己实际踩过的顺序把格式原理、画法选型、脚本实现、统计分析、排错经验完整说一遍代码可以直接抄去改。1. YOLO标签文件里到底存了什么1.1 一行五个数字的坐标系与归一化逻辑YOLO 检测格式的标签文件是纯文本一张图对应一个同名.txt文件里每一行代表一个目标框格式固定为五个字段class_id x_center y_center width height后面四个数全部是归一化到 0 到 1 之间的浮点数分别表示框中心点的横纵坐标、框的宽和高除以的是图片的原始像素宽高。这一点是理解所有可视化问题的钥匙——标签文件本身不存任何像素坐标它存的是一组相对比例。所以你在画框之前必须先知道这张图到底是多少像素才能把比例还原成位置。还原公式很朴素但每一步都容易写错# 归一化坐标 - 像素坐标 x1 (xc - w / 2) * img_w y1 (yc - h / 2) * img_h x2 (xc w / 2) * img_w y2 (yc h / 2) * img_h反过来如果你要自己生成标签就是先拿到像素框的左上角和右下角再倒推xc ((x1 x2) / 2) / img_w yc ((y1 y2) / 2) / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h之所以用中心点加宽高而不是左上右下是因为早期检测框架的输出直接就是中心偏移加尺度标签和网络输出对齐可以少一层换算。这个设计本身没问题问题出在人的手上写反、除错、忘记除是三个永恒的错误来源。提示画框时务必先做一次边界裁剪。归一化标签允许出现略微小于 0 或大于 1 的值有些标注工具在目标被裁切时会导出越界框直接按公式画OpenCV 会自动截断线段但文字标签可能跑到画布外面看起来像丢了一个框。1.2 类别索引和名字对不上的三种常见情况标签文件里只有class_id是个从 0 开始的整数它本身不带任何语义。想让图上显示人车狗这样的名字你必须有一份索引到名字的映射通常放在classes.txt或者数据配置文件的names字段里。映射这一环我遇到过三种典型的错位第一种是从 1 开始编号。有些标注工具默认类别编号从 1 起导出时不做减一于是你的names列表第 0 项永远匹配不上所有框的类别整体偏移一位最后一个类别直接缺失。判断方法很简单看标签文件里class_id的最大值是不是刚好等于类别总数如果等于基本就是从 1 开始的那批。第二种是映射表顺序被改过。多人协作时有人往classes.txt中间插了一行新类别后面的索引全部顺移但已经标好的旧文件不会自动更新。这时候可视化出来会发现某几类目标的框颜色全变了、名字全错了而且错得很规律。第三种是不同数据集混用同一套标签。把两个来源的数据合并训练各自索引含义不同标签文件却长得一模一样。这种情况光看图不一定能发现得配合类别分布统计一起看——某一类的数量突然暴涨往往就是两个语义被合并到了一个 id 上。我的做法是可视化脚本里加一行断言检查class_id是否落在[0, len(names)-1]区间内越界就打印文件名和行号不要静默跳过。这个检查成本几乎为零但能拦住绝大多数索引事故。1.3 除了检测框还有哪些变体需要可视化现在 YOLO 系列的标签不止一种形态可视化之前得先确认你手上的是哪一种否则画出来的东西驴唇不对马嘴。检测框五个字段最常见画矩形。实例分割一行是class x1 y1 x2 y2 ... xn yn后面跟一串归一化多边形顶点没有宽高。画法是cv2.polylines连线加半透明填充顶点数必须是偶数且一般不少于 6 个。旋转框在五个字段基础上多一个角度值顺序是class xc yc w h angle角度单位在不同实现里可能是弧度也可能是度。画法要用cv2.boxPoints配合RotatedRect别硬套轴对齐矩形。姿态关键点一行里包含框加一串关键点的 x、y、可见性标记三元组排列。画的时候要把可见性为 0 的点跳过否则会出现一堆挤在原点的散点。判断变体最省事的办法是直接看某一行有几个字段5 个是检测6 个大概率是旋转框其他数量再结合项目配置确认。千万不要用字段数不等于 5 就当多边形处理这种粗暴逻辑旋转框会被你画成一团乱线。1.4 空标签文件不是垃圾数据有一类文件特别容易被误删.txt存在但内容为空。很多人的第一反应是这是标注失败了吧删掉重标。实际上空文件在 YOLO 体系里有明确语义——这张图是负样本图里没有任何需要检测的目标。负样本对抑制误检非常关键尤其是背景复杂、容易误触发的场景。如果你在可视化脚本里遇到空标签就跳过不画质检时就会漏掉一整批图等训练完发现模型在纯背景图上疯狂出框回头再查数据已经来不及了。所以我的脚本里永远保留一个分支空标签也要生成一张原图副本文件名后面加个标记方便你确认这批负样本的图片内容是否合理——比如有没有漏标的目标藏在里面。2. 可视化方案怎么选2.1 现成标注工具自带的预览够不够用第一反应通常是打开标注工具直接看。这条路在小批量抽查场景下是成立的标注软件加载图片和标签后本来就会把框画出来改起来也方便。但它有三个绕不过去的限制。一是批量效率低。你要看五百张图就得点五百次下一张眼睛还得盯着屏幕中途走神就漏了。二是无法脱离工具环境。数据集要交给别人、要归档、要在文档里展示总不能要求对方也装一套标注软件。三是统计能力缺失。工具只告诉你这张图有几个框不会告诉你整个数据集里小目标的宽高比集中在什么区间。所以我的判断标准是临时抽检十张二十张用标注工具点一点最快超过一百张或者需要出图给别人看就老老实实写脚本。2.2 自己写脚本的两条路线OpenCV 与 PIL自己画基本就在这两个库之间选。它们的差异比想象中大选错了后面会别扭很久。OpenCV 路线读取用cv2.imread画框用cv2.rectangle画文字用cv2.putText写出用cv2.imwrite。优势是速度快一张 1080p 图上画几十个框单张耗时通常在毫秒级批量跑几千张毫无压力线段抗锯齿可以通过cv2.LINE_AA打开观感不差。劣势是putText只支持 ASCII 字符集中文类别名会变成一串问号。PIL 路线用Image.open读图ImageDraw.Draw画框draw.text写文字。优势是字体控制精细指定一个中文 ttf 字体路径就能正常渲染中文文字排版、描边、背景条都好做。劣势是速度慢一些尤其是画大量半透明填充时需要走Image.alpha_composite内存占用也更高。我的实际选择是混合框和填充用 OpenCV 画快中文类别名用 PIL 画对。具体做法是先用 OpenCV 在 ndarray 上画完几何图形转成 RGB 后包成Image对象再用ImageDraw叠加文字最后统一保存。多一次内存拷贝换来的是既快又能显示中文很值。2.3 方案对比与选型建议方案上手成本批量能力中文支持统计能力适合场景标注工具预览极低弱好无十张以内抽检OpenCV 脚本低强差可扩展纯英文类别、大批量PIL 脚本低中好可扩展中文类别、需要出图OpenCV PIL 混合中强好可扩展通用推荐可视化看板类库中中好强需要交互式排查如果你只是想在训练前扫一眼标注质量OpenCV 单库足够如果最终产物要放进报告、要给非技术同事看那中文渲染和省眼的排版就必须考虑混合方案更稳妥。别为了省事用拼音代替中文类别名后面交接的时候解释成本更高。3. 从零写一个可复用的可视化脚本3.1 目录结构和参数设计先说目录约定。YOLO 数据集的常规组织方式是这样dataset/ images/ train/ a001.jpg a002.jpg val/ a003.jpg labels/ train/ a001.txt a002.txt val/ a003.txt classes.txt标签和图片靠同文件名、不同后缀关联。这个约定看着简单实际坑不少图片后缀可能是.jpg也可能是.jpeg、.png大小写还可能混着来有的数据集把图片和标签放在同一层目录只靠扩展名区分。所以脚本里找标签文件不能硬拼字符串得用主文件名去匹配。参数设计上我建议至少暴露这几个images_dir/labels_dir输入路径out_dir输出路径classes_file类别映射文件允许为空为空时直接显示 idconf_style画框风格实线/虚线/半透明填充font_scale_ratio字号相对图片短边的比例默认 0.025 左右line_ratio线宽相对短边的比例默认 0.003 左右skip_empty是否跳过空标签字号和线宽为什么要用比例而不是固定像素因为数据集里图片尺寸差异可能非常大一批图里既有 640×480 的也有 4000×3000 的。固定字号 0.5 在小图上糊成一片在大图上小得像蚂蚁。按短边比例算视觉一致性最好。3.2 坐标反算与裁剪的核心函数下面是核心绘制部分我把坐标还原、越界裁剪、颜色分配都拆开写了import os import cv2 import numpy as np def load_names(path): if not path or not os.path.exists(path): return None with open(path, r, encodingutf-8) as f: return [line.strip() for line in f if line.strip()] def yolo_to_pixel(xc, yc, w, h, img_w, img_h): x1 (xc - w / 2.0) * img_w y1 (yc - h / 2.0) * img_h x2 (xc w / 2.0) * img_w y2 (yc h / 2.0) * img_h # 裁剪到图像范围内避免越界框撑出画布 x1 max(0.0, min(x1, img_w - 1)) y1 max(0.0, min(y1, img_h - 1)) x2 max(0.0, min(x2, img_w - 1)) y2 max(0.0, min(y2, img_h - 1)) return int(round(x1)), int(round(y1)), int(round(x2)), int(round(y2)) def color_for(cls_id): # 用黄金比例散列让相邻 id 的颜色差异足够大 hue int((cls_id * 0.618033988749895) % 1.0 * 180) hsv np.uint8([[[hue, 200, 230]]]) bgr cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)[0][0] return int(bgr[0]), int(bgr[1]), int(bgr[2])这里有个细节值得单独说颜色不要用随机数生成。用random.randint给每个类别取色同一类在不同图里颜色会变看图时非常干扰判断而且随机取色容易撞色两个相邻类别画出几乎一样的颜色。用类别 id 做确定性散列同类永远同色不同类尽量拉开肉眼辨识度会好很多。上面这个黄金比例散列是我常用的写法实现简单分布也比较均匀。裁剪那几行也别省。归一化标签在目标被图像边界截断时xc - w/2可能算出负数如果不裁OpenCV 画线会在画布外延伸虽然屏幕上看起来没差别但当你把框的坐标打印出来做二次分析时就会出现负坐标容易误判成数据错误。3.3 颜色分配与文字标签的排版技巧画框本身没什么技术含量真正影响能不能一眼看出问题的是文字标签的排版。我踩过的坑几乎都集中在这一点上。文字位置默认把文字压在框的左上角内侧遇到密集小目标时文字会互相遮挡完全没法读。我的做法是优先放在框上方外侧y1 - 文字高度只有当上方空间不足时才翻到框内。这个判断逻辑只需两行但观感差别巨大。文字可读性直接在原图上写白字遇到浅色背景就消失了。标准解法是给文字垫一个实心背景条背景色用该类别颜色文字用白色或黑色靠亮度自动决定def draw_label(img, text, x, y, color, font_scale, thickness): (tw, th), base cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, font_scale, thickness) # 亮度决定字色保证对比度 luminance 0.114 * color[0] 0.587 * color[1] 0.299 * color[2] text_color (0, 0, 0) if luminance 140 else (255, 255, 255) cv2.rectangle(img, (x, y - th - base), (x tw, y), color, -1) cv2.putText(img, text, (x, y - base), cv2.FONT_HERSHEY_SIMPLEX, font_scale, text_color, thickness, cv2.LINE_AA)标注信息叠加我习惯在图片左上角画一条半透明的信息带写上图文件名、框总数、各类别计数。这条信息带的价值在于你翻图时不用打开终端去对照一眼就知道这张图该有几个框、都是什么类。一旦实际画出来的数量对不上说明标签解析出了问题。半透明填充如果要给框加填充色来增强视觉区分记得用叠加而不是直接画。cv2.addWeighted对整图做混合最省事但如果只想让填充区域半透明得先在副本上画实心矩形再对副本做addWeighted否则框线也会被冲淡。3.4 批量处理与结果组织单张能画之后批量就是循环的事但输出组织方式值得设计一下。全平铺到同一个目录几千张图找起来痛苦按子集分目录train/val保留原结构找起来顺如果想快速定位有问题的图可以在文件名里带上信息比如a001_boxes5_cls2-3.jpg扫一眼文件名就知道哪些图和预期不符。一个最小可用的批量主循环长这样IMG_EXTS {.jpg, .jpeg, .png, .bmp, .webp} def run(images_dir, labels_dir, out_dir, namesNone, font_ratio0.025, line_ratio0.003): os.makedirs(out_dir, exist_okTrue) stats {total: 0, empty: 0, missing_label: 0, boxes: 0} for root, _, files in os.walk(images_dir): for fn in files: stem, ext os.path.splitext(fn) if ext.lower() not in IMG_EXTS: continue img_path os.path.join(root, fn) lbl_path os.path.join(labels_dir, stem .txt) img cv2.imread(img_path) if img is None: print(f[读图失败] {img_path}) continue h, w img.shape[:2] short min(h, w) font_scale max(0.35, short * font_ratio / 30.0) thickness max(1, int(round(font_scale * 2))) line_w max(1, int(round(short * line_ratio))) boxes [] if os.path.exists(lbl_path): with open(lbl_path, r, encodingutf-8) as f: for lineno, line in enumerate(f, 1): parts line.split() if len(parts) 5: continue cid int(float(parts[0])) if names and not (0 cid len(names)): print(f[类别越界] {fn}:{lineno} id{cid}) continue xc, yc, bw, bh map(float, parts[1:5]) boxes.append((cid, xc, yc, bw, bh)) else: stats[missing_label] 1 for cid, xc, yc, bw, bh in boxes: x1, y1, x2, y2 yolo_to_pixel(xc, yc, bw, bh, w, h) color color_for(cid) cv2.rectangle(img, (x1, y1), (x2, y2), color, line_w, cv2.LINE_AA) name names[cid] if names else str(cid) draw_label(img, name, x1, max(y1, 12), color, font_scale, max(1, thickness // 2)) out_path os.path.join(out_dir, stem .jpg) cv2.imwrite(out_path, img, [cv2.IMWRITE_JPEG_QUALITY, 92]) stats[total] 1 stats[boxes] len(boxes) if not boxes: stats[empty] 1 return stats这段代码跑完会返回一份统计把总图数、空标签数、缺失标签文件数、总框数都列出来。别小看这四个数字我第一次跑一份两万张的数据集时就是靠缺失标签文件数发现有一个子目录的标签压根没同步过来。4. 把看图升级成看数据4.1 类别分布和框数量统计逐张看图能发现个例问题但发现不了系统性偏差。系统性偏差要靠统计图。最基础的一张是类别分布柱状图横轴类别名纵轴框数量。它能立刻暴露两类问题——长尾和缺失。长尾是指某几类数量远超其他类训练时模型会严重偏向多数类缺失是指某个类别数量为 0 或只有个位数要么是数据集本身就没有要么是标注时漏标了整类。第二种情况最隐蔽因为模型不会报错只会默默学不会。第二张是每张图的框数量直方图。正常数据集一般呈现一个偏态分布多数图有 1 到 10 个框少数图有几十个。如果直方图在某个特定值上出现异常尖峰比如大量图刚好只有 1 个框那就要怀疑是不是标注规则被简化了或者某批数据只标了主目标。第三张可以做得更细按子集train/val分组画堆叠柱状图检查类别分布在训练集和验证集之间是否一致。如果验证集里某一类的比例明显高于训练集评估指标会失真这是很多人训练完发现验证效果好但上线拉胯的根因之一。4.2 宽高散点与长宽比分布类别统计看的是有多少尺寸统计看的是多大后者直接决定你的训练配置合不合适。把每个框的像素宽高画成散点图横轴宽、纵轴高用对数坐标你会看到数据集的目标尺寸分布形态。如果散点大量集中在左下角说明小目标占主导那么训练时的输入分辨率、特征金字塔层级、以及小目标增强策略都得相应调整如果散点沿对角线上散开说明长宽比差异大锚框聚类或者自适应锚框的配置就很重要。单独把长宽比拎出来画直方图能看出更具体的东西。人的框通常窄高车的框通常宽扁如果某一类的长宽比分布出现了双峰往往意味着这一类的标注口径不统一——比如有的人框整个车身有的人只框车头。这种口径不一致对回归损失的伤害比想象中大模型会学到一个平均形状两头都不讨好。还有一张容易被忽略的图框面积占整图面积的比例分布。这个比例如果普遍低于 0.1%说明小目标太多常规的检测头可能根本感受不到如果普遍高于 50%说明目标很大这时候输入分辨率可以适当降低训练能快不少。4.3 中心点热力图定位标注偏倚这个是我觉得最有用、但用的人最少的一张图。做法很简单把所有框的中心点按归一化坐标累加到一张二维网格上网格尺寸取 100×100每个格子的值是该位置出现的中心点次数最后渲染成热力图。正常的数据集热力图应该接近均匀中间略密因为拍摄时主体通常在画面中央。如果热力图出现明显偏斜比如大量中心点集中在左下角那要警惕两种情况一是图片本身经过了裁剪主体被系统性地放到了某个位置二是某些标注是沿着固定模板套出来的不是真的人工框的。还有一个专门的用法只画小目标面积占比低于阈值的框的中心点热力图。小目标因为看不清标注时容易点偏中心点分布会明显散乱甚至贴边。如果你看到大量小目标中心点紧贴图像边界那基本可以断定这些框是被裁切过的标注时只标了可见部分训练时这类框会持续给模型错误的尺寸监督信号。渲染热力图用matplotlib的imshow加上高斯平滑就够不需要额外依赖。我一般会把热力图和原图的缩略网格并排放在一起方便对照位置。4.4 尺寸分布对训练配置的影响统计出来不是为了好看是要落到配置上。几条我实际用过的对应关系统计现象可能问题处理方向小目标占比超过 60%下采样后特征消失提高输入分辨率增加浅层特征融合长宽比双峰分布标注口径不统一回到标注规范抽检并统一某类别数量不足百张该类学不会补充数据或做类别平衡采样中心点热力图贴边目标被裁切检查原图裁剪流程考虑填充框面积普遍很大分辨率浪费适当降低输入尺寸提升吞吐这张表不是铁律但它给了一个从看数据到改配置的落地路径。我个人的经验是先跑统计再定训练参数比直接拿一套默认配置开训要省下至少一半的调试轮次。5. 常见问题排查实录5.1 框全挤在左上角这是最高频的现象几乎每个第一次写可视化脚本的人都遇到过。原因只有一个忘记乘图片的宽高。直接拿 0 到 1 之间的归一化值当像素坐标画所有框都会落在左上角一个极小的区域内看起来像一堆小方块堆在一起。排查方法很直接打印任意一个框的原始四个数和还原后的四个像素坐标如果原始值都在 0 到 1 之间、还原后变成几十到几百说明公式对了如果还原后还是小数那就是漏了乘法。还有一种变体乘了但乘错了。比如把宽度乘到了高上。这种情况在正方形图上完全看不出来一旦换成 16:9 的图框就会明显偏移。所以测试脚本时一定要挑一张非正方形、且目标不居中的图来验证正方形居中图是最容易骗过眼睛的。5.2 框整体偏移、镜像或越界框位置看起来差一点点通常有三个来源。第一是x 和 y 写反了。有些标注工具导出的顺序是class yc xc h w和标准格式不一致。判断特征很明显框会沿着对角线方向整体镜像画面左侧的目标框跑到了上方。快速验证的办法是找一张有明显上下文的图比如人站在地面如果框飘在空中基本就是坐标顺序问题。第二是EXIF 方向信息。手机拍摄的图片常常带旋转标记图片查看器会自动转正显示但 OpenCV 的imread默认不处理 EXIF读出来是未旋转的原始像素。这就导致你看到的图是正的程序读到的图是横的宽高互换框自然全错。解决办法是读图时加上cv2.IMREAD_IGNORE_ORIENTATION之外的显式旋转处理或者干脆在数据预处理阶段就把所有图统一转正并清除 EXIF。第三是标注时用的图和现在的图不是同一份。图片被重新压缩、裁剪、缩放但标签没同步更新比例就对不上了。这类问题靠单张图很难判断得靠框是否始终紧贴目标边缘这个整体观感来识别——如果所有框都均匀地大了一圈或者小了一圈那就是缩放比例不一致。5.3 图片和标签配不上对文件名匹配看着简单实际上能出问题的地方很多。后缀大小写是第一个A001.JPG和a001.txt在某些系统上被认为是同一张图在另一些系统上不是。跨平台搬运数据时最容易踩。我的做法是匹配时统一转小写但保留原始文件名用于输出。扩展名不一致是第二个图片可能是.jpeg但预处理脚本假设是.jpg拼接标签路径时直接用replace(.jpg, .txt)结果一个都没匹配上所有图都被当成无标签。这种 bug 不会报错只会让统计结果里缺失标签数等于总数看到这个数字就该警觉。嵌套目录是第三个图片在images/train/xxx/标签在labels/train/xxx/两边层级深度不一致。用os.walk遍历时如果不保留相对路径拼出来的标签路径就是错的。稳妥写法是算出相对images_dir的相对路径再拼到labels_dir下面。注意跑完批量脚本后第一件事是看统计里的缺失标签文件数。只要这个数不为零先别管画出来的图好不好看把匹配逻辑修对再说。5.4 中文路径与编码的坑两个独立的坑经常一起出现。第一个是读图路径含中文。Windows 环境下cv2.imread遇到中文路径会返回None而且不抛异常你只会看到一堆读图失败但不知道为什么。解决办法是用np.fromfile读字节流再cv2.imdecodedef imread_unicode(path): data np.fromfile(path, dtypenp.uint8) return cv2.imdecode(data, cv2.IMREAD_COLOR) def imwrite_unicode(path, img, quality92): ok, buf cv2.imencode(.jpg, img, [cv2.IMWRITE_JPEG_QUALITY, quality]) if ok: buf.tofile(path) return ok第二个是标签文件编码。如果类别名列表里有中文用open读时没指定encodingutf-8在某些默认编码下会抛UnicodeDecodeError或者读出乱码。统一加encodingutf-8并且在写输出文件名时避免直接用类别名用 id 加英文缩写更安全。还有一个隐蔽的情况类别名里带了空格。YOLO 标签是按空格分列的如果classes.txt里某一行是red car读取时按行处理没问题但如果你的解析逻辑是按空白切分整个文件就会被拆成两项后面全部错位。读类别文件一定要按行读不要按空白切。5.5 大批量渲染的速度问题单张图几十毫秒一万张就是十分钟上下能接受。但如果你的图是四千万像素级别的航拍或工业图像单张可能要几秒一万张就是几个小时这就得优化了。第一招是降采样预览。质检阶段不需要看原图细节把长边缩到 1600 像素再画框速度能提升一个数量级肉眼判断框位置完全够用。只有怀疑某张图有问题时再单独对那一张跑原分辨率。第二招是多进程。这个任务是典型的 CPU 密集型且完全可并行用进程池按文件列表切分即可。池大小设成物理核心数的 0.75 倍左右比较稳开满会因为内存带宽争抢反而变慢。注意每个进程内部不要共享 OpenCV 的图像对象各读各的。第三招是输出格式。PNG 无损但体积大、编码慢JPEG 质量 90 左右肉眼几乎看不出差别体积能小到五分之一。纯做质检的话用 JPEG 就够了需要出报告再对选定的一批导出 PNG。5.6 常见问题速查表现象最可能原因快速验证处理框全挤在左上角忘记乘宽高打印还原后坐标是否仍小于 1补上乘img_w/img_h框沿对角线镜像x/y 顺序写反看地面上的人是否飘在空中交换解析顺序非正方形图框偏移宽高乘反了换 16:9 图测试检查img.shape取值顺序所有图都报缺失标签扩展名不匹配打印拼出的标签路径用splitext取主名读图返回 None路径含中文换成纯英文路径试用imdecode类别名显示错误索引从 1 开始或有增删看 max id 是否等于类别数校正映射表框大了一圈或小了一圈图片被重采样过看框是否均匀偏离边缘统一图片与标签的缩放流程中文标签显示成问号cv2.putText不支持换英文测试用 PIL 绘制文字小目标框贴边且很乱目标被裁切看中心点热力图是否贴边检查裁剪流程考虑填充我在实际使用中最大的体会是这套脚本写一次后面每个项目都能复用改动通常只是路径和类别文件。真正花时间的从来不是写代码而是看到异常图之后去反推数据是在哪一步出的问题。所以脚本里那些断言和统计数字比画出来的框本身更有价值——框是用来发现问题的统计是用来定位问题的两者配合着用数据集质检才算闭环。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询