ARTICLE DETAIL

资讯详情

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

YOLOv8+LPRNet车牌识别系统实战:从零跑通检测与识别全流程

YOLOv8+LPRNet车牌识别系统实战:从零跑通检测与识别全流程 简介这是一套面向计算机相关专业学生与初学者的车牌识别实战项目源码采用 YOLOv8 完成车牌检测、LPRNet 实现字符识别适合用作毕业设计、课程设计或大作业也可作为人工智能与深度学习方向的入门练手案例。压缩包共 60 个文件约 36.15MB包含 13 个 Python 脚本、3 个 pt 模型权重与 1 个 pth 文件覆盖训练、推理与数据处理流程另有 Vue 前端页面、JSON 配置、Markdown 说明文档及示例图片便于快速理解系统结构。资源内代码均经过运行测试功能正常可直接下载使用。目前已有 1146 人学习下载具备一定参考热度。通过该资源读者可掌握从数据标注、模型训练到 Flask 接口部署的完整链路理解检测与识别两阶段协同思路并借鉴目录组织与配置管理方式为后续项目开发提供可复用的工程模板。1. 车牌识别系统落地YOLOv8 加 LPRNet 这套源码到底能不能直接跑车牌识别这个方向每年毕业设计和课程设计都有人做但真正能一次跑通的组合并不多。这份资源给的是 YOLOv8 负责车牌检测、LPRNet 负责字符识别的两阶段方案附带 Flask 后端和 Vue 前端属于能直接演示的完整系统。我拿到包之后第一件事不是看 README而是先确认目录结构里runs、output_lpr、model、uploads这几个文件夹是否齐全因为它们分别对应训练输出、识别结果、权重文件和上传缓存。适合谁计算机相关专业做毕设、课程设计或者想快速搭一个车牌识别 demo 的从业者。不适合谁想直接上生产环境、要求高并发和毫秒级响应的场景这套代码的定位是学习和演示不是工业级部署。2. 两阶段架构拆解为什么检测用 YOLOv8、识别用 LPRNet2.1 检测与识别的分工逻辑车牌识别本质上是一个「先定位、再读字」的流水线。YOLOv8 在这里的角色是目标检测输入一张含车的图片输出车牌区域的边界框坐标。LPRNet 的角色是序列识别把裁剪出来的车牌小图送进去直接输出字符序列不需要先做字符分割。这个分工的好处是检测模型只管找车牌识别模型只管读字符两个模型可以独立训练、独立替换。常见做法是检测用 YOLOv8n 或 YOLOv8s识别用 LPRNet 的轻量版本整体推理速度在 CPU 上也能接受。为什么不用端到端方案端到端车牌识别虽然省事但训练数据要求高标注成本大而且调试时出了问题很难定位是检测错了还是识别错了。两阶段方案的好处是每一段都可以单独验证先用 YOLOv8 看检测框准不准再用 LPRNet 看字符读得对不对。对于毕设和课程设计来说这种可拆解的结构更容易写论文、做对比实验。2.2 目录结构与文件职责拿到包之后先别急着跑app.py把目录过一遍能省很多时间。下面这张表是我整理的核心文件职责文件/目录职责备注app.pyFlask 入口提供上传和识别接口启动后默认监听本地端口main.py主流程脚本串联检测和识别可单独测试generate_lpr_data.py生成 LPRNet 训练数据需要先有检测结果batch_resize_images.py批量缩放图片统一输入尺寸create_annotations.py生成标注文件YOLO 格式split_dataset.py划分训练集/验证集按比例切分runs/YOLOv8 训练输出含权重和日志output_lpr/LPRNet 识别结果含训练日志model/预训练权重存放检测和识别各一份uploads/上传图片缓存运行后自动生成src/vite.config.jsVue 前端需要单独构建这张表建议对照实际目录看一遍如果某个文件夹是空的说明需要自己训练或者从runs里拷贝权重过去。2.3 环境依赖与版本选择这套代码依赖的库不算多但版本对不上很容易翻车。我一般会先建一个干净的虚拟环境然后按下面的清单装# 创建虚拟环境 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate # 核心依赖 pip install ultralytics8.0.0 # YOLOv8 官方库 pip install torch torchvision # PyTorch按 CUDA 版本选 pip install opencv-python # 图像处理 pip install flask # Web 后端 pip install numpy pillow # 基础库逻辑说明ultralytics是 YOLOv8 的官方封装版本建议锁在 8.0.x太新的版本 API 可能有变动。torch的安装要看机器有没有 GPU有 CUDA 的话去官网查对应命令没有就用 CPU 版本。参数说明opencv-python用于图像读写和裁剪flask提供上传接口numpy和pillow是 LPRNet 预处理需要的。如果装完ultralytics之后import报错大概率是torch版本不匹配先确认torch能正常import再装其他。提示不要用pip install -r requirements.txt一把梭很多包里的 requirements 没有锁版本装出来一堆冲突。手动装核心库更稳。3. 从零跑通检测加识别数据准备、训练与推理全流程3.1 数据标注与 YOLO 格式转换YOLOv8 训练需要 YOLO 格式的标注每张图对应一个.txt文件每行是类别 x_center y_center width height坐标都归一化到 0 到 1。如果你手头是 LabelImg 标注的 XML需要转一下。包里create_annotations.py就是干这个的但我一般会先检查它的输入路径和类别定义# create_annotations.py 核心逻辑示意 import os import xml.etree.ElementTree as ET def convert_annotation(xml_path, output_path, classes): tree ET.parse(xml_path) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) with open(output_path, w) as f: for obj in root.iter(object): cls obj.find(name).text if cls not in classes: continue cls_id classes.index(cls) bbox obj.find(bndbox) x1 float(bbox.find(xmin).text) y1 float(bbox.find(ymin).text) x2 float(bbox.find(xmax).text) y2 float(bbox.find(ymax).text) # 归一化并转为中心点加宽高 x_center (x1 x2) / 2.0 / w y_center (y1 y2) / 2.0 / h bw (x2 - x1) / w bh (y2 - y1) / h f.write(f{cls_id} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}\n)逻辑说明这段代码把 XML 里的绝对坐标转成 YOLO 需要的归一化中心点格式。参数说明classes是类别列表车牌检测一般只有一个类别写成[plate]就行。x_center和y_center是框中心点除以图片宽高bw和bh是框宽高除以图片宽高。常见坑是坐标没归一化或者用了左上角坐标训练时 loss 会一直不降。3.2 YOLOv8 训练参数怎么设数据准备好之后用split_dataset.py按 8:2 切分训练集和验证集然后就可以启动训练。YOLOv8 的训练命令很简洁# 启动 YOLOv8 训练 yolo detect train \ datadataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ device0逻辑说明data指向数据配置文件里面写清楚训练集、验证集路径和类别数。model用预训练的yolov8n.pt做迁移学习比从零训练收敛快很多。参数说明epochs是训练轮数100 轮对车牌检测够用imgsz是输入尺寸640 是默认值显存不够可以降到 416batch是批大小显存 8G 以上可以开到 16lr0是初始学习率0.01 是常用值device0表示用第一块 GPUCPU 训练去掉这个参数。训练完权重在runs/detect/train/weights/best.pt把它拷到model/目录下备用。注意如果训练时提示显存不足先把batch降到 8 或 4再不行就降imgsz。不要硬扛显存爆了训练直接中断。3.3 LPRNet 数据生成与识别推理检测模型有了之后下一步是生成 LPRNet 的训练数据。generate_lpr_data.py的作用是用检测模型把训练集里的车牌框裁出来保存成小图同时生成对应的字符标签。这一步很关键因为 LPRNet 的输入是裁剪后的车牌图不是原图。# generate_lpr_data.py 核心逻辑示意 from ultralytics import YOLO import cv2 import os model YOLO(model/best.pt) # 加载训练好的检测模型 img_dir dataset/images save_dir images_lpr os.makedirs(save_dir, exist_okTrue) for img_name in os.listdir(img_dir): img_path os.path.join(img_dir, img_name) img cv2.imread(img_path) results model(img) # 推理 for i, box in enumerate(results[0].boxes): x1, y1, x2, y2 box.xyxy[0].tolist() plate img[int(y1):int(y2), int(x1):int(x2)] # 缩放到 LPRNet 输入尺寸 plate cv2.resize(plate, (94, 24)) cv2.imwrite(os.path.join(save_dir, f{img_name}_{i}.jpg), plate)逻辑说明这段代码遍历训练图片用检测模型找出车牌框裁剪后缩放到 94x24这是 LPRNet 的标准输入尺寸。参数说明model/best.pt是上一步训练好的检测权重94x24是 LPRNet 论文里的输入尺寸改大了识别模型也要跟着改保存的文件名带序号避免同一张图多个车牌覆盖。常见坑是裁剪时坐标越界加个max(0, x1)和min(w, x2)更稳。LPRNet 训练完之后推理流程就是原图送 YOLOv8 检测拿到车牌框裁剪缩放送 LPRNet 识别输出字符。main.py里应该已经串好了这个流程跑之前确认两个模型的权重路径都对。3.4 Flask 后端与 Vue 前端联调app.py是 Flask 入口提供上传和识别接口。启动方式# 启动 Flask 后端 python app.py # 默认监听 127.0.0.1:5000前端在src/目录下用 Vite 构建# 安装前端依赖并启动 cd src npm install npm run dev # 默认监听 5173 端口逻辑说明前端负责上传图片和展示识别结果后端负责调用模型推理。参数说明如果前后端端口不一致需要在vite.config.js里配代理把/api转发到 Flask 的 5000 端口。常见坑是跨域问题Flask 那边加CORS或者前端配代理都能解决。联调时先单独测后端接口用 Postman 或 curl 传一张图确认返回结果正常再开前端。4. 避坑与排查这套代码最容易翻车的五个地方4.1 权重文件路径对不上现象运行main.py或app.py时报FileNotFoundError提示找不到.pt文件。原因代码里写的权重路径是相对路径但你的工作目录不对或者model/目录下根本没有权重文件。解决先确认model/目录里有没有best.pt没有就从runs/detect/train/weights/拷过来。然后把代码里的路径改成绝对路径或者确保在项目根目录下运行脚本。4.2 LPRNet 输入尺寸不匹配现象识别结果全是乱码或者模型直接报维度错误。原因LPRNet 对输入尺寸敏感训练时用的 94x24推理时如果传了其他尺寸全连接层维度对不上。解决检查generate_lpr_data.py和推理脚本里的 resize 尺寸是否一致统一改成 94x24。如果自己改了输入尺寸LPRNet 的网络结构也要跟着改。4.3 字符集与标签不对应现象识别出来的字符不在预期范围内比如把0识别成O或者出现训练集里没有的字符。原因LPRNet 的输出是字符集索引训练时的字符集和推理时的字符集必须完全一致。解决找到训练时用的字符集文件确认推理脚本加载的是同一个。常见做法是把字符集写成一个列表或 txt 文件训练和推理都读它。4.4 Flask 上传大图导致超时现象前端上传高清图片后后端长时间没响应最后超时。原因YOLOv8 推理时间跟图片尺寸正相关4K 图在 CPU 上可能要好几秒。解决在后端加一步预处理把上传的图片先缩放到 1280 宽再送模型。或者在前端上传前用 canvas 压缩。参数上imgsz设成 640 就够了没必要用原图尺寸推理。4.5 Vue 前端构建后接口 404现象npm run dev正常但npm run build之后部署接口全部 404。原因开发环境的代理配置只在 dev server 生效构建后的静态文件需要 Nginx 或其他服务器转发/api请求。解决在 Nginx 配置里加一条location /api/ { proxy_pass http://127.0.0.1:5000/; }或者把前端和后端部署在同源下。这个坑在毕设答辩现场翻车率很高提前测一遍构建版本。5. 进阶技巧用 batch_resize_images.py 统一数据尺寸与验证识别效果5.1 批量缩放为什么重要batch_resize_images.py这个脚本容易被忽略但它解决的是一个很实际的问题训练数据来源杂图片尺寸从 320x240 到 4000x3000 都有直接送进 YOLOv8 训练dataloader 每次都要做 resize速度慢而且可能引入形变。我一般会先用这个脚本把所有图片统一缩放到一个基准尺寸比如宽 1280高按比例算。这样训练时 dataloader 的负担小很多而且标注文件不用改因为 YOLO 格式的坐标是归一化的缩放不影响。# batch_resize_images.py 核心逻辑 import cv2 import os def resize_images(src_dir, dst_dir, target_width1280): os.makedirs(dst_dir, exist_okTrue) for name in os.listdir(src_dir): if not name.lower().endswith((.jpg, .png, .jpeg)): continue img cv2.imread(os.path.join(src_dir, name)) h, w img.shape[:2] # 按宽度等比缩放 scale target_width / w new_h int(h * scale) resized cv2.resize(img, (target_width, new_h)) cv2.imwrite(os.path.join(dst_dir, name), resized)逻辑说明这段代码按宽度等比缩放保持长宽比不变避免车牌被拉变形。参数说明target_width默认 1280可以根据显存调整显存小就设 960 或 640。注意缩放后标注文件不用动因为 YOLO 坐标是归一化的。如果用的是绝对坐标标注缩放后要同步改标注。5.2 验证识别效果的三个指标跑通之后怎么判断这套系统好不好用我一般看三个指标检测框的 IoU、识别字符的准确率、端到端的整体准确率。检测这块YOLOv8 训练完会输出 mAP50 和 mAP50-95mAP50 到 0.9 以上基本够用。识别这块LPRNet 训练日志里有准确率但那个是字符级准确率实际要看整牌准确率也就是一张车牌所有字符全对才算对。端到端准确率就是检测和识别都对的占比这个指标最真实。验证方法很简单准备 50 张没参与训练的图片跑一遍完整流程人工核对结果。如果整牌准确率低于 80%先看是检测漏了还是识别错了。检测漏了就去补标注识别错了就去看是不是字符集或者输入尺寸的问题。这个验证过程建议在答辩前一周做留出调参时间。5.3 一个容易被忽略的细节车牌颜色与光照LPRNet 对车牌颜色不敏感它读的是字符形状但 YOLOv8 检测对光照和颜色敏感。如果训练集里全是蓝牌遇到绿牌或者黄牌可能检测不到。常见做法是在数据增强里加颜色抖动和亮度变化YOLOv8 默认的hsv_h、hsv_s、hsv_v参数就是干这个的。我一般会把hsv_v调到 0.4 以上让模型适应不同光照。另外夜间或者逆光的图片检测框容易偏移这个只能靠补充数据解决没有捷径。从那以后我每次拿到类似的两阶段识别项目都强制先跑一遍batch_resize_images.py统一尺寸再检查字符集和权重路径最后用 50 张图做端到端验证。这套流程走下来基本不会在答辩现场翻车。希望帮到你。本文还有配套的精品资源点击获取
返回列表