别只盯着训练了!用Python快速检查YOLO(v5/v8)数据集标注质量的3个脚本

张开发
2026/4/16 19:26:53 15 分钟阅读

分享文章

别只盯着训练了!用Python快速检查YOLO(v5/v8)数据集标注质量的3个脚本
别只盯着训练了用Python快速检查YOLO(v5/v8)数据集标注质量的3个脚本在目标检测项目中数据质量往往比模型架构更能决定最终性能上限。但现实中许多团队将80%精力投入模型调参却对标注数据中的错标、漏标、框体偏移等问题视而不见。本文将分享三个实战级Python脚本帮助你在训练前快速揪出YOLO格式数据集中的脏数据。1. 为什么标注质量检查比想象中更重要去年参与某工业缺陷检测项目时团队曾花费两周调整模型参数却收效甚微。最终发现是标注数据中存在30%的框体偏移——标注员在标注小目标时未准确贴合边缘。这个教训让我意识到高质量的标注数据比任何精妙的模型结构都更有价值。YOLO格式的标注文件.txt采用相对坐标存储肉眼难以直接判断以下常见问题框体偏移标注框未准确包围目标类别混淆相似类别标注错误如卡车标为汽车漏标问题图像中存在未标注的明显目标尺寸异常出现不符合物理规律的超大/小标注框接下来介绍的三个脚本分别对应不同检查场景建议按精细排查→宏观评估→统计分析的顺序使用。2. 单张图像可视化检查脚本这是最基础的检查工具适合对可疑样本进行精细验证。以下代码增加了动态调整显示比例和多窗口对比功能import cv2 import numpy as np from pathlib import Path def visualize_yolo_label(img_path, label_path, classes, scale1.0, compare_originalFalse): 可视化单张图像的YOLO标注 :param img_path: 图像路径 :param label_path: 标签路径 :param classes: 类别列表 :param scale: 显示缩放比例 :param compare_original: 是否并排显示原图对比 img cv2.imread(str(img_path)) h, w img.shape[:2] # 读取标签文件 labels [] if Path(label_path).exists(): with open(label_path, r) as f: for line in f.read().splitlines(): cls_id, xc, yc, bw, bh map(float, line.split()) x1 int((xc - bw/2) * w) y1 int((yc - bh/2) * h) x2 int((xc bw/2) * w) y2 int((yc bh/2) * h) labels.append((int(cls_id), x1, y1, x2, y2)) # 绘制标注框 vis_img img.copy() for cls_id, x1, y1, x2, y2 in labels: color (36, 255, 12) if cls_id len(classes) else (0, 0, 255) # 有效类别用绿色无效用红色 cv2.rectangle(vis_img, (x1, y1), (x2, y2), color, 2) cv2.putText(vis_img, f{classes[cls_id]}:{cls_id}, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) # 调整显示尺寸 if scale ! 1.0: vis_img cv2.resize(vis_img, (int(w*scale), int(h*scale))) if compare_original: img cv2.resize(img, (int(w*scale), int(h*scale))) # 显示结果 if compare_original: combo np.hstack([img, vis_img]) cv2.imshow(Original vs Annotated, combo) else: cv2.imshow(YOLO Annotation Check, vis_img) cv2.waitKey(0) cv2.destroyAllWindows()关键改进点增加scale参数应对高分辨率图像查看通过compare_original实现标注与原图同屏对比对无效类别ID自动用红色警示使用Pathlib提升路径处理兼容性提示实际使用时建议封装为命令行工具通过argparse接收图像路径、类别文件等参数。3. 批量随机抽样检查脚本当数据集规模达到数万张时手动检查每张图像不再现实。这个脚本通过随机抽样网格展示实现高效宏观评估import random import matplotlib.pyplot as plt from PIL import Image, ImageDraw def batch_visualize(dataset_dir, classes, sample_size16, grid_size(4,4), save_pathNone): 批量随机抽样可视化 :param dataset_dir: 数据集根目录需包含images和labels子目录 :param classes: 类别列表 :param sample_size: 抽样数量 :param grid_size: 展示网格布局 :param save_path: 结果保存路径可选 # 获取所有图像路径 img_dir Path(dataset_dir) / images img_paths list(img_dir.glob(*.*)) sampled_paths random.sample(img_paths, min(sample_size, len(img_paths))) # 创建画布 plt.figure(figsize(15, 10)) for idx, img_path in enumerate(sampled_paths, 1): # 获取对应标签路径 label_path img_path.parent.parent / labels / f{img_path.stem}.txt # 读取图像和标注 img Image.open(img_path) draw ImageDraw.Draw(img) if label_path.exists(): with open(label_path, r) as f: for line in f: cls_id, xc, yc, bw, bh map(float, line.split()) w, h img.size x1 (xc - bw/2) * w y1 (yc - bh/2) * h x2 (xc bw/2) * w y2 (yc bh/2) * h # 绘制半透明框体 draw.rectangle([x1, y1, x2, y2], outline(255, 0, 0, 128), width2) draw.text((x1, y1-15), classes[int(cls_id)], fill(255, 0, 0)) # 添加到网格 plt.subplot(grid_size[0], grid_size[1], idx) plt.imshow(img) plt.axis(off) plt.title(img_path.name) plt.tight_layout() if save_path: plt.savefig(save_path, dpi150, bbox_inchestight) plt.show()使用场景示例classes [person, car, truck, bicycle] batch_visualize( dataset_dirpath/to/your/dataset, classesclasses, sample_size12, grid_size(3,4), save_pathsample_check.jpg )输出效果优势随机抽样避免检查偏差网格布局便于快速发现异常模式PIL库绘制半透明框体避免遮挡目标自动保存检查结果供团队review4. 标注统计分析脚本前两个脚本解决看的问题而这个脚本解决量的问题。它会生成包含以下指标的可视化报告统计维度检测内容类别分布长尾现象、类别缺失框体尺寸分布异常大/小框体宽高比分布不符合物理规律的形状位置分布标注集中在特定区域import pandas as pd import seaborn as sns from tqdm import tqdm def analyze_annotations(dataset_dir, classes, output_diranalysis_results): 生成标注统计分析报告 :param dataset_dir: 数据集路径 :param classes: 类别列表 :param output_dir: 结果输出目录 # 准备数据结构 stats { class_dist: {name: 0 for name in classes}, widths: [], heights: [], aspect_ratios: [], center_x: [], center_y: [] } # 遍历所有标签文件 label_dir Path(dataset_dir) / labels for label_file in tqdm(list(label_dir.glob(*.txt)), descAnalyzing): with open(label_file, r) as f: for line in f: cls_id, xc, yc, bw, bh map(float, line.split()) stats[class_dist][classes[int(cls_id)]] 1 stats[widths].append(bw) stats[heights].append(bh) stats[aspect_ratios].append(bw / bh) stats[center_x].append(xc) stats[center_y].append(yc) # 创建输出目录 output_dir Path(output_dir) output_dir.mkdir(exist_okTrue) # 绘制类别分布 plt.figure(figsize(10, 6)) sns.barplot( xlist(stats[class_dist].keys()), ylist(stats[class_dist].values()) ) plt.title(Class Distribution) plt.xticks(rotation45) plt.savefig(output_dir / class_dist.png, bbox_inchestight) # 绘制框体尺寸分布 plt.figure(figsize(12, 5)) plt.subplot(1, 2, 1) sns.histplot(stats[widths], bins30) plt.title(Width Distribution) plt.subplot(1, 2, 2) sns.histplot(stats[heights], bins30) plt.title(Height Distribution) plt.savefig(output_dir / size_dist.png, bbox_inchestight) # 输出统计摘要 df pd.DataFrame({ Category: [Min, Max, Mean, Std], Width: [ min(stats[widths]), max(stats[widths]), np.mean(stats[widths]), np.std(stats[widths]) ], # 其他统计量... }) df.to_csv(output_dir / stats_summary.csv, indexFalse)典型问题诊断类别分布图中出现某个类别数量异常少 → 需补充采集尺寸分布中出现大量0.01的相对尺寸 → 可能存在无效标注宽高比集中在1:10等极端比例 → 检查标注规范是否合理5. 工程化集成建议将上述脚本整合到你的训练流水线中建议采用以下架构dataset_validation/ ├── visual_check.py # 单图可视化 ├── batch_sample.py # 批量抽样 ├── stats_analysis.py # 统计分析 └── run_validation.sh # 一键执行脚本自动化工作流示例# 在训练开始前自动执行检查 python stats_analysis.py --data ./dataset --output ./validation_report python batch_sample.py --data ./dataset --sample 20 --output ./samples.jpg # 根据检查结果决定是否启动训练 if [ $? -eq 0 ]; then python train.py --data ./dataset else echo Data quality issues detected! Please check validation report. fi对于大型团队可以考虑将这些检查点集成到Label Studio等标注工具的Review环节实现标注即检查的闭环流程。

更多文章