CCPD数据集标注文件生成实战:从数据解析到格式转换全流程指南

1次阅读
没有评论

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

image.webp

背景痛点

CCPD 数据集是车牌识别领域常用的公开数据集,但它的原始标注格式与常见的 YOLO、PASCAL VOC 等格式存在显著差异。CCPD 的标注信息存储在以图片名命名的.txt 文件中,包含车牌四点坐标、倾斜角度、车牌号码等信息。而 YOLO 格式需要的是归一化的中心点坐标和宽高,PASCAL VOC 则需要 XML 格式的标注。手动转换这些格式不仅耗时,还容易出错,特别是当数据量达到数万张时,几乎不可行。

CCPD 数据集标注文件生成实战:从数据解析到格式转换全流程指南

技术方案

解析 CCPD 标注文件结构

CCPD 的标注文件内容通常如下所示:

 车牌号码 四点坐标 (x1,y1,x2,y2,x3,y3,x4,y4) 倾斜角度 其他信息 

我们需要解析这些信息,并提取出车牌区域的边界框。

坐标系转换算法

YOLO 格式需要将四点坐标转换为归一化的中心点坐标和宽高。步骤如下:

  1. 从四点坐标中找出最小和最大的 x、y 值,确定边界框
  2. 计算中心点坐标:(x_min + x_max)/2 和 (y_min + y_max)/2
  3. 计算宽度和高度:x_max - x_min 和 y_max - y_min
  4. 归一化:将上述值除以图像宽度和高度

多格式输出支持

我们将实现一个转换器类,支持输出 YOLO 和 PASCAL VOC 格式。YOLO 格式简单,适合快速训练;PASCAL VOC 格式更详细,适合需要更多信息的场景。

代码实现

以下是 Python 实现的核心代码:

import os
import xml.etree.ElementTree as ET
from typing import List, Tuple

class CCPDAnnotationConverter:
    """CCPD 标注文件转换器"""

    def __init__(self, img_width: int, img_height: int):
        self.img_width = img_width
        self.img_height = img_height

    def parse_ccpd_line(self, line: str) -> dict:
        """解析 CCPD 单行标注"""
        parts = line.strip().split()
        if len(parts) < 9:
            raise ValueError("Invalid CCPD annotation format")

        plate_number = parts[0]
        points = list(map(float, parts[1:9]))
        angle = float(parts[9])

        return {
            'plate_number': plate_number,
            'points': points,
            'angle': angle
        }

    def convert_to_yolo(self, points: List[float]) -> Tuple[float, float, float, float]:
        """将四点坐标转换为 YOLO 格式"""
        x_coords = points[0::2]
        y_coords = points[1::2]

        x_min, x_max = min(x_coords), max(x_coords)
        y_min, y_max = min(y_coords), max(y_coords)

        # 计算中心点和宽高
        x_center = (x_min + x_max) / 2 / self.img_width
        y_center = (y_min + y_max) / 2 / self.img_height
        width = (x_max - x_min) / self.img_width
        height = (y_max - y_min) / self.img_height

        return x_center, y_center, width, height

    def convert_to_voc(self, points: List[float], plate_number: str) -> ET.Element:
        """转换为 PASCAL VOC 格式"""
        annotation = ET.Element('annotation')

        # 添加图像信息
        size = ET.SubElement(annotation, 'size')
        ET.SubElement(size, 'width').text = str(self.img_width)
        ET.SubElement(size, 'height').text = str(self.img_height)
        ET.SubElement(size, 'depth').text = '3'

        # 添加目标信息
        obj = ET.SubElement(annotation, 'object')
        ET.SubElement(obj, 'name').text = 'license_plate'
        ET.SubElement(obj, 'pose').text = 'Unspecified'
        ET.SubElement(obj, 'truncated').text = '0'
        ET.SubElement(obj, 'difficult').text = '0'

        bndbox = ET.SubElement(obj, 'bndbox')
        x_coords = points[0::2]
        y_coords = points[1::2]

        ET.SubElement(bndbox, 'xmin').text = str(int(min(x_coords)))
        ET.SubElement(bndbox, 'ymin').text = str(int(min(y_coords)))
        ET.SubElement(bndbox, 'xmax').text = str(int(max(x_coords)))
        ET.SubElement(bndbox, 'ymax').text = str(int(max(y_coords)))

        # 添加车牌号码
        ET.SubElement(obj, 'plate_number').text = plate_number

        return annotation

# 使用示例
if __name__ == '__main__':
    converter = CCPDAnnotationConverter(720, 1160)  # CCPD 典型图像尺寸

    # 示例 CCPD 标注行
    ccpd_line = "皖 AD12345 123.4 567.8 234.5 678.9 345.6 789.0 456.7 890.1 15 其他信息"

    # 解析
    parsed = converter.parse_ccpd_line(ccpd_line)

    # 转换为 YOLO 格式
    yolo_format = converter.convert_to_yolo(parsed['points'])
    print(f"YOLO 格式: {yolo_format}")

    # 转换为 VOC 格式
    voc_format = converter.convert_to_voc(parsed['points'], parsed['plate_number'])
    print(f"VOC 格式: {ET.tostring(voc_format, encoding='unicode')}")

避坑指南

处理倾斜车牌的坐标转换

CCPD 中的车牌经常有倾斜角度,直接取最小 / 最大 x,y 值得到的矩形框可能会包含过多背景。解决方案:

  1. 使用四点坐标计算最小外接矩形
  2. 考虑旋转角度调整边界框

多线程批处理的资源竞争

当处理大量文件时,使用多线程可以加速,但要注意:

  1. 避免多个线程同时写入同一个文件
  2. 使用队列管理任务分配
  3. 控制线程数量,避免内存不足

验证集划分时的数据泄漏

确保同一个车牌的不同角度图像不会同时出现在训练集和验证集中:

  1. 按车牌号码分组后再划分
  2. 使用分层抽样保证分布均衡

扩展思考

  1. 如何调整代码以支持其他车牌数据集(如 AOLP、PKU 等)?不同数据集的标注格式差异如何处理?
  2. YOLO 格式和 PASCAL VOC 格式在训练目标检测模型时,会有哪些性能差异?
  3. 对于极端倾斜(如大于 45 度)的车牌,当前的边界框表示方式是否仍然有效?如何改进?

总结

本文详细介绍了如何将 CCPD 数据集转换为常用标注格式的全过程。通过面向对象的设计,我们实现了一个灵活的转换工具,可以轻松扩展到其他格式和其他数据集。在实际应用中,还需要考虑数据增强、模型兼容性等问题,但有了标准化的标注文件,这些后续工作会变得容易很多。

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