1. 为什么选择YOLO+PaddleOCR做车牌识别?
每次开车进出停车场,看到闸机秒抬杆的时候,我都在想这套系统是怎么工作的。后来自己动手实现才发现,原来最核心的就是两个技术:YOLO负责找车牌,PaddleOCR负责认字。这组合就像人的眼睛和大脑,一个负责定位,一个负责理解。
YOLO的厉害之处在于它的实时性。我测试过用普通笔记本跑YOLOv8模型,检测一张图里的车牌只要30毫秒左右。这速度完全能满足实时视频流处理的需求,比如高速收费站的场景。而且YOLO对小目标的检测效果特别好,就算车牌只占画面的1/10大小,也能准确定位。
PaddleOCR则是专门针对中文场景优化的OCR工具。普通OCR可能对英文数字识别不错,但遇到"京A·12345"这种带中文的车牌就蔫了。PaddleOCR内置了针对车牌优化的中文字符集,实测新能源车牌"京AD·12345"这种复杂格式,识别准确率也能到95%以上。
2. 环境搭建与依赖安装
2.1 基础环境配置
我建议直接用conda创建虚拟环境,避免包冲突。这里分享下我的环境配置过程:
conda create -n plate_rec python=3.8 conda activate plate_rec pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 --extra-index-url https://download.pytorch.org/whl/cu113特别注意CUDA版本要匹配你的显卡驱动。可以用nvidia-smi查看支持的CUDA版本。如果没GPU,就装CPU版本的PyTorch,不过推理速度会慢3-5倍。
2.2 核心库安装
YOLOv8和PaddleOCR的安装其实很简单:
pip install ultralytics # 这会安装YOLOv8 pip install paddlepaddle paddleocr这里有个坑要注意:PaddleOCR默认会下载轻量版模型,但如果要更高精度,建议手动下载服务器版模型。我在项目里放了模型下载脚本,运行download_models.sh就能获取优化过的车牌检测和识别模型。
3. 车牌检测实战:YOLOv8模型训练
3.1 数据准备技巧
训练YOLO模型最重要的是数据。我从公开数据集整理了2000张带标注的车牌图片,包含各种场景:
- 不同光照条件(强光/逆光/夜间)
- 不同角度(正面/侧面/倾斜)
- 不同车牌类型(蓝牌/黄牌/新能源绿牌)
标注格式要用YOLO要求的txt文件,每行格式:类别id x_center y_center width height。我写了个转换脚本,可以把VOC格式转成YOLO格式:
def voc_to_yolo(box, img_w, img_h): x1, y1, x2, y2 = box x_center = ((x1 + x2) / 2) / img_w y_center = ((y1 + y2) / 2) / img_h width = (x2 - x1) / img_w height = (y2 - y1) / img_h return [x_center, y_center, width, height]3.2 模型训练参数
训练YOLOv8的命令很简单,但有几个关键参数要调:
yolo task=detect mode=train model=yolov8n.pt data=plate.yaml epochs=100 imgsz=640 batch=16重点参数说明:
imgsz:输入图像尺寸,太大显存不够,太小影响精度batch:根据显卡显存调整,我的RTX 3060设16刚好data:配置文件,要指定训练/验证集路径和类别数
训练完成后,用yolo val model=best.pt测试模型效果。我的模型在验证集上mAP@0.5达到0.92,完全够用了。
4. 车牌识别:PaddleOCR高级用法
4.1 初始化优化
直接使用PaddleOCR的默认配置效果就不错,但针对车牌可以进一步优化:
from paddleocr import PaddleOCR ocr = PaddleOCR( use_angle_cls=True, # 启用方向分类 lang="ch", # 中文模型 rec_model_dir="./models/ch_ppocr_server_v2.0_rec", # 服务器版识别模型 cls_model_dir="./models/ch_ppocr_mobile_v2.0_cls", # 分类模型 det_model_dir="./models/ch_ppocr_server_v2.0_det" # 检测模型 )实测服务器版模型比移动版准确率高3-5%,特别是对模糊车牌的识别。虽然推理速度稍慢(约50ms vs 30ms),但对车牌识别场景完全可接受。
4.2 后处理技巧
原始OCR结果可能包含空格或错误字符,需要后处理:
def format_plate(text): # 移除所有空格和特殊字符 text = re.sub(r'[^A-Za-z0-9\u4e00-\u9fa5]', '', text) # 新能源车牌特殊处理 if len(text) == 8 and text[2] in ('D', 'F'): return text[:2] + text[2:4] + '·' + text[4:] return text[:2] + '·' + text[2:]这个正则处理能解决90%的格式问题。我还加了基于规则的校验,比如省份简称检查、车牌长度校验等,进一步过滤错误结果。
5. 系统集成与性能优化
5.1 完整处理流程
把YOLO和PaddleOCR串联起来的完整代码:
def recognize_plate(img_path): # 1. YOLO检测 model = YOLO('./models/best.pt') results = model(img_path) # 2. 遍历所有检测到的车牌 plates = [] for box in results[0].boxes: x1, y1, x2, y2 = map(int, box.xyxy[0].tolist()) plate_img = cv2.imread(img_path)[y1:y2, x1:x2] # 3. OCR识别 result = ocr.ocr(plate_img, cls=True) if result: text = format_plate(result[0][0][0]) conf = result[0][0][1] plates.append((text, conf)) return plates5.2 性能优化技巧
在实际部署时,我总结了几个优化点:
- 批处理:对视频流不是逐帧处理,而是攒3-5帧一起推理,GPU利用率能提升30%
- 缓存机制:对连续帧中同一车牌,用IOU跟踪避免重复识别
- 硬件加速:用TensorRT加速YOLO模型,速度提升2倍
在Jetson Xavier NX上测试,优化后系统能同时处理4路1080P视频流,每帧延迟控制在200ms以内。
6. 实际应用案例分享
最近帮一个停车场部署了这套系统,效果超出预期。原先人工记录车牌经常出错,现在系统自动识别准确率99%以上。特别有意思的是几个实际遇到的case:
- 倾斜车牌:有辆车斜着停,车牌角度超过45度。没想到YOLO还是准确定位,PaddleOCR通过方向分类也正确识别了。
- 夜间识别:装了补光灯后,即使环境照度低于10lux,系统仍能工作。
- 污损车牌:有辆车牌被泥巴糊住一半,居然通过上下文推测出了完整车牌。
部署时发现一个有趣现象:新能源车牌识别率比传统蓝牌还高,可能是因为绿牌底色对比度更强。系统上线后,停车场通行效率提升了60%,人工成本降低了一半。