共计 2977 个字符,预计需要花费 8 分钟才能阅读完成。
背景介绍
CCPD(Chinese City Parking Dataset)是一个大型车牌检测数据集,包含超过 30 万张车牌图像,广泛应用于车牌识别和车辆检测任务。而 YOLO(You Only Look Once)是一种流行的目标检测算法,其训练数据需要特定的格式。

CCPD 数据集的特点:
- 图像文件名包含车牌位置和角度信息
- 使用四点坐标表示车牌位置
- 包含多种光照和天气条件下的车牌图像
YOLO 格式要求:
- 使用归一化的中心坐标和宽高表示目标位置
- 每个图像对应一个.txt 标注文件
- 类别标签为整数索引
两者之间的主要差异在于坐标表示方式,这带来了转换的主要挑战。
技术方案
1. CCPD 数据解析方法
CCPD 数据集的文件名包含了丰富的信息,我们需要从中提取出车牌的位置坐标。文件名格式通常为:
区域 - 车牌号 - 倾斜角度 - 亮度 - 模糊度 - 四个坐标点.jpg
我们需要特别关注的是最后的四个坐标点,它们以 _ 分隔,格式为x1,y1,x2,y2,x3,y3,x4,y4。
2. 坐标转换算法
从四点坐标转换到 YOLO 格式的中心坐标和宽高,需要以下步骤:
- 计算四点坐标的最小外接矩形
- 将矩形坐标转换为中心坐标 (x_center, y_center) 和宽高(width, height)
- 将坐标归一化(除以图像宽高)
- 将类别索引(车牌通常为 0)和归一化坐标写入.txt 文件
3. 文件组织方式
转换后的文件应按照 YOLO 的标准格式组织:
- 将所有图像放在
images文件夹 - 将所有标注文件放在
labels文件夹 - 保持图像和标注文件同名(仅扩展名不同)
代码实现
以下是完整的 Python 转换脚本:
import os
import cv2
import numpy as np
# 配置参数
data_dir = 'CCPD2020' # CCPD 数据集目录
output_dir = 'yolo_format' # 输出目录
class_id = 0 # 车牌类别 ID
# 创建输出目录
os.makedirs(os.path.join(output_dir, 'images'), exist_ok=True)
os.makedirs(os.path.join(output_dir, 'labels'), exist_ok=True)
# 遍历数据集
for filename in os.listdir(data_dir):
if not filename.endswith('.jpg'):
continue
# 解析文件名获取坐标点
parts = filename.split('-')
coords = parts[-1].split('_')[-4:]
coords = [list(map(int, c.split(','))) for c in coords]
# 读取图像获取尺寸
img_path = os.path.join(data_dir, filename)
img = cv2.imread(img_path)
img_h, img_w = img.shape[:2]
# 计算最小外接矩形
rect = cv2.minAreaRect(np.array(coords))
box = cv2.boxPoints(rect)
box = np.int0(box)
# 获取矩形参数
x_min, y_min = box.min(axis=0)
x_max, y_max = box.max(axis=0)
# 转换为 YOLO 格式
x_center = ((x_min + x_max) / 2) / img_w
y_center = ((y_min + y_max) / 2) / img_h
width = (x_max - x_min) / img_w
height = (y_max - y_min) / img_h
# 写入标注文件
base_name = os.path.splitext(filename)[0]
label_path = os.path.join(output_dir, 'labels', base_name + '.txt')
with open(label_path, 'w') as f:
f.write(f'{class_id} {x_center} {y_center} {width} {height}\n')
# 复制图像
output_img_path = os.path.join(output_dir, 'images', filename)
cv2.imwrite(output_img_path, img)
print('转换完成!')
验证方法
转换完成后,我们需要验证结果是否正确:
- 随机选择几张转换后的图像和对应的标注文件
- 使用以下脚本可视化检查标注框是否正确
import cv2
import random
# 随机选择一张图像
image_files = os.listdir(os.path.join(output_dir, 'images'))
sample_image = random.choice(image_files)
# 读取图像和标注
img = cv2.imread(os.path.join(output_dir, 'images', sample_image))
label_path = os.path.join(output_dir, 'labels', os.path.splitext(sample_image)[0] + '.txt')
with open(label_path, 'r') as f:
line = f.readline().strip()
class_id, x_center, y_center, width, height = map(float, line.split())
# 将 YOLO 坐标转换为图像坐标
img_h, img_w = img.shape[:2]
x_center *= img_w
y_center *= img_h
width *= img_w
height *= img_h
x_min = int(x_center - width/2)
y_min = int(y_center - height/2)
x_max = int(x_center + width/2)
y_max = int(y_center + height/2)
# 绘制矩形
cv2.rectangle(img, (x_min, y_min), (x_max, y_max), (0, 255, 0), 2)
# 显示结果
cv2.imshow('Validation', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
避坑指南
- 坐标归一化处理
- 确保所有坐标都除以图像的实际宽高
-
注意 OpenCV 读取图像时尺寸顺序是(height, width)
-
图像尺寸不一致问题
- CCPD 数据集中的图像尺寸可能不同
-
必须对每张图像单独计算归一化系数
-
特殊字符处理
- 文件名中可能包含特殊字符
-
建议在解析前先对文件名进行规范化处理
-
四点坐标顺序问题
- 四点坐标可能不是顺时针或逆时针顺序
- 使用
cv2.minAreaRect()可以自动处理这个问题
性能优化建议
- 多进程处理
-
对于大规模数据集,可以使用 Python 的 multiprocessing 模块加速处理
-
增量处理
-
记录已处理的文件,避免重复处理
-
内存优化
-
对于非常大的图像,可以分块读取处理
-
并行 I /O
- 使用异步 I / O 操作提高文件读写效率
扩展功能
转换完成后,您可以进一步:
- 实现数据增强(旋转、缩放、色彩变换等)
- 添加可视化工具实时检查标注质量
- 将转换流程封装为命令行工具
- 集成到自动化训练流程中
希望这篇指南能帮助您顺利完成 CCPD 到 YOLO 格式的转换,祝您的目标检测项目取得成功!
正文完
