找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1938

积分

0

好友

272

主题
发表于 昨天 17:19 | 查看: 8| 回复: 0

本项目介绍了如何在工业树莓派 CM0 NANO 单板计算机上,结合 LPRNet 算法和 Ultralytics 库实现车牌识别的完整流程。内容涵盖环境部署、软件包安装、模型获取、关键代码解析以及板端推理演示,为边缘 AI 应用的快速开发提供了参考。

项目介绍

  • 准备工作:OpenCV 安装、Ultralytics 软件包安装、预训练模型下载等。
  • 车牌识别:采用 LPRNet 算法及 ONNX 模型实现车牌识别的板端推理。

为了快速实现车牌识别功能,需要完成 OpenCV 部署和 Ultralytics 软件包的安装等操作。

准备工作

本节包括硬件连接、虚拟环境创建、OpenCV 安装、Ultralytics 库部署等步骤。

硬件连接

  • 连接 WiFi 实现无线网络通信。
  • 使用 Type-C 数据线为设备供电。

树莓派CM0 NANO开发板连接示意图

OpenCV 安装

OpenCV 是一个开源的计算机视觉库,广泛应用于图像处理、视频分析和机器学习等领域。

OpenCV标志

为了避免影响系统 Python 环境,推荐采用虚拟环境方案。

  • 创建并激活虚拟环境
    mkdir ~/cv && cd ~/cv    # 创建 cv 文件夹,便于管理
    python3 -m venv venv     # 创建虚拟环境 venv
    source venv/bin/activate # 激活虚拟环境 venv
  • 安装 numpy 和 opencv
    pip install -U pip numpy                          # 安装 numpy
    pip install opencv-python opencv-contrib-python   # opencv 主模块及 contrib
  • 验证安装
    python3 -c "import cv2,sys,numpy;print('OpenCV:',cv2.__version__,'NumPy:',numpy.__version__)"
  • 输出版本号
    OpenCV与NumPy版本验证截图

字体安装

为了方便显示中文车牌,需要安装 CJK 字体。

sudo apt install fonts-noto-cjk
fc-list | grep -i "Noto Sans CJK" | head -3

字体文件路径查询结果

记录字体所在路径,例如 /usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc,以便后续代码调用。

Ultralytics 部署

Ultralytics 基于多年在计算机视觉和人工智能领域的研究,打造了 YOLO 系列模型,具有速度快、精度高、操作简便等特点,在目标检测、跟踪、实例分割等任务中表现出色。

YOLO系列模型性能对比图

  • 安装 ultralytics 软件包
    sudo apt install python3-dev python3-pip libopenblas-dev
    sudo pip install python3-torch
    sudo pip install ultralytics --break-system-packages
  • 验证安装
    python3 -c "import ultralytics, sys, torch; print('✅ ultralytics', ultralytics.__version__, '| torch', torch.__version__, '| Python', sys.version.split()[0])"
  • 输出相应版本号
    Ultralytics、Torch和Python版本信息

详见项目仓库: https://github.com/ultralytics/ultralytics

车牌识别

车牌识别网络(License Plate Recognition Network,LPRNet)是一种专为车牌识别设计的深度学习模型。

LPRNet车牌识别网络结构图

它采用端到端的训练方法,能够直接从原始图像中识别出车牌文本,无需进行传统的字符分割步骤。这种设计使得 LPRNet 在处理车牌识别任务时更加高效和准确,特别是在面对复杂背景或不同国家的车牌样式时。

详见: https://github.com/sirius-ai/LPRNet_Pytorch

模型

下载所需模型文件。

wget https://github.com/h030162/PlateRecognition/blob/main/ocr_rec.py
wget https://github.com/h030162/PlateRecognition/blob/main/license_models/dict.txt
wget https://github.com/h030162/PlateRecognition/blob/main/license_models/license_ocr.onnx
wget https://github.com/h030162/PlateRecognition/blob/main/license_models/y11n-pose_plate_best.onnx

将文件存放在对应路径,项目目录结构如下:

license_plate_recognition
   ├── img
   │   ├── yue.jpg
   ├── lpr_onnx.py
   ├── model
   │   ├── dict.txt
   │   ├── license_ocr.onnx
   │   └── y11n-pose_plate_best.onnx
   └── ocr_rec.py

流程图

车牌识别系统工作流程图

代码

在终端执行 touch lpr_onnx.py 新建程序文件,并添加如下代码。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np
import cv2
from ocr_rec import TextRecognizer, init_args
from PIL import Image, ImageDraw, ImageFont
from ultralytics import YOLO
import warnings
warnings.filterwarnings("ignore")

# ========== figure ==========
#IMG
_FILE = "./img/yue.jpg"
args = init_args().parse_args()
IMG_FILE = args.image_path or './img/test.jpg'   # image path
# 使用方法:python lpr_onnx.py --image_path ./img/jing.jpg

# =========== class ===========
class PlateRecognizer:
    def __init__(self, det_model_path="./model/y11n-pose_plate_best.onnx"):
        self.model_det = YOLO(det_model_path)
        parser = init_args().parse_args()
        self.model_ocr = TextRecognizer(parser)

    def recognize(self, img):
        plate_objs = []
        plates = self.model_det(img, verbose=False)
        for plate, conf in zip(plates[0].boxes.xyxy, plates[0].boxes.conf):
            x1, y1, x2, y2 = map(int, plate.cpu())
            plate_img = img[y1:y2, x1:x2]
            try:
                rec_res, _ = self.model_ocr([plate_img])
            except Exception as E:
                print(E)
                continue
            if len(rec_res[0]) > 0:
                plate_objs.append({
                    'text': rec_res[0][0],
                    'score_text': rec_res[0][1],
                    'bbox': [x1, y1, x2, y2],
                    'score_bbox': conf.cpu().numpy().item()
                })
        return plate_objs

def DrawPlateNum(img, plate_num, x1, y1):
    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    img_pil = Image.fromarray(img_rgb)
    draw = ImageDraw.Draw(img_pil)
    font = ImageFont.truetype("/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", 40) # 系统字体
    # -------- 优化标签显示,增加填充背景,兼容新版 Pillow ----------------
    left, top, right, bottom = draw.textbbox((0, 0), plate_num, font=font)
    tw, th = right - left, bottom - top
    # 蓝色填充条
    draw.rectangle([(x1, y1 - th - 8), (x1 + tw, y1)], fill=(0, 0, 255))   # BGR 蓝色
    # 绿色文字
    draw.text((x1, y1 - th - 16), plate_num, font=font, fill=(0, 255, 0))   # BGR 绿色
    return cv2.cvtColor(np.array(img_pil, dtype=np.uint8), cv2.COLOR_RGB2BGR)

# ========== 主程序 ==========
def main():
    img = cv2.imread(IMG_FILE)
    if img is None:
        print(f"未找到图片:{IMG_FILE}")
        cv2.waitKey(0)
        return
    recognizer = PlateRecognizer()
    plates = recognizer.recognize(img)
    for p in plates:
        x1, y1, x2, y2 = p['bbox']
        cv2.rectangle(img, (x1, y1), (x2, y2), (255, 0, 0), 2)
        img = DrawPlateNum(img, p['text'], x1, y1)
        print(f"车牌: {p['text']}  置信度: {p['score_text']:.4f}  框置信度: {p['score_bbox']:.4f}")
    cv2.imshow("LPR", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == "__main__":
    main()

保存代码。

效果

  • 在终端执行 python lpr_onnx.py --image_path ./img/yue.jpg 指令,对目标车牌进行识别。
  • 终端会打印识别到的车牌号、置信度等信息。

车牌识别程序终端运行输出

  • 程序会弹窗显示识别结果。

车牌识别结果弹窗显示示例1

  • 更多测试效果展示。

车牌识别结果弹窗显示示例2
车牌识别结果弹窗显示示例3
车牌识别结果弹窗显示示例4

总结

本文详细介绍了在树莓派 CM0 NANO 上搭建车牌识别系统的全过程,从环境配置、依赖安装到模型推理与代码实现。该项目展示了如何在资源受限的边缘设备上运行基于Python和深度学习的计算机视觉应用,为智能交通、安防监控等领域的边缘AI开发提供了可行的实践案例。希望这篇教程能为你开启边缘计算项目带来帮助。欢迎在 云栈社区 分享你的实践成果或提出技术问题。




上一篇:PageHelper线程污染问题解析:账号重复注册与数据分页异常
下一篇:Rust生命周期解析:从图书馆借书规则理解编译器的安全检查
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-11 14:17 , Processed in 0.207426 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表