从TT100K到YOLO:一份完整的交通标志数据集转换与实战指南

发布时间:2026/7/4 23:19:53

从TT100K到YOLO:一份完整的交通标志数据集转换与实战指南 1. 为什么需要转换TT100K数据集格式第一次接触TT100K数据集时我完全被它复杂的目录结构和标注格式搞懵了。这个由清华大学和腾讯联合发布的交通标志数据集包含了10万张图片和3万多个标注实例但它的JSON标注格式和YOLO完全不兼容。当时为了训练YOLOv5模型我不得不花了两周时间研究格式转换的问题。TT100K数据集最大的特点是采用层级式JSON标注所有标注信息都存放在一个巨大的annotations_all.json文件里。这种设计虽然节省了存储空间但在实际使用时非常不方便。相比之下YOLO需要的格式就简单多了——每个图片对应一个.txt文件每行记录一个目标的类别和归一化坐标。举个具体例子TT100K中一个停车标志的标注可能是这样的{ objects: [{ category: p12, bbox: {xmin: 100, ymin: 200, xmax: 150, ymax: 250} }] }而YOLO需要的格式则是0 0.325 0.417 0.104 0.083这种转换不仅仅是格式变化还涉及到坐标系的转换从绝对坐标到相对坐标、类别ID的重新映射从字符串标签到数字索引以及数据集划分策略的调整。我在第一次尝试时就因为忽略了图像尺寸的读取顺序导致所有检测框都偏移了位置。2. 数据预处理的关键步骤2.1 筛选有效类别TT100K原始数据集包含221个交通标志类别但实际项目中我们往往只需要其中的一部分。我的经验是先用以下代码统计各类别的实例数量with open(annotations_all.json) as f: data json.load(f) class_count {} for img_id, img_info in data[imgs].items(): for obj in img_info[objects]: class_count[obj[category]] class_count.get(obj[category], 0) 1 # 按数量排序 sorted_classes sorted(class_count.items(), keylambda x: x[1], reverseTrue)建议保留实例数超过100的类别这样可以保证每个类别都有足够的训练样本。在我的实践中最终筛选出了45个主要类别包括禁令标志如p1、p10警告标志如ph4、pl5指示标志如i2、i42.2 处理破损和无效数据数据集里总会有些问题儿童需要特别处理标注错误有些边界框完全超出图像范围需要用clamp函数限制坐标图像损坏约0.3%的JPEG文件无法正常读取建议用OpenCV的imread检查长宽比异常极少数图片的宽高比超过10:1这类样本最好剔除这里分享一个实用的图像验证代码片段def validate_image(img_path): try: img cv2.imread(img_path) if img is None: return False h, w img.shape[:2] return w 16 and h 16 # 过滤掉过小的图像 except: return False3. 从TT100K到COCO的格式转换3.1 构建COCO格式的中间层为什么需要COCO格式作为中转因为直接从TT100K转到YOLO格式会丢失很多结构化信息。我的转换脚本主要处理以下几个部分类别信息将筛选后的类别建立数字ID映射图像信息记录每张图片的路径、尺寸和唯一ID标注信息转换边界框格式并关联到对应图像核心的数据结构如下coco_format { info: {...}, licenses: [...], categories: [ {id: 0, name: p1, supercategory: prohibitory}, ... ], images: [ {id: 0, file_name: test/100.jpg, width: 640, height: 480}, ... ], annotations: [ { id: 0, image_id: 0, category_id: 0, bbox: [100, 200, 50, 50], area: 2500, iscrowd: 0 }, ... ] }3.2 数据集划分策略TT100K原本的划分方式不适合目标检测任务。我采用了分层抽样的方法确保每个类别在训练集、验证集和测试集中都有代表按7:2:1的比例划分对样本数较少的类别适当增加其在训练集中的比例确保同一张图片不会出现在多个子集中实现代码的关键部分for cls in class_list: cls_images get_images_by_class(cls) random.shuffle(cls_images) train_end int(0.7 * len(cls_images)) val_end train_end int(0.2 * len(cls_images)) train_set.update(cls_images[:train_end]) val_set.update(cls_images[train_end:val_end]) test_set.update(cls_images[val_end:])4. COCO到YOLO格式的终极转换4.1 坐标归一化处理这是最容易出错的环节。YOLO要求的是中心坐标宽高的归一化格式计算时需要特别注意def coco_to_yolo_bbox(bbox, img_width, img_height): # bbox格式[x_min, y_min, width, height] x_center bbox[0] bbox[2] / 2 y_center bbox[1] bbox[3] / 2 # 归一化 x_center / img_width y_center / img_height width bbox[2] / img_width height bbox[3] / img_height return [x_center, y_center, width, height]4.2 生成YOLO格式的标签文件每个图片对应一个.txt文件格式要求非常严格每行一个目标空格分隔的五个数值类别ID、中心x、中心y、宽度、高度数值精度保留6位小数实际操作时我建议使用这个模板def save_yolo_label(file_path, class_id, bbox): with open(file_path, a) as f: line f{class_id} {bbox[0]:.6f} {bbox[1]:.6f} {bbox[2]:.6f} {bbox[3]:.6f}\n f.write(line)4.3 创建数据集配置文件最后需要准备YOLO模型训练必需的data.yaml文件train: ../images/train val: ../images/val test: ../images/test nc: 45 # 类别数量 names: [p1, p10, ph4, ...] # 按类别ID顺序排列5. 实战中的常见问题与解决方案5.1 标签错位问题第一次训练时模型完全学不会任何东西。排查后发现是因为图像尺寸读取错误OpenCV的shape返回的是高度在前归一化时混淆了宽高顺序解决方法是在转换时统一添加尺寸检查height, width img.shape[:2] assert width 0 and height 0, fInvalid image size: {img_path}5.2 类别不平衡处理某些常见标志如限速标志的样本数是不常见标志的100倍以上。我采用了这些策略过采样少数类别使用带权重的损失函数在数据增强时对少数类别使用更强的变换5.3 数据增强技巧针对交通标志的特点这些增强方式特别有效模拟天气变化添加雾、雨、雪效果透视变换模拟不同拍摄角度色彩抖动考虑白平衡变化的影响示例增强代码import albumentations as A transform A.Compose([ A.RandomBrightnessContrast(p0.5), A.HueSaturationValue(p0.5), A.RandomFog(fog_coef_lower0.1, fog_coef_upper0.3, p0.1), A.RandomRain(p0.1) ])6. 完整代码结构与使用指南我的项目目录结构是这样的tt100k2yolo/ ├── configs/ │ ├── classes.txt # 筛选后的类别列表 │ └── data.yaml # YOLO数据集配置 ├── datasets/ │ ├── images/ # 图片文件夹 │ │ ├── train/ │ │ ├── val/ │ │ └── test/ │ └── labels/ # 标签文件夹 │ ├── train/ │ ├── val/ │ └── test/ └── scripts/ ├── convert.py # 主转换脚本 └── utils.py # 工具函数转换流程只需三步修改configs/classes.txt定义需要的类别运行转换脚本python scripts/convert.py \ --input_dir /path/to/tt100k \ --output_dir ./datasets \ --config ./configs/classes.txt检查生成的data.yaml文件7. 模型训练与效果验证使用转换后的数据集训练YOLOv8关键配置参数model YOLO(yolov8n.yaml) results model.train( dataconfigs/data.yaml, epochs300, imgsz640, batch16, optimizerAdamW )在我的RTX 3090上训练300个epoch大约需要8小时。最终在测试集上的指标mAP0.5: 0.87mAP0.5:0.95: 0.63推理速度8ms/张640x640特别要注意的是交通标志检测需要更高的召回率。我通过调整置信度阈值和NMS参数将漏检率控制在5%以下results model.predict( sourcetest.jpg, conf0.3, # 降低置信度阈值 iou0.4, # 放宽IoU阈值 augmentTrue )经过三个版本迭代这套转换流程已经稳定支持各种YOLO系列模型。最大的收获是认识到数据质量比模型结构更重要——合理的格式转换和数据处理能让普通模型也表现出色。

相关新闻