1. CCPD数据集概述与下载指南

CCPD(Chinese City Parking Dataset)是目前国内规模最大、标注最完善的开源车牌数据集之一。我第一次接触这个数据集是在2019年做智能交通项目时,当时为了找合适的车牌数据翻遍了国内外平台,直到发现CCPD才真正解决了数据瓶颈问题。

这个数据集分为两个主要版本:

  • CCPD2019 :包含25万+蓝色普通车牌图像
  • CCPD2020 :专为新能源车设计的绿色车牌数据集

数据集最让我惊喜的是其丰富的场景覆盖:

  • 不同天气条件(雨雪雾)
  • 各种拍摄角度(水平倾斜最高50度)
  • 多种光照情况(过曝/欠曝)
  • 运动模糊等真实场景干扰

下载方式很简单:

# CCPD2019 (12.26GB)
wget https://example.com/ccpd2019.zip  # 替换为实际下载链接

# CCPD2020 (865MB) 
wget https://example.com/ccpd2020.zip

实测发现百度云下载速度更快,建议用官方提供的百度云链接。下载后记得校验MD5值,我遇到过两次下载中断导致文件损坏的情况。

2. 数据标注解析实战

CCPD最特别的是其"文件名即标注"的设计。刚开始用的时候觉得这种设计很反人类,但熟悉后发现其实非常高效。来看个典型文件名示例:

025-95_113-154&383_386&473-386&473_177&454_154&383_363&402-0_0_22_27_27_33_16-37-15.jpg

用Python解析非常方便:

def parse_filename(filename):
    parts = filename.split('-')
    return {
        'ratio': parts[0],  # 车牌区域占比
        'angle': list(map(int, parts[1].split('_'))),  # 水平/垂直倾斜角
        'bbox': [list(map(int, p.split('&'))) for p in parts[2].split('_')],  # 边界框
        'vertices': [list(map(int, p.split('&'))) for p in parts[3].split('_')],  # 四顶点坐标
        'plate_num': decode_plate(parts[4]),  # 车牌号码
        'brightness': int(parts[5]),  # 亮度值
        'blurriness': int(parts[6].split('.')[0])  # 模糊度
    }

车牌号码的解码需要特别注意:

provinces = ["皖", "沪", "津", "渝", "冀", "晋", "蒙", "辽", "吉", "黑", "苏", "浙", "京", 
             "闽", "赣", "鲁", "豫", "鄂", "湘", "粤", "桂", "琼", "川", "贵", "云", "藏", 
             "陕", "甘", "青", "宁", "新"]

def decode_plate(plate_str):
    codes = list(map(int, plate_str.split('_')))
    province = provinces[codes[0]]
    chars = [chr(ord('A')+x) if x<26 else str(x-26) for x in codes[1:]]
    return province + ''.join(chars)

3. 数据预处理技巧

3.1 图像增强方案

在车牌识别任务中,我常用的增强组合是:

transform = transforms.Compose([
    transforms.ColorJitter(brightness=0.3, contrast=0.3),  # 应对光照变化
    transforms.RandomRotation(10),  # 增强旋转鲁棒性
    transforms.RandomPerspective(distortion_scale=0.2),  # 模拟视角变化
    GaussianBlur(kernel_size=3)  # 抗模糊
])

3.2 数据清洗经验

CCPD虽然标注质量整体不错,但仍有约3%的脏数据需要处理。我通常用以下规则过滤:

  1. 检查边界框是否超出图像范围
  2. 验证车牌号码是否符合编码规则
  3. 剔除亮度/模糊度极值样本
def is_valid_sample(metadata):
    # 检查边界框
    x1, y1 = metadata['bbox'][0]
    x2, y2 = metadata['bbox'][1]
    if not (0 <= x1 < x2 < 720 and 0 <= y1 < y2 < 1160):
        return False
        
    # 检查车牌号码
    plate = metadata['plate_num']
    if len(plate) not in (7,8) or not plate[0] in provinces:
        return False
        
    return True

4. 模型训练实战

4.1 YOLOv5检测模型配置

推荐使用以下配置进行训练:

# yolov5s_ccpd.yaml
nc: 1  # 只有车牌一个类别
depth_multiple: 0.33
width_multiple: 0.50

anchors:
  - [10,13, 16,30, 33,23]  # P3/8
  - [30,61, 62,45, 59,119]  # P4/16
  - [116,90, 156,198, 373,326]  # P5/32

启动训练命令:

python train.py --img 640 --batch 32 --epochs 100 --data ccpd.yaml --cfg yolov5s_ccpd.yaml --weights yolov5s.pt

4.2 LPRNet识别模型优化

针对车牌识别任务,我对原始LPRNet做了三点改进:

  1. 增加空间注意力模块
  2. 调整CNN通道数适配车牌长宽比
  3. 使用Focal Loss解决字符类别不平衡

关键修改部分:

class EnhancedLPRNet(nn.Module):
    def __init__(self, lpr_max_len=8):
        super().__init__()
        self.backbone = nn.Sequential(
            nn.Conv2d(3, 64, 3, 1),
            nn.BatchNorm2d(64),
            SpatialAttention(),  # 新增注意力
            nn.ReLU(),
            # ... 其他层保持不变
        )
        self.loss = FocalLoss(gamma=2)  # 替换原始CrossEntropy

5. 模型部署与性能优化

5.1 TensorRT加速实践

将PyTorch模型转为TensorRT能获得3-5倍加速:

# 转换脚本示例
builder = trt.Builder(TRT_LOGGER)
network = builder.create_network()
parser = trt.OnnxParser(network, TRT_LOGGER)

# 加载ONNX模型
with open("lprnet.onnx", "rb") as f:
    parser.parse(f.read())

# 配置优化参数
config = builder.create_builder_config()
config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, 1 << 30)
engine = builder.build_engine(network, config)

5.2 端侧部署技巧

在树莓派等边缘设备上,我推荐:

  1. 使用量化后的TFLite模型
  2. 开启ARM NEON加速
  3. 采用多线程流水线处理

实测性能对比:

设备 原始模型 优化后 提升
Jetson Nano 12 FPS 28 FPS 2.3x
Raspberry Pi 4 3 FPS 9 FPS 3x

6. 常见问题解决方案

问题1:小尺寸车牌检测效果差

  • 解决方案:在YOLOv5中添加小目标检测层
  • 修改模型配置:
# 添加P2检测头
head:
  [[-1, 1, Conv, [256, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 3], 1, Concat, [1]],
   [-1, 3, C3, [256, False]],
   [-1, 1, Conv, [256, 3, 2]],
   [[-1, 4], 1, Concat, [1]],
   [-1, 3, C3, [512, False]],
   # ... 原有结构
  ]

问题2:新能源车牌识别率低

  • 根本原因:CCPD2020数据量较少
  • 解决方案:
    1. 使用迁移学习,先用CCPD2019预训练
    2. 添加新能源车牌数据增强:
# 模拟绿色车牌色调
def green_plate_aug(img):
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    hsv[:,:,0] = hsv[:,:,0] * 0.7  # 调整色相
    return cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)

在实际项目中,建议定期用bad case分析工具找出模型弱点,有针对性地补充训练数据。我开发了一个自动化分析工具,可以自动聚类识别错误的样本类型。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐