CCPD数据集高效转换为YOLO格式:技术实现与避坑指南

1次阅读
没有评论

共计 3271 个字符,预计需要花费 9 分钟才能阅读完成。

image.webp

背景介绍

CCPD(Chinese City Parking Dataset)是目前国内最全面的车牌检测数据集,包含超过 30 万张真实场景下的车牌图像。这个数据集的特点是覆盖了多种天气、光照条件和车牌类型,非常适合用于训练鲁棒的车牌检测模型。

CCPD 数据集高效转换为 YOLO 格式:技术实现与避坑指南

YOLO(You Only Look Once)是当前最流行的目标检测算法之一,它要求标注文件采用特定的格式:每个标注文件对应一张图像,包含多个对象的类别和边界框信息。YOLO 格式的边界框使用归一化的中心坐标(x_center, y_center)和宽度高度(width, height)表示,数值范围在 0 - 1 之间。

技术难点

  1. 坐标系统差异:CCPD 使用像素级的绝对坐标(x1,y1,x2,y2)表示车牌位置,而 YOLO 需要归一化的相对坐标
  2. 标注结构不同:CCPD 将多个车辆的标注信息存储在一个 JSON 文件中,YOLO 则要求每个图像有单独的 txt 标注文件
  3. 类别表示方式:CCPD 未明确区分车牌类型,而实际应用中可能需要识别不同颜色或类型的车牌
  4. 图像尺寸问题:YOLO 的归一化坐标需要基于图像的实际尺寸,而 CCPD 中的图像可能有不同的分辨率

实现方案

以下是完整的 Python 转换脚本,主要功能包括:

  1. 解析 CCPD 的 JSON 标注文件
  2. 将绝对坐标转换为 YOLO 格式的相对坐标
  3. 为每张图像生成对应的 txt 标注文件
import json
import os
import cv2
from pathlib import Path

def convert_ccpd_to_yolo(ccpd_json_path, output_dir, class_id=0):
    """
    将 CCPD 数据集标注转换为 YOLO 格式
    :param ccpd_json_path: CCPD 标注 JSON 文件路径
    :param output_dir: YOLO 格式输出目录
    :param class_id: 车牌类别 ID(默认为 0)"""
    # 确保输出目录存在
    os.makedirs(output_dir, exist_ok=True)

    # 加载 CCPD 标注数据
    with open(ccpd_json_path, 'r') as f:
        ccpd_data = json.load(f)

    for img_info in ccpd_data['images']:
        # 获取图像路径和尺寸
        img_path = img_info['file_name']
        img = cv2.imread(img_path)
        if img is None:
            print(f"警告: 无法加载图像 {img_path}")
            continue

        height, width = img.shape[:2]

        # 准备 YOLO 标注内容
        yolo_lines = []
        for anno in img_info['annotations']:
            # 获取 CCPD 格式的边界框 [x1, y1, x2, y2]
            bbox = anno['bbox']

            # 转换为 YOLO 格式 [x_center, y_center, width, height]
            x_center = (bbox[0] + bbox[2]) / 2 / width
            y_center = (bbox[1] + bbox[3]) / 2 / height
            w = (bbox[2] - bbox[0]) / width
            h = (bbox[3] - bbox[1]) / height

            # 确保坐标在 [0,1] 范围内
            x_center = max(0, min(1, x_center))
            y_center = max(0, min(1, y_center))
            w = max(0, min(1, w))
            h = max(0, min(1, h))

            yolo_lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}")

        # 写入 YOLO 标注文件
        if yolo_lines:
            output_path = os.path.join(output_dir, Path(img_path).stem + '.txt')
            with open(output_path, 'w') as f:
                f.write('\n'.join(yolo_lines))

if __name__ == '__main__':
    # 使用示例
    convert_ccpd_to_yolo(
        ccpd_json_path='path/to/ccpd_annotations.json',
        output_dir='path/to/yolo_labels'
    )

性能优化

处理大规模数据集时,可以考虑以下优化策略:

  1. 批量处理:使用多进程并行处理多个图像文件
  2. 内存管理:避免同时加载所有图像到内存,改为逐张处理
  3. 缓存机制:对已经处理过的文件进行记录,避免重复处理
  4. 预处理优化:先将所有图像路径收集到列表中,再分配给不同进程处理

以下是改进后的并行处理版本核心代码:

from multiprocessing import Pool

def process_single_image(args):
    """包装函数用于多进程调用"""
    img_path, width, height, annotations = args
    yolo_lines = []
    for anno in annotations:
        # 转换逻辑与之前相同
        ...
    return yolo_lines

def convert_ccpd_parallel(ccpd_json_path, output_dir, workers=4):
    """并行版本的主函数"""
    # 加载数据并准备参数
    ...

    # 创建进程池
    with Pool(workers) as pool:
        results = pool.map(process_single_image, all_args)

    # 写入结果
    ...

避坑指南

  1. 坐标越界问题 :转换后的 YOLO 坐标必须确保在[0,1] 范围内,否则训练时会报错
  2. 图像路径问题:确保 CCPD 标注中的图像路径是有效的,或者提前准备好图像副本
  3. 类别 ID 混淆:如果数据集中有多种车牌类型,需要为它们分配不同的 class_id
  4. 图像格式兼容性:某些 CCPD 图像可能是 RGBA 格式,需要转换为 RGB 格式
  5. 文件名冲突:确保输出文件名不会重复,特别是当处理多个 CCPD 子集时

扩展思考

这个转换方案可以轻松适配到其他自定义数据集,主要修改点包括:

  1. 标注解析逻辑:根据新数据集的标注格式调整解析代码
  2. 类别映射:建立自定义类别与 YOLO class_id 的对应关系
  3. 特殊处理:如处理旋转框、分割掩码等其他标注类型
  4. 验证机制:添加可视化检查代码,确保转换后的标注与图像对齐

实践任务

尝试用本方案处理 1000 张 CCPD 图片,并验证转换效果:

  1. 从 CCPD 数据集中随机选择 1000 张图像及其标注
  2. 运行转换脚本生成 YOLO 格式标注
  3. 使用以下代码抽样检查转换结果:
import cv2
import random

def visualize_yolo_label(img_path, label_path):
    """可视化检查 YOLO 标注是否正确"""
    img = cv2.imread(img_path)
    h, w = img.shape[:2]

    with open(label_path) as f:
        for line in f:
            class_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)

            cv2.rectangle(img, (x1,y1), (x2,y2), (0,255,0), 2)

    cv2.imshow('Check', img)
    cv2.waitKey(0)

# 随机检查 10 个样本
for _ in range(10):
    img_file = random.choice(processed_images)
    label_file = img_file.replace('.jpg', '.txt')
    visualize_yolo_label(img_file, label_file)

通过这个完整的解决方案,开发者可以高效地将 CCPD 数据集转换为 YOLO 格式,为后续的车牌检测模型训练打好数据基础。

正文完
 0
评论(没有评论)