这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【树莓派Zero2W】数字识别

共1条 1/1 1 跳转至

【树莓派Zero2W】数字识别

工程师
2025-11-08 14:56:22     打赏

【树莓派 Zero 2W】数字识别

本文介绍了树莓派 Zero 2W 开发板实现数字识别的板端推理的项目设计,包括准备工作、环境搭建、MNIST 数据集和 ONNX 模型、流程图、工程代码以及效果演示等。

项目介绍

  • 准备工作:包括所需 Python 环境、数据集训练、模型下载、软件包的安装部署等;

  • 单数字识别:使用预训练 onnx 模型实现包含一个手写数字图片的板端推理;

  • 多数字识别:使用预训练 onnx 模型实现包含多个手写数字图片的板端推理;

MNIST 数据集

MNIST(Modified National Institute of Standards and Technology,修改后的美国国家标准与技术研究院)数据集是一个大型手写数字数据库,通常用于训练各种图像处理系统和机器学习模型。它通过“重新混合” NIST 原始数据集中的样本而创建,并且已成为评估图像分类算法性能的基准。

mnist_cover.jpg

主要功能

  • MNIST 包含 60,000 个训练图像和 10,000 个手写数字的测试图像。

  • 该数据集包含大小为 28×28 像素的灰度图像。

  • 这些图像经过归一化处理,以适应28×28像素的边界框并进行抗锯齿处理,从而引入灰度级别。

  • MNIST 广泛用于机器学习领域的训练和测试,特别是对于图像分类任务。

数据结构

MNIST 数据集分为两个子集:

  1. 训练集: 该子集包含 60,000 张手写数字图像,用于训练机器学习模型。

  2. 测试集:此子集包含 10,000 张用于测试和评估已训练模型的图像。

数据集中的每张图像都标有相应的数字(0-9),使其成为一个用于分类任务的理想监督学习数据集。

应用

MNIST数据集广泛用于训练和评估图像分类任务中的深度学习模型,例如卷积神经网络(CNN)、支持向量机(SVM)和各种其他机器学习算法。

详见:yann.lecun.comfashion-mnist .

ONNX

Open Neural Network Exchange (ONNX) 是一个开放的生态系统,为 AI 开发人员提供支持 随着项目的发展选择正确的工具。

onnx_cover.jpg

  • ONNX 为 AI 模型(包括深度学习和传统 ML)提供开源格式。它定义了一个可扩展的计算图模型,以及内置运算符和标准的定义数据类型。

  • ONNX 可用于标准化模型的表示形式,使得模型可以在不同的框架(如PyTorch、TensorFlow)和推理引擎(如ONNX Runtime、TensorRT)之间转换。

详见:onnx/onnx: Open standard for machine learning interoperability .

准备工作

包括 OpenCV、 onnxruntime 库安装和预训练 onnx 模型下载。

库安装

  • 执行指令 sudo apt install python3-opencv 安装 OpenCV;

  • 安装 onnxruntime 库,终端执行指令

sudo apt-get install python3-onnxruntime

onnxruntime_install.jpg

  • 执行指令 python -c "import onnxruntime, sys; print(onnxruntime.__version__)" 验证安装;

onnxruntime_version.jpg

若遇到问题,可根据 Linux 系统版本和 Python 版本,下载 对应的 *.whl 文件并安装

wget https://pypi.tuna.tsinghua.edu.cn/packages/1c/a1/428ee29c6eaf09a6f6be56f836213f104618fb35ac6cc586ff0f477263eb/onnxruntime-1.23.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
sudo pip install onnxruntime-1.23.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl --break-system-packages

详见:Links for onnxruntime .

通过 uname -a 查询Linux系统信息,python --version 指令查询Python版本。

模型下载

  • 下载 模型文件至 ./model 文件夹;

mkdir model
cd model
wget https://github.com/onnx/models/blob/main/validated/vision/classification/mnist/model/mnist-12.onnx

详见:mnist | onnx/models · GitHub .

单个数字识别

采用预训练的 MNIST 轻量化的 onnx 模型实现单个数字识别的板端推理,并弹窗显示、终端打印识别结果。

流程图

flowchart_hnr_single.jpg

代码

终端执行  touch hnr_single.py 指令新建文件,并添加如下代码

#!/usr/bin/env python3
import cv2, numpy as np, onnxruntime as ort, time, sys

model = './model/mnist-12.onnx'
img_p = sys.argv[1] if len(sys.argv) > 1 else './img/num8.jpg'

# ---------- 1. 载入模型 ----------
sess = ort.InferenceSession(model, providers=['CPUExecutionProvider'])
in_name  = sess.get_inputs()[0].name   # 'Input3'  shape [1,1,28,28]
out_name = sess.get_outputs()[0].name  # 'Plus214_Output_0' 10 类置信度

# ---------- 2. 读图并预处理 ----------
img = cv2.imread(img_p, cv2.IMREAD_GRAYSCALE)
if img is None:
    raise FileNotFoundError(img_p)

# 反二值化 + Resize 28×28 + 归一化 0~1
img = cv2.bitwise_not(img)          # 白底黑字→黑底白字
img = cv2.resize(img, (28, 28))
blob = img.astype(np.float32) / 255.0
blob = blob.reshape(1, 1, 28, 28)   # NCHW

# ---------- 3. 推理 ----------
t0 = time.time()
pred = sess.run([out_name], {in_name: blob})[0]  # [1,10]
digit = int(np.argmax(pred))
cost = (time.time() - t0) * 1000

# ---------- 4. 结果 ----------
print(f'识别结果: {digit}  (置信度: {pred[0,digit]:.3f})  耗时: {cost:.1f} ms')

# 简单弹窗(可选)
cv2.putText(img, f'{digit}', (5, 22), cv2.FONT_HERSHEY_SIMPLEX, 0.8, 255, 2)
cv2.imshow('digit', img)
cv2.waitKey(0)

保存代码。

效果

hnr_single终端执行  python hnr_single.py 运行程序,弹窗显示识别结果;

hnr_single.jpg

终端输出识别结果和置信度等信息

hnr_single_print.jpg


多数字识别

采用预训练的 MNIST 轻量化的 onnx 模型实现多个数字识别的板端推理,并弹窗显示和终端打印识别结果。

流程图

flowchart_hnr_multi.jpg


代码

终端执行  touch hnr_multi.py 指令新建文件,并添加如下代码

#!/usr/bin/env python3
import cv2, numpy as np, onnxruntime as ort, sys, time, os

sess = ort.InferenceSession('./model/mnist-12.onnx', providers=['CPUExecutionProvider'])
in_name  = sess.get_inputs()[0].name
out_name = sess.get_outputs()[0].name

# ---------- 1. 读图 ----------
img_path = sys.argv[1] if len(sys.argv) > 1 else './img/numbers.jpg'
img_bgr  = cv2.imread(img_path)
assert img_bgr is not None, 'cannot read '+img_path

# ---------- 2. 灰度 + 反色 ----------
gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)
binary = cv2.bitwise_not(gray)          # 白底黑字 → 黑底白字

# ---------- 3. 去噪 ----------
binary = cv2.medianBlur(binary, 3)

# ---------- 4. Otsu 二值 ----------
_, th = cv2.threshold(binary, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# ---------- 5. 找轮廓 ----------
cnts, _ = cv2.findContours(th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
print('[dbg] findContours:', len(cnts), 'pieces')

# ---------- 6. 预处理函数(单数字) ----------
def mnistify(roi_u8, save_prefix):
    """
    roi_u8: 黑底白字 uint8 图
    return: NCHW 1×1×28×28 已归一化
    """

    # 缩到 20×20
    roi20 = cv2.resize(roi_u8, (20, 20), interpolation=cv2.INTER_AREA)
    canvas = np.zeros((28, 28), dtype=np.uint8)
    tl = (28 - 20) // 2
    canvas[tl:tl + 20, tl:tl + 20] = roi20



    blob = canvas.astype(np.float32) / 255.0
    return blob.reshape(1, 1, 28, 28)

# ---------- 7. 逐 ROI 推理 ----------
show = img_bgr.copy()
digits = []
for idx, c in enumerate(cnts):
    x, y, w, h = cv2.boundingRect(c)
    print(f'[dbg] contour{idx}:  x={x} y={y} w={w} h={h}  area={cv2.contourArea(c):.1f}')
    if w < 5 or h < 15 or w > 200 or h > 200 or w / h > 1.2 or h / w > 4:
        print('        -> skip by filter')
        continue

    pad = 4
    x1 = max(0, x - pad); y1 = max(0, y - pad)
    x2 = min(img_bgr.shape[1], x + w + pad)
    y2 = min(img_bgr.shape[0], y + h + pad)
    roi = th[y1:y2, x1:x2]          # 黑底白字


    blob = mnistify(roi, f'05_roi{idx}')

    pred = sess.run([out_name], {in_name: blob})[0]
    digit = int(np.argmax(pred))
    conf  = float(pred[0, digit])
    digits.append((x1, digit, conf))
    print(f'        -> pred={digit}  conf={conf:.3f}')

    cv2.rectangle(show, (x1, y1), (x2, y2), (0, 255, 0), 2)
    cv2.putText(show, str(digit), (x1, y1 - 5),
                cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2)

# ---------- 8. 结果 ----------
digits.sort(key=lambda d: d[0])
result = ''.join(str(d[1]) for d in digits)
print('found digits:', result, '  conf:', [f'{d[2]:.3f}' for d in digits])

cv2.imshow('multi-digit', show)
cv2.waitKey(0)

保存代码。

效果

终端执行  python hnr_multi.py 运行程序,弹窗显示识别结果;

hnr_multi

hnr_multi.jpg

终端打印识别到的数字和坐标信息

hnr_multi_print.jpg

总结

本文介绍了树莓派 Zero 2W 开发板实现数字识别的板端推理的项目设计,包括准备工作、环境搭建、MNIST 数据集和 ONNX 模型、流程图、工程代码以及效果演示等,为相关产品在 AI 视觉领域的开发设计和快速应用提供了参考。





关键词: 树莓派     系统     Linux     数字识别    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]