CCPD数据集实战指南:从数据预处理到模型训练的全流程解析

1次阅读
没有评论

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

image.webp

背景介绍

CCPD(Chinese City Parking Dataset)是目前最全面的中文车牌识别数据集之一,包含超过 30 万张真实场景下的车牌图像。数据集特点包括:

CCPD 数据集实战指南:从数据预处理到模型训练的全流程解析

  • 覆盖不同天气条件(晴天、雨天、雾天等)
  • 多种角度和光照变化
  • 包含新能源车牌和普通蓝牌
  • 每张图片附带精确的边界框(bounding box)和车牌号标注

新手常见问题:

  • 标注信息分散在文件名和额外 txt 文件中
  • 图像尺寸不统一(从几十 KB 到几 MB 不等)
  • 特殊字符(如新能源车牌字母 ’D’)需要特殊处理

数据准备

  1. 下载数据集:
  2. 官方地址:https://github.com/detectRecog/CCPD
  3. 建议下载 CCPD2019 基础版(约 12GB)

  4. 目录结构:

    CCPD2019/
    ├── ccpd_base/    # 基础数据集
    │   ├── 01_92_182_26_92_182_26_182.jpg
    │   └── ...
    ├── ccpd_blur/    # 模糊车牌
    ├── ccpd_db/      # 低亮度车牌
    └── ccpd_fn/      # 夜间车牌

  5. 文件名解析:
    示例文件名 01_92_182_26_92_182_26_182.jpg 包含:

  6. 车牌号:苏 A92E26
  7. 边界框坐标:(182,92)到(182,26)

预处理流程

完整 Python 处理脚本:

import cv2
import os
from pathlib import Path

# 解析文件名获取标注信息
def parse_filename(filename):
    parts = filename.split('_')
    # 车牌号转换(示例:01-> 苏, 92->A)province_code = parts[0]
    plate_number = parts[1] + parts[2] + parts[3]
    # 边界框坐标
    left, top = int(parts[4]), int(parts[5])
    right, bottom = int(parts[6]), int(parts[7])
    return {'plate': f'{province_dict[province_code]}{plate_number}',
        'bbox': [left, top, right, bottom]
    }

# 转换所有数据
def convert_dataset(input_dir, output_dir):
    Path(output_dir).mkdir(exist_ok=True)

    for img_file in Path(input_dir).glob('*.jpg'):
        img = cv2.imread(str(img_file))
        info = parse_filename(img_file.stem)

        # 保存为 YOLO 格式
        with open(f'{output_dir}/{img_file.stem}.txt', 'w') as f:
            x_center = (info['bbox'][0] + info['bbox'][2]) / 2 / img.shape[1]
            y_center = (info['bbox'][1] + info['bbox'][3]) / 2 / img.shape[0]
            width = abs(info['bbox'][2] - info['bbox'][0]) / img.shape[1]
            height = abs(info['bbox'][3] - info['bbox'][1]) / img.shape[0]
            f.write(f"0 {x_center} {y_center} {width} {height}")

        # 保存调整后的图像
        cv2.imwrite(f'{output_dir}/{img_file.name}', img)

数据增强

针对车牌识别的特殊增强方法:

  1. 透视变换(模拟不同拍摄角度):

    def perspective_transform(img):
        h, w = img.shape[:2]
        pts1 = np.float32([[0,0], [w,0], [0,h], [w,h]])
        pts2 = np.float32([[0,0], [w,0], [random.randint(0,50),h], 
                           [random.randint(w-50,w),h]])
        M = cv2.getPerspectiveTransform(pts1, pts2)
        return cv2.warpPerspective(img, M, (w,h))

  2. 颜色扰动(应对不同光照条件):

    def color_jitter(img):
        img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
        img[:,:,1] = img[:,:,1] * random.uniform(0.7, 1.3)  # 饱和度变化
        img[:,:,2] = img[:,:,2] * random.uniform(0.7, 1.3)  # 明度变化
        return cv2.cvtColor(img, cv2.COLOR_HSV2BGR)

  3. 模糊处理(模拟运动模糊):

    def motion_blur(img):
        kernel_size = random.randint(3, 10)
        kernel = np.zeros((kernel_size, kernel_size))
        kernel[:, kernel_size//2] = 1/kernel_size
        return cv2.filter2D(img, -1, kernel)

模型训练

PyTorch 基础训练示例:

import torch
import torchvision

# 自定义数据集类
class LicensePlateDataset(torch.utils.data.Dataset):
    def __init__(self, img_dir, transform=None):
        self.img_dir = Path(img_dir)
        self.img_files = list(self.img_dir.glob('*.jpg'))
        self.transform = transform

    def __len__(self):
        return len(self.img_files)

    def __getitem__(self, idx):
        img_path = self.img_files[idx]
        img = cv2.imread(str(img_path))

        # 读取对应标注文件
        with open(str(img_path).replace('.jpg', '.txt')) as f:
            label = f.read().strip()

        if self.transform:
            img = self.transform(img)

        return img, label

# 定义简单 CNN 模型
class PlateRecognitionModel(torch.nn.Module):
    def __init__(self, num_classes=68):  # 31 个省份 +10 数字 +24 字母 + 新能源
        super().__init__()
        self.backbone = torchvision.models.resnet18(pretrained=True)
        self.fc = torch.nn.Linear(512, num_classes)

    def forward(self, x):
        features = self.backbone(x)
        return self.fc(features)

# 训练循环
def train(model, dataloader, criterion, optimizer, epochs=10):
    for epoch in range(epochs):
        for imgs, labels in dataloader:
            optimizer.zero_grad()
            outputs = model(imgs)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()

避坑指南

  1. 字符编码问题:
  2. 新能源车牌包含特殊字母(如 ’D’)
  3. 解决方案:建立完整字符映射表(31 省份简称 +24 字母 +10 数字)

  4. 标注格式混淆:

  5. CCPD 同时使用文件名和 txt 存储标注
  6. 建议:预处理时统一转换为 YOLO 或 COCO 格式

  7. 图像尺寸差异大:

  8. 直接 resize 会导致小车牌模糊
  9. 解决方案:先检测车牌区域再 resize

性能优化

  1. 模型层面:
  2. 使用 CRNN(CNN+RNN)处理序列识别
  3. 添加注意力机制提升小目标检测

  4. 数据层面:

  5. 针对模糊 / 低照度样本过采样
  6. 使用 GAN 生成极端天气样本

  7. 后处理:

  8. 基于车牌规则校验(如省份简称校验)
  9. 时序融合(对视频流连续帧结果投票)

实践建议

  1. 从小数据集开始(如 CCPD_base 的 10% 样本)验证流程
  2. 使用 wandb 或 tensorboard 监控训练过程
  3. 尝试在自有数据上微调模型

希望这篇指南能帮助你快速上手 CCPD 数据集!如果在复现过程中遇到问题,建议先检查数据预处理是否正确,这是大多数错误的根源。

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