YOLO目标检测与车牌识别问题
超越传统OCR极限,基于YOLO的三阶段流水线实战车牌识别系统
问题意识
传统的OCR在干净的文件上表现良好,但在如车牌般模糊且倾斜的图像中则很脆弱。当字符间距不规则或部分被遮挡时,识别率急剧下降。此外,韩国汽车车牌的字符排列多样,混合了地名和数字,一般的OCR模型存在局限性。
该项目采用将字符视为对象而非文本的观点。通过基于YOLO的对象检测独立定位每个字符,并对原图和校正图像执行双重OCR验证。通过NMS和极点线拟合分离地名和数字,即使在传统OCR失败的环境中也能稳定工作。
三阶段流水线
整个流程由detect.py的get_num()函数单一控制。三个ONNX模型各自专注于其专业领域。
阶段 | 模型 | 角色 |
|---|---|---|
1 |
| 从整体图像中检测车牌区域 |
2 |
| 检测四个角点后进行透视校正 |
3 |
| 检测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性能较慢且较重。此外,由于分为多个阶段且使用不同模型,仍存在优化问题。
然而,该项目的本质在于在不使用预处理的情况下验证识别率。若能在未来有效使用预处理并通过单一模型识别并组合车牌及字符,则能够在保留或提升识别率的同时提高检测速度。
结束语
在进行这个项目的过程中,我首次将机器学习应用于服务中。这是一个有意义的项目,因其在微调模型上及新方法的尝试上。
从现在的角度来看,我发现了许多改进点。希望在未来对程序进行更新,以提升性能和速度。