共计 3271 个字符,预计需要花费 9 分钟才能阅读完成。
背景介绍
CCPD(Chinese City Parking Dataset)是目前国内最全面的车牌检测数据集,包含超过 30 万张真实场景下的车牌图像。这个数据集的特点是覆盖了多种天气、光照条件和车牌类型,非常适合用于训练鲁棒的车牌检测模型。

YOLO(You Only Look Once)是当前最流行的目标检测算法之一,它要求标注文件采用特定的格式:每个标注文件对应一张图像,包含多个对象的类别和边界框信息。YOLO 格式的边界框使用归一化的中心坐标(x_center, y_center)和宽度高度(width, height)表示,数值范围在 0 - 1 之间。
技术难点
- 坐标系统差异:CCPD 使用像素级的绝对坐标(x1,y1,x2,y2)表示车牌位置,而 YOLO 需要归一化的相对坐标
- 标注结构不同:CCPD 将多个车辆的标注信息存储在一个 JSON 文件中,YOLO 则要求每个图像有单独的 txt 标注文件
- 类别表示方式:CCPD 未明确区分车牌类型,而实际应用中可能需要识别不同颜色或类型的车牌
- 图像尺寸问题:YOLO 的归一化坐标需要基于图像的实际尺寸,而 CCPD 中的图像可能有不同的分辨率
实现方案
以下是完整的 Python 转换脚本,主要功能包括:
- 解析 CCPD 的 JSON 标注文件
- 将绝对坐标转换为 YOLO 格式的相对坐标
- 为每张图像生成对应的 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'
)
性能优化
处理大规模数据集时,可以考虑以下优化策略:
- 批量处理:使用多进程并行处理多个图像文件
- 内存管理:避免同时加载所有图像到内存,改为逐张处理
- 缓存机制:对已经处理过的文件进行记录,避免重复处理
- 预处理优化:先将所有图像路径收集到列表中,再分配给不同进程处理
以下是改进后的并行处理版本核心代码:
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)
# 写入结果
...
避坑指南
- 坐标越界问题 :转换后的 YOLO 坐标必须确保在[0,1] 范围内,否则训练时会报错
- 图像路径问题:确保 CCPD 标注中的图像路径是有效的,或者提前准备好图像副本
- 类别 ID 混淆:如果数据集中有多种车牌类型,需要为它们分配不同的 class_id
- 图像格式兼容性:某些 CCPD 图像可能是 RGBA 格式,需要转换为 RGB 格式
- 文件名冲突:确保输出文件名不会重复,特别是当处理多个 CCPD 子集时
扩展思考
这个转换方案可以轻松适配到其他自定义数据集,主要修改点包括:
- 标注解析逻辑:根据新数据集的标注格式调整解析代码
- 类别映射:建立自定义类别与 YOLO class_id 的对应关系
- 特殊处理:如处理旋转框、分割掩码等其他标注类型
- 验证机制:添加可视化检查代码,确保转换后的标注与图像对齐
实践任务
尝试用本方案处理 1000 张 CCPD 图片,并验证转换效果:
- 从 CCPD 数据集中随机选择 1000 张图像及其标注
- 运行转换脚本生成 YOLO 格式标注
- 使用以下代码抽样检查转换结果:
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 格式,为后续的车牌检测模型训练打好数据基础。
正文完
发表至: 未分类
近一天内
