Skip to main content
Mandacode mandacode
YOLO目标检测与车牌识别问题
·
OCR Python YOLO

YOLO目标检测与车牌识别问题

超越传统OCR极限,基于YOLO的三阶段流水线实战车牌识别系统

问题意识

传统的OCR在干净的文件上表现良好,但在如车牌般模糊且倾斜的图像中则很脆弱。当字符间距不规则或部分被遮挡时,识别率急剧下降。此外,韩国汽车车牌的字符排列多样,混合了地名和数字,一般的OCR模型存在局限性。

该项目采用将字符视为对象而非文本的观点。通过基于YOLO的对象检测独立定位每个字符,并对原图和校正图像执行双重OCR验证。通过NMS和极点线拟合分离地名和数字,即使在传统OCR失败的环境中也能稳定工作。

三阶段流水线

整个流程由detect.pyget_num()函数单一控制。三个ONNX模型各自专注于其专业领域。

阶段

模型

角色

1

plate_detect_v1

从整体图像中检测车牌区域

2

vertex_detect_v1

检测四个角点后进行透视校正

3

syllable_detect_v1

检测75个类别的单个字符

第一个模型从整体图像中找到一个车牌区域,并从多个候选中选出可信度最高的进行裁剪。第二个模型在裁剪的图像中检测四个角点并进行透视校正。第三个模型将75个类别的单个字符检测为对象。不同于传统OCR读取文本行,该方法定位车牌内每个字符的位置,因此即使字符间距不规则或部分遮挡,其他部分仍能被识别。

graph LR
    Input[输入图像] --> Plate[车牌检测]
    Plate --> Crop[车牌裁剪]
    Crop --> Vertex[角点检测]
    Vertex --> Warp[透视校正]
    Warp --> OCR1[校正图像 OCR]
    OCR1 --> Validate1[正则表达式验证]
    Validate1 -->|通过| Output[最终号码]
    Validate1 -->|失败| OCR2[裁剪图像 OCR]
    Crop --> OCR2
    OCR2 --> Validate2[正则表达式验证]
    Validate2 --> Output

验证与回退:稳定与效率的平衡

透视转换不总是完美的。角点检测可能失败,或者遇到倾斜的车牌。

该项目优先进行校正图像的OCR,通过正则表达式验证后立即返回结果。失败时才回退到原始裁剪图像进行额外OCR。

def get_num(img):
    cropped = plate_detector.detect_and_crop(img)
    warped = vertex_detector.detect_and_warp(cropped)

    # Step 1: 优先进行校正图像的OCR
    if warped is not None:
        res = syllable_detector.get_num_from_img(warped)
        result = validate_plate_num(res, mask=False)
        if result:
            return result

    # Step 2: 回退 - 裁剪图像OCR
    if cropped is not None:
        res = syllable_detector.get_num_from_img(cropped)
        result = validate_plate_num(res, mask=False)
        if result:
            return result

    return None

def validate_plate_num(plate_num, mask=True):
    """对单个OCR结果进行regex验证 + 应用mask"""
    if plate_num is None:
        plate_num = ''

    m = re.fullmatch(PLATE_REGEX, plate_num)
    if m is None:
        return None

    if mask:
        plate_num = re.search(OUTPUT_REGEX, plate_num).group()

    return plate_num

这种方法在warping成功时只需OCR一次,失败时才回退到裁剪图像。确保减少不必要推理的同时保持稳定性。

在字符检测后,通过NMS移除重复的边界框,并依据左右端点画线分离地名和数字区域。通过与预设的有效地名列表对比纠正地名,如首尔、京畿、釜山等。

sequenceDiagram
    participant Detect as detect.py
    participant ONNX as ONNX Runtime
    participant Validate as validate_plate_num

    Detect->>ONNX: 识别校正图像中的字符
    ONNX-->>Detect: 返回结果
    Detect->>Validate: 正则表达式验证

    alt 验证通过
        Validate-->>Detect: 返回最终号码
    else 验证失败
        Detect->>ONNX: 识别裁剪图像中的字符
        ONNX-->>Detect: 返回结果
        Detect->>Validate: 正则表达式验证
        alt 验证通过
            Validate-->>Detect: 返回最终号码
        else
            Validate-->>Detect: 返回失败
        end
    end

以用户为中心的GUI设计

当批处理过程中某些图像未能检测到时该怎么办?忽略这些图像可能降低数据质量,而中断整个处理又会降低效率。

基于PySide6的GUI在检测失败时自动暂停并在屏幕上显示相关图像。在用户手动输入车牌号码并按下确认键之前,程序将暂停处理。

这是为需要准确检测所有数据的情况而设计的,通过让用户判断而不是随机修正不完整部分。

权衡与设计哲学

基于YOLO的字符检测相比预处理的OCR性能较慢且较重。此外,由于分为多个阶段且使用不同模型,仍存在优化问题。

然而,该项目的本质在于在不使用预处理的情况下验证识别率。若能在未来有效使用预处理并通过单一模型识别并组合车牌及字符,则能够在保留或提升识别率的同时提高检测速度。

结束语

在进行这个项目的过程中,我首次将机器学习应用于服务中。这是一个有意义的项目,因其在微调模型上及新方法的尝试上。

从现在的角度来看,我发现了许多改进点。希望在未来对程序进行更新,以提升性能和速度。