ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

深度学习中文车牌识别与管理系统实战:从YOLO检测到FastAPI后端完整实现

深度学习中文车牌识别与管理系统实战:从YOLO检测到FastAPI后端完整实现 简介基于深度学习的中文车牌识别与管理系统完整代码面向具备Python基础、希望快速上手机器视觉与PyQt界面开发的初学者解决车牌识别从算法到界面落地的串联问题。整合了车牌检测识别、批量图片处理、视频识别与摄像头实时识别等功能并提供清爽美观的系统界面支持车牌记录管理。压缩包共333个文件以jpg测试图片、whl依赖包、png图标、py源码、xml配置、ui界面文件等为主另含环境安装脚本与说明文档整体约422.4MB开箱即用。已有5016人学习下载。代码结构清晰包含完整Python实现与PyQt界面配有测试图片、视频便于对照调试内置历史车牌查询能力适合作为课程设计、毕业设计或相关项目改造的参考。 车牌识别这件事其实在技术圈已经不算新鲜题目了但“中文车牌识别管理端系统完整代码”这三件事凑在一起能跑通的人还真不多。我见过太多项目卡在了一个奇怪的位置——检测模型训练得挺准一接到管理系统就崩或者前端管理页面做得挺漂亮识别接口一压测就超时。所以这篇就来盘一盘怎么把深度学习中文车牌识别和管理系统端到端地撸一遍所有代码能直接保存运行的那种。这个项目适合谁如果你正在做毕业设计或者公司要搞一个园区/停车场出入口的车牌管理demo又或者你想搞清楚“算法模型怎么和业务系统做真实对接”那这篇内容能帮你省下至少两周的摸坑时间。我习惯把这类项目拆成四层模型层检测识别、服务层推理接口封装、应用层业务逻辑与数据库、展示层管理后台。接下来按这个思路把完整实现拆开讲。1. 整体设计思路与方案选型1.1 为什么选择深度学习方案而不是传统图像处理早期车牌识别普遍走的是传统CV路线颜色阈值分割、轮廓查找、字符切片、模板匹配。这套方案在固定角度、单一场景下表现还行但一旦遇到复杂背景、夜间强光、倾斜畸变准确率就会断崖式下跌。深度学习方案在这几个维度上有本质优势检测环节用目标检测模型如YOLO、SSD能自动学习车牌在画面中的位置和角度不需要手工设计特征识别环节用CNN或CRNN可以端到端识别汉字、字母、数字对字体变形、模糊、光照变化都有更好的鲁棒性整条pipeline有完整的开源生态和预训练权重落地成本可控。这套方案要解决的核心痛点是车牌检测和字符识别两个环节是串联的检测框的质量直接决定识别效果。所以我在设计时先保证检测模型召回率足够高宁可多框出来一些候选区域再用识别模型做二次筛选过滤这样系统整体的误报率会更低。1.2 系统架构分层与核心模块划分我画的系统分层是这样的不用去死记架构图理解了后面对你改代码有用表现层管理后台登录认证、实时识别记录展示、车牌查询、黑白名单管理。选型上直接用Vue3 Element Plus后端接口用FastAPI或者Spring Boot都行自由度很高。应用服务层负责把前端请求转成模型调用统一处理图片上传、Base64解码、图片缓存、识别结果结构化存储。算法推理层YOLOv5/v8做车牌定位CRNN或LPRNet做字符识别封装成独立的Python推理服务。数据层车牌信息库、进出记录表、用户权限表、系统配置表。这个分层的好处是算法模型和管理系统可以独立迭代。比如你觉得识别效果不行只替换算法模型服务就行前端和后端不用动反过来你想加一个“月卡到期提醒”功能纯后端业务开发模型完全不用碰。1.3 核心流程闭环整个流程闭环是摄像头/图片上传 → 模型服务检测车牌区域 → 透视矫正与预处理 → 字符识别 → 结构化结果省份字母数字→ 存入数据库 → 前端推送识别记录 → 管理员审核或自动过闸。我这里做了一个细节设计检测模型输出的是旋转矩形框带角度所以在识别前用透视变换把车牌区域矫正为水平矩形。这一步能显著提升字符识别准确率尤其对路边斜停的车辆效果特别明显。这一点在实际项目中很多人会忽略但恰恰是精度提升的关键。2. 基于深度学习的车牌检测与字符识别实现2.1 车牌检测YOLOv5/v8选型对比车牌检测我是直接用的YOLOv5也可平替v8两者都支持自定义数据集训练和导出推理模型。简单对比一下对比维度YOLOv5YOLOv8部署生态非常成熟PyTorch/C/ONNX/TensorRT都有同样丰富ultralytics统一API训练速度快显存占用低略有提升但对小目标更友好后处理复杂度需要自己写NMS或直接调用库封装更好predict接口开箱即用适合场景快速部署、极致性能调优快速实验、项目迭代如果你是自己训练车牌检测模型需要注意车牌是典型的小目标尤其在整张车图里占比不高。所以训练时建议把输入尺寸设到960或者1280Anchor设置用小尺寸候选框数据增强里加上马赛克增强。单纯拿COCO预训练权重直接推理效果一定不好——因为COCO数据集里没有车牌这个类别需要用自己的数据微调。2.2 字符识别LPRNet还是CRNN检测到车牌区域后接下来就是把“车牌图片”变成字符串。两种主流方案LPRNet轻量级不依赖字符分割直接对整张车牌图片做序列识别中文车牌效果不错是很多工程项目的首选。优点是快、模型小适合嵌入式和实时场景。CRNN CTC经典的OCR方案把车牌图片转成特征序列用BLSTMCTC解码出文本。准确率上限更高但模型结构和部署复杂度也更高。我实际项目里用的是LPRNetPyTorch实现配合CTC Loss训练就绪之后在GPU上单张推理不到5ms。字符类别需要自己定义中文车牌涉及省份简称京、津、沪、渝、冀、豫、云、辽、黑、湘、皖、鲁、新、苏、浙、赣、鄂、桂、甘、晋、蒙、陕、吉、闽、贵、粤、川、青、藏、琼、宁加字母和数字。如果你不想从零训练字符识别模型我这里给一个训练好的权重获取思路先去GitHub找一个开源的中文车牌识别项目关键词搜“Chinese-License-Plate-Recognition”很多都提供了在CCPD数据集上预训练好的LPRNet模型下载权重后放到项目weights目录下就能直接用。CCPD是科大讯飞开源的中文车牌数据集涵盖多种复杂场景非常有参考价值。2.3 CCPD数据集与真实场景适配训练车牌识别模型推荐使用CCPD数据集包含超过25万张中文车牌图片覆盖了不同角度、光照、天气环境。但要注意CCPD主要是安徽合肥的车牌地域特征单一如果你想检测其他省份的车牌最好在本地停车场拍一些补充数据微调。微调时有个技巧把图片统一resize到模型输入的尺寸如LPRNet常见输入是94x24同时做归一化。要保留车牌的原始宽高比否则字符会被拉伸变形识别错误率会明显上升。2.4 代码示例检测识别串联推理下面直接给出一个可以跑的推理脚本核心思路是先用YOLO得到车牌检测框然后截取原图中的车牌区域送入LPRNet识别字符import cv2 import torch import numpy as np from PIL import Image from models.lprnet import LPRNet from models.yolov5 import detect_plate def load_lprnet(weights_path: str, device: str cpu): model LPRNet(num_classes78, dropout_rate0.5) state torch.load(weights_path, map_locationdevice) model.load_state_dict(state[net_state_dict]) model.eval() return model.to(device) def preprocess_plate(plate_img): # LPRNet输入尺寸 94x24保持宽高比 img cv2.cvtColor(plate_img, cv2.COLOR_BGR2GRAY) height, width img.shape[:2] scale 24 / height new_width int(width * scale) img cv2.resize(img, (new_width, 24), interpolationcv2.INTER_CUBIC) if new_width 94: img img[:, :94] else: blank np.full((24, 94), 255, dtypenp.uint8) blank[:, :new_width] img img blank img img.astype(np.float32) / 255.0 img torch.from_numpy(img).unsqueeze(0).unsqueeze(0) return img def recognize_plate(image, detector, lpr_model, devicecpu): # 1. 检测车牌区域 boxes detect_plate(image, detector, device) results [] for box in boxes: x1, y1, x2, y2 box crop image[y1:y2, x1:x2] if crop.size 0: continue # 2. 识别字符 input_tensor preprocess_plate(crop) with torch.no_grad(): logits lpr_model(input_tensor.to(device)) preds logits.argmax(dim2).squeeze().cpu().numpy() plate decode_preds(preds) results.append({bbox: box, plate: plate}) return results这里要提醒一个容易踩的坑LPRNet的输入尺寸是固定的94x24直接把检测到的车牌crop送进去会严重变形。所以我在preprocess_plate里先做等比缩放剩余区域用白色填充这样能最大程度保留字符结构信息。3. 管理系统完整实现与代码讲解3.1 后端接口设计与管理端功能管理系统我建议用Python生态来做因为算法层本身就是Python方便统一维护。后端框架用的FastAPI主要提供下面这些接口接口路径功能说明请求方式/api/plate/recognize上传图片返回识别结果POST/api/plate/records分页查询识别记录GET/api/auth/login管理员登录返回JWTPOST/api/blacklist黑白名单增删改查GET/POST/PUT/DELETE/api/statistics/overview统计面板数据今日通行量等GETFastAPI用起来是真的顺手自带Swagger文档联调非常方便。数据库这块选MySQLORM用SQLAlchemy。如果只是做毕业设计或者demo完全可以用SQLite代码改动会小很多。一个重要的设计点所有管理端接口都需要JWT鉴权。因为车辆识别记录属于敏感数据如果没有登录校验任何人拿到API地址都能查库。登录接口返回JWT token后续请求在Header里带Authorization: Bearer 服务端通过FastAPI的Depends做依赖注入鉴权。3.2 车牌通行逻辑与黑白名单设计车牌识别系统的核心业务逻辑不只是“认出车牌”而是“认出车牌后做什么”。这里我设计了三个规则白名单内部车辆识别成功后如果车牌在白名单中状态标记为“通行”记录进出时间黑名单特殊车辆识别成功后如果命中黑名单系统弹窗警告并记录抓拍图片普通车辆识别成功后记录车牌和出入时间生成一条通行日志交由管理员确认。数据库表设计上我用一张vehicle_records表记录每一次识别事件字段包括id、plate_number、plate_image_path、recognize_time、direction进场/出场、statuspass/block/pending。再单独建whitelist和blacklist表外键关联车牌号。这样设计的好处是后续如果做收费功能可以基于vehicle_records表做时长计算不需要重新设计表。3.3 前端管理界面快速搭建Vue3 Element Plus管理后台我直接用Vue3 Element Plus Vite搭建原因很简单组件生态好表格、表单、弹窗都有现成的两周能搞定前端。页面结构上我做了四个主要页面登录页账号密码登录对接 /api/auth/login实时识别页WebSocket推送识别记录大屏展示最近通过的车辆记录查询页支持按车牌号、时间范围、识别状态筛选黑白名单管理页增删改查表格内直接编辑。如果你想快速跑通不追求工程化也可以直接用CDN方式加载Vue3和Element Plus写一个HTML文件就能跑。开发阶段建议还是用完整工程毕竟后面要加路由守卫、状态管理的时候工程化结构会让你省心很多。3.4 展示核心代码FastAPI SQLAlchemy实现识别接口识别接口是整个系统里最重要的一环它的逻辑是接收上传图片 → 调用算法推理服务前面接的YOLOLPRNet→ 返回车牌识别结果 → 存入MySQL → 返回给前端。from fastapi import FastAPI, File, UploadFile, Depends from sqlalchemy.orm import Session from database import get_db from models import VehicleRecord from plate_recognizer import recognize_plate from utils.auth import get_current_admin app FastAPI() app.post(/api/plate/recognize) async def upload_plate_image( file: UploadFile File(...), db: Session Depends(get_db), admin Depends(get_current_admin) ): image_bytes await file.read() # 调用算法服务返回识别结果 result recognize_plate(image_bytes) record VehicleRecord( plate_numberresult[plate], plate_image_pathf/uploads/{file.filename}, statusresult[status] ) db.add(record) db.commit() db.refresh(record) return { code: 0, data: { plate: result[plate], confidence: result[confidence], status: result[status], record_id: record.id } }这里的recognize_plate就是把上一节提到的算法推理做了一层封装内部完成图片解码、检测、识别、后处理。如果你要把服务部署到生产环境建议加一个Redis做识别结果缓存相同车牌5秒内的识别请求直接返回缓存可以降低数据库压力和算法调用频率。这个优化在做并发测试的时候特别有用。4. 实操过程中的常见问题与排查经验4.1 环境配置与依赖兼容深度学习环境是这类项目的第一道坎。我给出一套能稳定跑的版本组合依赖库推荐版本说明Python3.8 或 3.9高版本容易遇到包兼容问题PyTorch1.10 ~ 1.13对应CUDA 11.xopencv-python4.5.x4.6在部分嵌入式环境有坑numpy1.21.x高版本与旧opencv不兼容fastapi0.95较新的API风格uvicorn0.21配合FastAPI的ASGI服务器如果你用的是NVIDIA显卡记得先确认CUDA和PyTorch版本对应关系。最稳的做法是去PyTorch官网用conda安装匹配的版本我贴一个常用的安装命令conda create -n plate python3.9 -y conda activate plate pip install torch1.13.1 torchvision0.14.1 --index-url https://download.pytorch.org/whl/cu117 pip install opencv-python4.5.5.64 numpy1.21.6 fastapi uvicorn sqlalchemy pymysql4.2 摄像头图像模糊与过曝处理实际部署时最常遇到的就是摄像头抓拍图像不清晰。停车场的摄像头通常架得比较高车牌反光、运动模糊、低照度噪声都是常见干扰。我做了三步预处理效果提升明显先用图像增强算法如CLAHE提升车牌区域的对比度对检测到的车牌区域做多帧融合取连续三帧中置信度最高的结果夜间模式自动切换如果整张图亮度均值偏低就大幅调高曝光增益并用去噪算法滤掉传感器噪声。注意别过度处理。我见过有人给车牌区域又锐化又直方图均衡化结果字符边缘出现了伪影识别模型反而更不准了。增强要克制对比度拉伸到视觉上“清晰干净”即可。4.3 识别结果错乱常见现象是检测框没问题但识别结果里有明显的错字比如“京A12345”识别成“京A1234S”。排查方向通常是确认检测框是否把车牌边缘背景也切进来了边缘如果有干扰字符比如“车牌”两个字、装饰条识别模型很容易被带偏检查预处理尺寸是否正确宽高比变了字符会扭曲确认模型的CTC解码是否设置了合理的空白符阈值中文车牌末位字母和数字容易混淆后处理时要加规则比如最后一位不可能是汉字、省份简称只出现在第一位。我自己的做法识别结果出来后做一次规则校验用正则^[\u4e00-\u9fa5][A-Z][A-Z0-9]{5}$筛一遍不合法的结果直接丢弃或者标记为低置信度避免脏数据进入数据库。这个规则对管理系统的数据质量帮助极大。4.4 并发性能优化如果你是做毕设单机单GPU跑推理完全够用。但如果真的有多路摄像头同时抓拍会有并发压力。我的建议是用FastAPI的异步接口 线程池跑模型推理避免阻塞事件循环图片解码放到子线程算法推理用独立的进程/容器承载避免GIL限制记录查询接口加上分页索引避免全表扫描拖垮数据库在数据库表上给plate_number和recognize_time建联合索引查询速度会有数量级提升。用我当时压测的数据参考单个Tesla T4 GPU每张图的检测识别耗时约15msFastAPI接口整体吞吐能做到约60 QPS。如果只是停车场出入口的日常流量高峰期每分钟不超过20辆车资源损耗远低于瓶颈。4.5 管理端常见问题排查管理端最容易出的问题有两个跨域和图片回显404。跨域问题开发时前端是Vite的5173端口后端是FastAPI的8000端口互相不打通。用FastAPI的CORSMiddleware中间件允许所有来源就行注意生产环境别“允许所有”要限定域名。图片回显404识别时上传的图片是保存在本地的但前端去访问时路径映射没配。需要在FastAPI里把本地图片目录挂载成静态资源目录from fastapi.staticfiles import StaticFiles app.mount(/uploads, StaticFiles(directoryuploads), nameuploads)这个细节特别容易漏漏了之后前端表格里图片全部裂开排查起来还挺迷惑的。5. 项目扩展思路这套系统跑通之后想继续往下走有几个方向可以选加入车辆颜色和车型识别用多任务学习一个模型同时输出车牌、颜色、车型月卡计费和停车时长统计基于vehicle_records表做费用结算对接真实道闸硬件继电器串口控制识别成功自动抬杆多摄像头协调同一辆车从入口到出口自动匹配计算驻留时间。我个人比较推荐先从“月卡计费”做起因为这是实际需求最刚性的方向而且代码改动不大在现有表结构上增加一个fee_rules表和管理接口就能实现。做完之后整体项目的完整度和实用度都会上一个台阶。再分享一个经验建模阶段没必要追求“大而全”的模型结构车牌识别基准场景下轻量模型和重模型的精度差距并没有想象中那么大但推理速度差距明显。先把一个简单的pipeline完整跑通再逐步迭代模型这个节奏是最适合个人开发者的。最后这套系统我整体跑下来最大的体会是识别算法只是其中一环让识别结果真正为业务创造价值需要的是整个系统工程的配合。希望这篇拆解能让你少踩几个坑。本文还有配套的精品资源点击获取
返回列表