这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【RaspberryPi_Sense-HAT】网页手写数字识别与显示

共1条 1/1 1 跳转至

【RaspberryPi_Sense-HAT】网页手写数字识别与显示

工程师
2026-04-23 15:42:52     打赏

【Raspberry Pi Sense HAT】网页手写数字识别与显示

本文介绍了 Raspberry Pi Sensor HAT 扩展板结合 MNIST 数据集和 ONNX 模型实现网页手写数字识别与显示的项目设计,包括环境搭建、工程设计、流程图、效果演示等。

项目介绍

  • 准备工作:硬件连接、MNIST 预编译模型获取、Python 库安装等;

  • 工程测试:流程图、后端 Flask 服务器代码、前端 Web 网页设计代码;

  • 效果演示:程序运行、网页UI展示、矩阵 LED 显示、动态效果等。

MNIST

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

mnist_principle.jpg

详见:yann.lecun.com

硬件连接

  • 将 SENSE-HAT 与树莓派 CM0 对应 40pin 接口连接;

  • 使用 Type-C 数据线连接开发板和 5V 电源;

hardware_connect.jpg

环境搭建

  • 创建并激活虚拟环境;

 python -m venv .venv --system-site-packages
 source .venv/bin/activate
  • 安装 OpenCV 和 onnxruntime 软件包;

 pip install opencv-python onnxruntime
  • 安装 SENSE-HAT 软件包;

 sudo apt install sense-hat


模型下载

获取 onnx 模型文件;

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


工程目录

工程共包含三个文件,分别为 Flask 后端服务器代码、Web 前端代码、ONNX 模型。

 ~/mnist/                  # 项目根目录(当前工作目录)
 ├── mnist_web.py          # 主程序(Flask + ONNX Runtime + Sense HAT)
 ├── model/
 │   └── mnist-12.onnx     # 本地 ONNX 模型文件
 └── web/
     └── index.html       # 网页前端文件(手写面板)


流程图

flowchart_mnist_web_show.jpg

服务器后端

新建 mnist_web_sensehat.py 文件,添加如下代码

 import os
 import sys
 import numpy as np
 import onnxruntime as ort
 from flask import Flask, send_from_directory, request, jsonify
 from sense_hat import SenseHat
 
 # ==================== 配置 ====================
 BASE_DIR = os.path.dirname(os.path.abspath(__file__))
 MODEL_PATH = os.path.join(BASE_DIR, "model/mnist-12.onnx")
 INDEX_PATH = os.path.join(BASE_DIR, "web/index.html")
 HOST = "0.0.0.0"  # 监听所有网络接口,允许局域网访问
 PORT = 8081
 
 sense = SenseHat()
 sense.set_rotation(0)
 red = (255, 0, 0)
 # ==================== 加载模型 ====================
 print("=" * 60)
 print("  MNIST 手写数字识别服务")
 print("=" * 60)
 
 # 检查模型文件
 if not os.path.exists(MODEL_PATH):
     print(f"\\n错误: 模型文件不存在: {MODEL_PATH}")
     print("\\n请下载模型文件:")
     print("  wget https://github.com/onnx/models/raw/main/validated/vision/classification/mnist/model/mnist-12.onnx")
     print("\\n或者使用 piwheels:")
     print("  wget https://piwheels.org/simple/onnx-models/mnist-12.onnx")
     sys.exit(1)
 
 print(f"\\n模型路径: {MODEL_PATH}")
 print(f"网页路径: {INDEX_PATH}")
 
 # 优化会话选项
 sess_options = ort.SessionOptions()
 sess_options.inter_op_num_threads = 2      # 限制线程数,减少资源占用
 sess_options.intra_op_num_threads = 2
 sess_options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
 
 try:
     session = ort.InferenceSession(
         MODEL_PATH,
         sess_options=sess_options,
         providers=['CPUExecutionProvider']
     )
     print(f"\\n✓ 模型加载成功!")
     print(f"  输入名称: {session.get_inputs()[0].name}")
     print(f"  输入形状: {session.get_inputs()[0].shape}")
     print(f"  输出名称: {session.get_outputs()[0].name}")
     print(f"  输出形状: {session.get_outputs()[0].shape}")
 except Exception as e:
     print(f"\\n✗ 模型加载失败: {e}")
     sys.exit(1)
 
 # ==================== Flask 应用 ====================
 app = Flask(__name__)
 
 @app.route("/")
 def index():
     """返回前端页面"""
     if os.path.exists(INDEX_PATH):
         return send_from_directory(os.path.join(BASE_DIR, "web"), "index.html")
     else:
         return "<h1>index.html not found</h1><p>请确认 index.html 路径</p>", 404
 
 @app.route("/predict", methods=["POST"])
 def predict():
     """
     接收前端传来的 28x28 图像数据,返回推理结果
     
     请求 JSON:
         {"image": [784个float值]}  // 28x28=784, 范围[0.0,1.0], 黑底白字
     
     响应 JSON:
         {
             "digit": 7,
             "confidence": 0.9823,
             "probabilities": [0.001, 0.002, ..., 0.9823, ...]
         }
     """
     try:
         data = request.get_json()
         
         if not data or "image" not in data:
             return jsonify({"error": "缺少 image 字段"}), 400
         
         image_data = data["image"]
         
         # 验证数据长度
         if len(image_data) != 784:
             return jsonify({"error": f"图像数据长度应为 784 (28x28),实际收到 {len(image_data)}"}), 400
         
         # 转换为 numpy 数组
         input_array = np.array(image_data, dtype=np.float32)
         
         # 重塑为 (1, 1, 28, 28) - NCHW 格式
         input_tensor = input_array.reshape(1, 1, 28, 28)
         
         # 执行推理
         input_name = session.get_inputs()[0].name
         output_name = session.get_outputs()[0].name
         
         outputs = session.run([output_name], {input_name: input_tensor})
         logits = outputs[0][0]  # 10 个 logits
         
         # Softmax 转换为概率
         exp_scores = np.exp(logits - np.max(logits))  # 数值稳定性
         probabilities = exp_scores / np.sum(exp_scores)
         
         # 获取预测结果
         predicted_digit = int(np.argmax(probabilities))
         confidence = float(probabilities[predicted_digit])
         
         return jsonify({
             "digit": predicted_digit,
             "confidence": confidence,
             "probabilities": probabilities.tolist()
         })
         
         sense.show_letter(str(predicted_digit), text_colour=red)  # 显示推理结果
  
     except Exception as e:
         print(f"推理错误: {e}")
         import traceback
         traceback.print_exc()
         return jsonify({"error": str(e)}), 500
 
 @app.route("/health")
 def health():
     """健康检查"""
     return jsonify({"status": "ok", "model_loaded": True})
 
 # ==================== 启动 ====================
 if __name__ == "__main__":
     print("\\n" + "=" * 60)
     print("  服务启动中...")
     print(f"  访问地址: http://{HOST}:{PORT}")
     print(f"  本机测试: http://127.0.0.1:{PORT}")
     print("=" * 60 + "\\n")
 
     app.run(
         host=HOST,
         port=PORT,
         debug=False,
         threaded=True
     )

保存代码。

网页前端

新建 web 文件夹并打开,新建 index.html 文件,添加如下代码


web_code.jpg


保存代码。

Web 测试

使用浏览器打开该 HTML 文件,正常显示数字识别前端面板设计,效果如下

mnist_web_recognize_num2.jpg


效果演示

  • 终端执行指令 python mnist_web_sensehat.py 运行 Flask 服务器后端;

  • 依次加载模型、加载本地网页前端文件 index.html、启动服务器、打印访问地址 192.168.31.117:8081;

mnist_web_show_print.jpg

  • 打开浏览器,输入网址 192.168.31.117:8081 并访问;

  • 使用鼠标在左侧手写面板写出 0-9 数字,点击识别按钮;

  • 右侧立即显示识别结果和各个数字的推理结果与置信度;

  • 同时 SENSE-HAT 面板 LED 矩阵显示推理结果(数字 8);

mnist_hat_show_num8.jpg


动态演示

网页手写数字,点击识别按钮,显示结果,同时 LED 矩阵更新数字;

mnist_num.gif


总结

本文介绍了 Raspberry Pi Sensor HAT 扩展板结合 MNIST 数据集和 ONNX 模型实现网页手写数字识别与显示的项目设计,包括环境搭建、工程设计、流程图、效果演示等,为相关产品在边缘 AI 领域的快速开发和应用设计提供了参考。





关键词: 树莓派     AI     LED     OpenCV     MNIST    

共1条 1/1 1 跳转至

回复

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