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

1次阅读
没有评论

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

image.webp

背景痛点:为什么需要自动化标注转换?

刚开始接触 CCPD 数据集时,我对着那些.txt 文件发呆了半天。原始标注文件长这样:

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

 车牌图片路径 四点坐标 (x1,y1,x2,y2,x3,y3,x4,y4) 倾斜角度 车牌号码 

但 YOLO 需要的格式却是:

 类别序号 中心点 x 中心点 y 宽度 高度 (均需归一化)

手动转换?我试过处理 100 张图就花了半小时,还总把坐标算错。更别提数据集动辄几万张的规模了 …

技术方案拆解

1. 解析 CCPD 的标注结构

每个 txt 行包含三大关键信息:
四点坐标 :定义车牌在图像中的四边形区域
倾斜角度 :处理旋转车牌的必备参数
车牌号码 :可用于分类任务(本文暂不展开)

2. 坐标系转换核心算法

关键步骤:

  1. 从四边形到矩形:通过四点坐标计算最小外接矩形
  2. 坐标归一化:将像素坐标转换为 0 - 1 之间的相对值
  3. 格式适配:不同框架需要不同格式(YOLO/PASCAL VOC 等)

转换公式示例(YOLO 格式):

 中心点 x = (x_min + x_max) / 2 / 图像宽度
中心点 y = (y_min + y_max) / 2 / 图像高度
宽度 = (x_max - x_min) / 图像宽度
高度 = (y_max - y_min) / 图像高度 

3. 多格式输出设计

建议采用工厂模式,通过统一接口支持多种输出格式:

class AnnotationConverter:
    @staticmethod
    def to_yolo(points, img_size):
        # 实现 YOLO 格式转换
        ...

    @staticmethod
    def to_voc(points, img_size):
        # 实现 PASCAL VOC 格式转换
        ...

代码实现(带完整异常处理)

import os
import numpy as np
from multiprocessing import Pool

class CCPDParser:
    def __init__(self, annotation_dir):
        self.annotation_dir = annotation_dir

    def parse_single_file(self, txt_path):
        """解析单个标注文件"""
        try:
            with open(txt_path, 'r') as f:
                line = f.readline().strip()

            parts = line.split()
            if len(parts) < 9:  # 基本校验
                raise ValueError(f"Invalid annotation format in {txt_path}")

            # 解析四点坐标(注意转换为整数)points = np.array([float(x) for x in parts[1:9]]).reshape(4, 2)
            return {'image_path': parts[0],
                'points': points,
                'angle': float(parts[9]),
                'plate_number': ' '.join(parts[10:])
            }
        except Exception as e:
            print(f"Error parsing {txt_path}: {str(e)}")
            return None

class CoordinateConverter:
    @staticmethod
    def quadrilateral_to_yolo(points, img_size):
        """将四边形转换为 YOLO 格式"""
        x_coords = points[:, 0]
        y_coords = points[:, 1]

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

        # 归一化处理
        width, height = img_size
        x_center = ((x_min + x_max) / 2) / width
        y_center = ((y_min + y_max) / 2) / height
        w = (x_max - x_min) / width
        h = (y_max - y_min) / height

        return [x_center, y_center, w, h]

# 使用示例
if __name__ == "__main__":
    parser = CCPDParser("CCPD2020/annotations")
    sample_data = parser.parse_single_file("sample.txt")

    if sample_data:
        img_size = (1920, 1080)  # 假设图像尺寸
        yolo_coords = CoordinateConverter.quadrilateral_to_yolo(sample_data['points'], img_size
        )
        print(f"YOLO 格式坐标: {yolo_coords}")

避坑指南

1. 倾斜车牌处理

当遇到旋转角度大的车牌时,简单取 min/max 会丢失区域信息。解决方案:

  • 使用 cv2.minAreaRect 计算旋转矩形
  • 或保留原始四边形作为多边形标注(需框架支持)

2. 多线程批处理

def process_batch(annotation_files):
    with Pool(processes=4) as pool:  # 4 进程并行
        results = pool.map(parse_single_file, annotation_files)
    return [r for r in results if r is not None]

注意:
– 避免直接写同一文件
– 使用队列管理 IO 密集型任务

3. 数据泄漏预防

在划分训练 / 验证集时:
– 按车牌号码哈希分桶(防止同一车牌出现在两个集合)
– 使用 sklearn 的 StratifiedKFold 保持类别分布

扩展思考

  1. 跨数据集适配 :如何修改代码以支持 CRPD 等其它车牌数据集?
  2. 关键点是抽象解析逻辑,通过继承实现不同数据源的适配

  3. 格式对比实验 :YOLO 格式与 COCO 格式在训练效率上有何差异?

  4. 建议用相同数据分别训练,比较 mAP 和训练速度

  5. 自动化验证 :如何自动检查标注转换的正确性?

  6. 可开发可视化工具叠加显示原图与转换后的 bbox

结语

处理完第一批数据时,看着自动生成的几千个标注文件,终于不用再熬夜手动改坐标了。建议大家在实践中思考:

  1. 如果车牌被严重遮挡,四点坐标还可靠吗?
  2. 如何扩展支持车牌颜色分类?
  3. 当处理 100 万 + 数据时,如何优化内存使用?

希望本指南能帮你跳过那些我踩过的坑。完整代码已放在 GitHub(示例链接),欢迎提交改进建议!

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