【工业树莓派CM0 Dev Board】AI视觉应用部署方案:数字识别

本文介绍了树莓派 CM0 Dev Board 的实现 AI 视觉应用方案:数字识别的项目设计,包括准备工作、环境搭建、MNIST 数据集、ONNX 模型、流程图、关键代码以及效果演示等。

项目介绍

  • 准备工作:包括所需 Python 环境、数据集训练、模型下载、软件包的安装部署等;
  • 单个数字识别:通过预训练模型实现单张图片包含一个数字的识别和板端推理;
  • 多个数字识别:通过预训练模型实现单张图片包含多个数字的识别和板端推理;

MNIST 数据集

Modified National Institute of Standards and Technology (MNIST) 是一个包含手写数字的数据集,里面有上万张数字图片,每张图片都标注了对应的数字标签(0到9)。该数据集可用来训练识别手写数字的神经网络。

在这里插入图片描述

详见:yann.lecun.com

ONNX

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

在这里插入图片描述

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

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

准备工作

系统安装及环境搭建详见:【工业树莓派CM0 Dev Board】介绍、镜像烧录、系统测试 .

硬件连接

  • 若采用 SSH 远程登录操作,则仅需连接电源供电即可;
  • 若采用本地登录,则需连接 HDMI 视频流传输线、USB 键盘连接线等;

在这里插入图片描述

库安装

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

  • 安装解析 ONNX 模型所需的 onnxruntime 库,终端执行

sudo apt install python3-pip
sudo pip3 install onnxruntime --break-system-packages
模型下载
  • 下载 模型文件至本地 ./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 模型实现单个数字识别的板端推理,并弹窗显示、终端打印识别结果。

流程图

开始
读取图片
载入模型
灰度读图
反色
调整尺寸
ONNX推理
ArgMax数字
弹窗显示
按ESC键
计时
终端打印
结束

代码

终端执行 touch hnr_mnist.py 指令新建文件,并使用 nano 文本编辑器添加如下代码

#!/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/num2.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)

保存代码。

效果

终端执行 python hnr_mnist.py ,弹窗显示处理后的图片

在这里插入图片描述

同时终端打印识别结果及置信度

在这里插入图片描述

更多数字举例

在这里插入图片描述

在这里插入图片描述

多个数字识别

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

流程图

开始
载入模型
读取图片
灰度+反色
中值滤波去噪
OTSU二值化
外轮廓
遍历每个轮廓
尺寸过滤
调整尺寸
归一化
ONNX推理
ArgMax获得数字
选框和标签
打印结果
按ESC键
结束

代码

终端执行 python hnr_mnist_multi.py 指令新建文件,并使用 nano 文本编辑器添加如下代码

#!/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_mnist_multi.py 弹窗显示多个数字的识别结果;

在这里插入图片描述

同时终端输出识别结果

在这里插入图片描述

更多测试效果

在这里插入图片描述

总结

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

更多推荐