4、数据集准备:标注工具LabelImg安装与使用、COCO数据集格式解析、自定义数据集制作、数据集划分

数据,才是YOLO真正的燃料。模型结构再花哨,没有高质量的数据集,一切都是空中楼阁。这一章,咱们就亲手把数据集这块硬骨头啃下来。

核心要点: 标注工具选对、格式搞懂、数据自己做、划分合理。这四个环节,一个都不能少。

4.1 标注工具LabelImg:安装与实战

说到目标检测的标注工具,LabelImg是入门首选。它轻量、免费、跨平台,而且操作直观。我个人习惯用它来做小规模数据集的快速标注,效率很高。

4.1.1 安装

安装其实很简单,我建议直接用pip安装,省心。

# 安装LabelImg
pip install labelImg

# 启动
labelImg

如果你在macOS上遇到权限问题,加个 sudo 就行。Windows用户记得先装好Python和pip。

小提示: 我第一次用的时候,直接双击图标没反应,后来才发现需要从命令行启动。嗯,这个坑我替你们踩过了。

4.1.2 使用流程

启动后,界面很简洁。核心操作就三步:

  1. 打开图片目录:点击“Open Dir”,选择你的图片文件夹。
  2. 创建矩形框:点击“Create RectBox”,在目标上拉个框。
  3. 输入标签名:弹窗里输入类别名称,比如“person”、“car”。

标注完一张,按 Ctrl+S 保存。LabelImg默认生成Pascal VOC格式的XML文件。但YOLO需要的是TXT格式,怎么办?别急,在菜单栏 View → Auto Save mode 勾上,再在 Change Save Dir 里设置好输出目录。更关键的一步:点击 PascalVOC 按钮,切换成 YOLO 格式。这样保存的就是 .txt 文件了。

注意: YOLO格式的TXT文件里,每一行代表一个目标:类别ID x_center y_center width height。注意,这里的坐标都是归一化到0-1之间的比例值,不是像素值。我曾经有个学生直接用了像素坐标,模型怎么训都不收敛……

4.2 COCO数据集格式解析

COCO(Common Objects in Context)是目前目标检测领域最权威的数据集之一。YOLO官方预训练模型,基本都是在COCO上训的。所以,理解COCO格式,对你后续做迁移学习、评估模型都至关重要。

COCO使用JSON文件存储标注信息。结构看起来复杂,其实核心就几个字段:

字段 说明 示例
images 图片信息列表,包含id、文件名、宽高 {"id": 1, "file_name": "000001.jpg", "width": 640, "height": 480}
annotations 标注信息列表,包含目标框、类别id、分割掩码等 {"id": 1, "image_id": 1, "bbox": [x, y, w, h], "category_id": 1}
categories 类别列表,包含id和名称 {"id": 1, "name": "person"}

这里有个容易混淆的点:COCO的bbox格式是 [x, y, width, height],其中 x, y 是框左上角的像素坐标。而YOLO用的是中心点坐标加宽高。转换的时候要小心。

转换公式(像素坐标 → YOLO归一化坐标):

x_center = (x + w/2) / image_width
y_center = (y + h/2) / image_height
width = w / image_width
height = h / image_height

4.3 自定义数据集制作

实际项目中,你很少能直接用现成的数据集。比如我去年做一个工业质检项目,需要检测电路板上的微小焊点缺陷。COCO里哪有这个?只能自己做。

制作自定义数据集,我建议按这个流程来:

  1. 数据采集:用手机、工业相机或者爬虫收集图片。注意场景多样性,光照、角度、背景都要覆盖。
  2. 数据清洗:去掉模糊的、重复的、无关的图片。这一步很枯燥,但必须做。我见过有人偷懒,结果模型学了一堆噪声。
  3. 数据标注:用LabelImg或者更专业的工具(如LabelStudio)进行标注。标注质量直接决定模型上限。
  4. 格式转换:将标注结果统一转换成YOLO需要的TXT格式。写个Python脚本批量处理就行。

下面是一个简单的格式转换脚本示例:

import json
import os

def convert_coco_to_yolo(coco_json_path, output_dir):
    with open(coco_json_path, 'r') as f:
        coco_data = json.load(f)
    
    # 建立类别ID映射
    categories = {cat['id']: idx for idx, cat in enumerate(coco_data['categories'])}
    
    for img in coco_data['images']:
        img_id = img['id']
        img_w = img['width']
        img_h = img['height']
        filename = img['file_name'].split('.')[0] + '.txt'
        
        annotations = [ann for ann in coco_data['annotations'] if ann['image_id'] == img_id]
        
        with open(os.path.join(output_dir, filename), 'w') as f:
            for ann in annotations:
                cat_id = categories[ann['category_id']]
                bbox = ann['bbox']  # [x, y, w, h]
                x_center = (bbox[0] + bbox[2]/2) / img_w
                y_center = (bbox[1] + bbox[3]/2) / img_h
                width = bbox[2] / img_w
                height = bbox[3] / img_h
                f.write(f"{cat_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n")

# 使用示例
convert_coco_to_yolo('annotations.json', 'labels/')

4.4 数据集划分

数据准备好了,接下来要划分成训练集、验证集和测试集。比例一般是 8:1:1 或者 7:2:1。为什么需要验证集?说白了,就是用来调超参数和做模型选择的。测试集则是最终评估模型泛化能力的,不能参与训练过程。

划分的时候,有几点要注意:

  • 随机划分:用 random.shuffle 打乱数据,避免类别分布不均。
  • 分层采样:如果类别不平衡(比如A类有1000张,B类只有50张),建议按类别比例分层划分,保证每个子集里各类别比例一致。
  • 文件结构:YOLO通常要求图片和标签文件同名,放在对应的 images 和 labels 目录下。

下面是一个划分脚本的骨架:

import os
import random
import shutil

def split_dataset(image_dir, label_dir, output_dir, train_ratio=0.8, val_ratio=0.1):
    images = [f for f in os.listdir(image_dir) if f.endswith(('.jpg', '.png'))]
    random.shuffle(images)
    
    train_count = int(len(images) * train_ratio)
    val_count = int(len(images) * val_ratio)
    
    train_images = images[:train_count]
    val_images = images[train_count:train_count+val_count]
    test_images = images[train_count+val_count:]
    
    for split, img_list in zip(['train', 'val', 'test'], [train_images, val_images, test_images]):
        os.makedirs(f'{output_dir}/{split}/images', exist_ok=True)
        os.makedirs(f'{output_dir}/{split}/labels', exist_ok=True)
        for img in img_list:
            shutil.copy(f'{image_dir}/{img}', f'{output_dir}/{split}/images/{img}')
            label_file = img.replace('.jpg', '.txt').replace('.png', '.txt')
            shutil.copy(f'{label_dir}/{label_file}', f'{output_dir}/{split}/labels/{label_file}')

# 使用示例
split_dataset('images/', 'labels/', 'yolo_dataset/')

经验之谈: 划分完成后,记得检查一下每个子集的类别分布。写个简单的统计脚本,打印出每个类别的数量。如果发现某个类别在验证集里一个都没有,那模型评估结果就是假的。

4.5 本章知识体系

为了让你更直观地理解整个数据准备流程,我画了一张流程图:

数据集准备流程 数据集准备核心流程 数据采集 数据清洗 数据标注 格式转换 数据集划分 训练集 (80%) 验证集 (10%) 测试集 (10%) 💡 关键提醒: • 标注质量 > 标注数量:100张高质量标注 > 1000张粗糙标注 • 划分后务必检查类别分布,避免验证集/测试集出现未见过的类别 • 测试集一旦确定,就不要再用它做任何模型选择或调参

这张图把整个流程串起来了。从数据采集开始,经过清洗、标注、格式转换,最后划分成三个子集。每一步都有坑,但只要你按这个流程走,基本不会出大问题。