【CanMV K210】AI 视觉 MNIST 手写数字识别与分类推理

在 CanMV K210 入门和 AI 视觉项目中,MNIST 手写数字识别是一个很适合拆解的分类模型实验。它不像人脸检测那样输出目标框,而是把输入图像送入模型后,判断画面中的数字更接近 0 到 9 中的哪一类。

本实验使用 CanMV K210 运行 4.7_Mnist_recognition.py。程序通过摄像头采集画面,对图像进行开窗、灰度化、缩放、反色、字符增强和 AI 格式转换,再送入 KPU 执行 MNIST 分类模型推理。模型输出 10 个分类结果后,程序取置信度最高的一项作为识别数字,并在 LCD 画面上显示 num: x

学习目标 说明
理解分类模型流程 掌握图像输入、预处理、KPU 推理、分类输出和结果显示之间的关系
区分分类与检测 理解 MNIST 输出数字类别,人脸检测输出目标位置框
掌握图像预处理 使用灰度化、缩放、反色和字符增强改善模型输入
理解 KPU 推理结果 从模型输出列表中找到最大值,并得到对应数字类别
建立调试思路 从摄像头画面、模型路径、输入尺寸、光照和数字书写方式排查问题

这个实验的重点不是让 LCD 显示一个数字那么简单,而是理解"图像如何变成分类结果"。摄像头采集到的是一张实时图像,经过预处理后变成适合模型输入的数据,KPU 输出的是 10 个类别的分数,程序再从这些分数中选出最可能的数字。

文章目录

理论基础

MNIST 手写数字识别属于图像分类任务。分类模型的目标是判断输入图像属于哪一个类别,本实验中的类别就是数字 0 到 9。和人脸检测不同,分类模型通常不会告诉目标在画面中的具体位置,也不会输出矩形框,而是输出每个类别对应的分数或置信度。

本实验中,摄像头输出的是 QVGA 图像,程序通过 sensor.set_windowing((224, 224)) 截取中间区域,让识别对象尽量处于画面中心。随后图像被转换成灰度图,并缩放为 112×112。MNIST 模型通常关注的是数字笔画形状,因此灰度化可以减少颜色干扰,缩放可以让输入尺寸匹配模型要求,反色和字符增强可以让数字轮廓更接近模型训练时的数据特征。

代码中的 out = kpu.run_with_output(img_mnist2, getlist=True) 会返回一个列表,这个列表可以理解成模型对 0 到 9 每个数字的判断结果。程序使用 max(out) 找到分数最高的一项,再用 out.index(max_mnist) 得到对应的数字编号。比如最大值出现在列表第 3 个位置,就认为当前图像更像数字 3。

下面的流程图展示的是 MNIST 手写数字识别的数据处理链路。它不是普通电路接线图,而是从摄像头图像到分类结果的 AI 推理流程。
摄像头采集

sensor.snapshot()
开窗取图

224×224 画面区域
灰度化处理

to_grayscale()
缩放图像

resize(112,112)
反色与字符增强

invert() / strech_char()
AI 输入格式转换

pix_to_ai()
KPU 分类推理

uint8_mnist_cnn_model.kmodel
输出 10 类分数

0 ~ 9
取最大分数索引

max() / index()
LCD 显示结果

num: x
SD 卡模型文件

/sd/uint8_mnist_cnn_model.kmodel
串口输出

print(display_str)
gc.collect()

内存回收

从这条链路可以看出,MNIST 识别效果不仅取决于模型文件,还取决于输入图像是否符合模型预期。数字是否居中、背景是否干净、光照是否稳定、笔画是否清晰、图像是否正确反色,都会影响最终分类结果。调试时不能只盯着 KPU 推理代码,也要观察 LCD 中的实际画面和预处理后的数字特征。

分类模型和检测模型的区别也可以通过这个实验理解。人脸检测模型需要输出目标框,因此后处理重点是坐标、宽高、置信度和 NMS;MNIST 分类模型只需要输出类别,因此后处理重点是从 10 个分数中找到最大值。前者回答"目标在哪里",后者回答"这是什么类别"。

硬件设施

本实验围绕 CanMV K210 的 AI 视觉分类能力展开,主要使用开发板、摄像头模块、LCD 显示屏、SD 卡模型文件和 KPU 神经网络加速器。代码没有使用按键、蜂鸣器、电机、传感器或 WiFi 模块,因此这些外设不作为本节重点。

运行效果截图可以放在这里。发布时建议放置一张 LCD 上显示摄像头画面和 num: x 识别结果的图片,方便读者直接观察数字识别现象。

硬件 / 软件 作用 说明
CanMV K210 开发板 实验运行平台 执行 MicroPython 程序,调用摄像头、LCD 和 KPU
摄像头模块 图像采集 通过 sensor.snapshot() 获取实时画面
LCD 显示屏 结果显示 显示摄像头画面和识别到的数字结果
KPU 神经网络加速器 AI 推理 加载 kmodel 模型并执行手写数字分类
SD 卡 模型文件存储 存放 /sd/uint8_mnist_cnn_model.kmodel
串口控制台 调试输出 通过 print(display_str) 查看识别数字
sensor 摄像头控制模块 完成摄像头初始化、图像格式、分辨率和开窗设置
image 图像处理模块 完成灰度化、缩放、反色、字符增强和绘制文字
lcd LCD 显示模块 初始化屏幕并显示处理后的图像
maix.KPU KPU 模块 加载模型、执行推理并返回分类结果
gc 内存管理模块 在循环中执行内存回收,降低长时间运行风险

摄像头、LCD、SD 卡和开发板的实物连接图可以放在这里。接线检查时重点确认摄像头排线、LCD 屏幕、SD 卡模型文件和开发板供电状态。

接口 / 资源 代码对象 对应硬件与说明
摄像头接口 sensor.reset() / sensor.snapshot() 初始化摄像头并持续采集图像帧
LCD 接口 lcd.init() / lcd.display(img) 显示摄像头画面和识别结果
KPU 模型文件 /sd/uint8_mnist_cnn_model.kmodel 从 SD 卡加载手写数字识别模型
摄像头开窗 sensor.set_windowing((224, 224)) 截取画面中心区域,减少无关背景干扰
灰度输入 img.to_grayscale(1) 将彩色图像转换为更适合数字识别的灰度图
缩放输入 resize(112,112) 将图像缩放到模型推理需要的尺寸
分类结果 out.index(max_mnist) 得到 0 到 9 中分数最高的数字类别
LCD 文字显示 img.draw_string(...) 在画面左上角显示 num: x

本实验不涉及普通 GPIO 接线,重点不是排查某根引脚是否接错,而是确认 AI 视觉链路是否完整。摄像头没有画面时,应先检查摄像头连接和初始化;LCD 不显示时,应先检查屏幕初始化和供电;模型加载失败时,应先检查 SD 卡、模型文件路径和文件名;识别结果不稳定时,应重点检查数字是否居中、图像是否清晰、背景是否干净。

实验现象 正常表现 异常提示
程序启动 LCD 初始化,摄像头开始输出画面 黑屏时检查 LCD、摄像头和程序初始化
模型加载 程序正常进入主循环,无模型路径报错 报错时检查 /sd/uint8_mnist_cnn_model.kmodel 是否存在
数字进入画面 LCD 左上角显示 num: x 结果乱跳时检查数字位置、光照和背景
串口输出 串口持续打印 num: x 没有输出时检查程序是否进入主循环
画面刷新 LCD 持续显示摄像头画面 卡顿时减少额外操作,检查内存回收
长时间运行 程序持续识别并显示 卡死时检查模型资源、SD 卡和内存占用

软件代码

本实验的软件部分以 4.7_Mnist_recognition.py 为核心。程序导入 sensorimagetimelcdKPUgc,随后完成 LCD 初始化、摄像头初始化、模型加载,并在主循环中持续采集图像、完成预处理、执行 KPU 分类推理、输出识别结果和刷新 LCD。

软件环境 作用 检查重点
CanMV IDE 编辑、运行和调试 K210 程序 能识别开发板串口,并能运行基础摄像头程序
CanMV 固件 提供 sensorlcdKPU 等模块 固件需要支持 KPU 模型加载和图像处理函数
SD 卡 存放模型文件 /sd/uint8_mnist_cnn_model.kmodel 路径需要与代码一致
摄像头驱动 图像采集 能正常显示 QVGA RGB565 图像
LCD 显示环境 结果显示 能正常显示摄像头画面和 num: x 文本
串口终端 调试输出 能看到识别数字输出和报错信息
python 复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ----湖南创乐博智能科技有限公司----
#  文件名:4.7_Mnist_recognition.py
#  版本:V2.0
#  author: zhulin
# 说明:Mnist - 手写数字识别实验
#####################################################
import sensor, image, time, lcd
from maix import KPU
import gc


lcd.init()                          # 初始化LCD显示屏
sensor.reset()                      # 复位并初始化摄像头
sensor.set_pixformat(sensor.RGB565) # 设置摄像头输出格式为 RGB565
sensor.set_framesize(sensor.QVGA)   # 设置摄像头输出大小为 QVGA (320x240)
sensor.set_windowing((224, 224))    # 摄像头输出开窗
sensor.skip_frames(time = 500)      # 等待摄像头稳定
sensor.set_hmirror(0)               # 禁用水平镜像
clock = time.clock()                # 创建一个clock对象,用来计算帧率

# 创建一个kpu对象
kpu = KPU()
# 加载模型
kpu.load_kmodel("/sd/uint8_mnist_cnn_model.kmodel")

while True:
    gc.collect()
    img = sensor.snapshot()                 # 拍照,获取一张图像
    img_mnist1=img.to_grayscale(1)          # 将图片转为灰度图
    img_mnist2=img_mnist1.resize(112,112)   # 将图片缩放为112x112
    a=img_mnist2.invert()                   # 反转图片
    a=img_mnist2.strech_char(1)             # 预处理图片
    a=img_mnist2.pix_to_ai()                # 对image处理生成ai运算需要的r8g8b8格式存储

    # 对输入图像进行kpu运算,并得出结果
    out = kpu.run_with_output(img_mnist2, getlist=True)
    max_mnist = max(out)
    index_mnist = out.index(max_mnist)
    #score = KPU.sigmoid(max_mnist)
    display_str = "num: %d" % index_mnist
    print(display_str)
    a=img.draw_string(4,3,display_str,color=(0,0,0),scale=2)
    lcd.display(img)

# 创建的kpu对象去初始化,释放模型内存
kpu.deinit()

这段程序可以分成三个层级。底层是 LCD、摄像头和 KPU 模型初始化,负责准备图像采集和模型推理环境;中间层是灰度化、缩放、反色、字符增强和 AI 格式转换,负责把摄像头图像处理成适合 MNIST 模型输入的数据;上层是分类结果计算、串口打印和 LCD 显示,负责把模型输出转换成可观察的数字结果。

初始化阶段中,sensor.set_pixformat(sensor.RGB565) 设置摄像头输出彩色图像,sensor.set_framesize(sensor.QVGA) 设置画面为 320×240,sensor.set_windowing((224, 224)) 截取中间区域。kpu.load_kmodel("/sd/uint8_mnist_cnn_model.kmodel") 从 SD 卡加载模型文件,这一步要求模型文件路径和文件名完全一致。

函数 / 语句 功能 对应现象
lcd.init() 初始化 LCD 显示屏 屏幕准备显示图像
sensor.reset() 复位并初始化摄像头 摄像头进入可采集状态
sensor.set_pixformat(sensor.RGB565) 设置摄像头像素格式 获取彩色图像
sensor.set_framesize(sensor.QVGA) 设置摄像头分辨率 输出 320×240 画面
sensor.set_windowing((224, 224)) 设置摄像头开窗 截取中间区域作为主要识别画面
sensor.skip_frames(time=500) 等待摄像头稳定 启动后画面更稳定
sensor.set_hmirror(0) 禁用水平镜像 保持画面方向不镜像
KPU() 创建 KPU 对象 准备加载模型并执行推理
kpu.load_kmodel() 加载 MNIST 模型 从 SD 卡读取 kmodel 文件
gc.collect() 执行内存回收 降低循环运行中的内存压力
sensor.snapshot() 获取一帧摄像头图像 主循环持续采集画面
to_grayscale(1) 转换为灰度图 减少颜色对数字分类的干扰
resize(112,112) 缩放图像 匹配模型输入尺寸
invert() 反转图像颜色 让数字和背景关系更接近模型输入特征
strech_char(1) 字符增强处理 增强数字笔画特征
pix_to_ai() 转换为 KPU 输入格式 图像可以送入 KPU 推理
run_with_output(..., getlist=True) 执行模型推理并返回列表 输出 0 到 9 的分类结果
max(out) 获取最高分类分数 找到模型最有把握的一类
out.index(max_mnist) 获取最大值所在索引 得到识别数字
draw_string() 在图像上绘制识别结果 LCD 左上角显示 num: x
lcd.display(img) 刷新 LCD 显示 显示最新摄像头画面和识别文本

运行时,程序会不断执行"采集图像、预处理、KPU 推理、取最大分类结果、显示识别数字"的循环。如果画面中有清晰、居中、背景干净的手写数字,LCD 和串口会显示对应的 num: x。如果画面中没有数字,模型仍然会在 0 到 9 中选出一个最接近的类别,因此输出结果不一定代表真实有效目标,只代表当前输入图像在模型看来最像哪一个数字。

需要注意的是,代码中创建了 clock = time.clock(),但主循环没有调用 clock.tick() 或显示 FPS,因此这个对象在当前版本中没有实际参与结果显示。代码末尾的 kpu.deinit() 位于无限循环之后,正常运行时不会自动执行到这一行。如果后续要支持安全退出,可以再加入 try...excepttry...finally 结构释放 KPU 资源。本篇保持原始实验代码结构,便于和课程文件一致。

扩展应用

MNIST 手写数字识别实验常见问题主要集中在摄像头、LCD、模型文件、输入图像质量和预处理效果几个方面。排查时建议先确认摄像头和 LCD 基础功能,再确认模型文件路径,最后再调整数字摆放、背景、光照和预处理方式。

问题现象 可能原因 处理思路
程序无法运行 文件没有传到开发板、固件不支持相关模块、库文件缺失 确认主程序在正确目录,检查 CanMV 固件版本和报错行号
LCD 黑屏或无画面 LCD 未初始化成功、摄像头未输出图像、程序卡在模型加载阶段 先运行基础摄像头显示程序,确认 LCD 和摄像头正常
模型加载失败 uint8_mnist_cnn_model.kmodel 没有放到 /sd/,或文件名不一致 将模型文件复制到 SD 卡根目录,并核对代码路径
串口没有输出 程序没有进入主循环、串口终端未打开 加入基础 print() 或观察 LCD 是否刷新
识别结果乱跳 画面中没有明确数字,背景复杂,光照不稳定 使用白纸黑字或黑底白字,固定摄像头距离,保持背景干净
数字识别错误 数字不居中、笔画太细、倾斜严重、预处理效果不佳 将数字放到画面中心,增大笔画粗细,保持数字完整
每次都输出某个数字 输入图像特征过于单一,模型被背景干扰 调整背景和光照,让数字占据主要区域
画面颜色正常但结果不准 分类模型看的是预处理后的灰度图,不是原始彩色图 重点检查灰度、反色、缩放和字符增强后的输入效果
结果刷新慢 图像处理、KPU 推理和 LCD 刷新占用时间 减少额外打印和不必要图像操作
程序运行一段时间后卡顿 内存碎片或资源占用增加 保留 gc.collect(),减少循环中创建额外对象

MNIST 手写数字识别实验的价值不只在于复现实验现象,更在于建立从图像输入到分类输出的项目思路。在掌握基础代码后,可以把它和显示、通信、存储、按键菜单或其他模块组合成更完整的作品。

扩展效果图或项目运行截图可以放在这里。发布时建议放置手写数字卡片、LCD 识别画面、串口输出结果或不同数字识别对比画面。

应用场景 实现思路 可扩展能力
手写数字识别 将纸面数字放入摄像头画面,模型输出 0 到 9 的分类结果 可扩展数字卡片识别、课堂演示和模型推理教学
AI 入门演示 展示图像分类模型如何在 K210 本地运行 可用于讲解模型输入、输出分数和分类结果
试卷数字采集 对简单手写数字区域进行识别 可扩展拍照保存、串口上传和结果记录
模型分类教学 对比分类模型和检测模型的输出差异 可衔接人脸检测、物体分类和目标识别实验
嵌入式推理练习 使用 KPU 在边缘设备上完成图像分类 可扩展更多自训练分类模型
视觉分类原型 将识别结果作为后续控制条件 可联动 LED、蜂鸣器、LCD 菜单或上位机通信
数字密码演示 连续识别多个数字形成简单输入序列 可扩展为门禁密码输入、实验互动和识别结果验证

从工程角度看,当前程序已经具备 AI 分类项目的基本分层。摄像头负责输入,图像处理负责预处理,KPU 负责推理,分类后处理负责选出最大分数,LCD 和串口负责输出结果。后续扩展时,可以单独替换模型、调整输入尺寸、改变预处理方式,或者把识别结果转换成外设动作,而不需要重写整个采集和显示流程。

总结

本实验通过 CanMV K210 完成了基于 KPU 的 MNIST 手写数字识别,核心能力包括摄像头初始化、图像开窗、灰度化、缩放、反色、字符增强、KPU 模型加载、分类推理、最大值结果选择、LCD 显示和串口输出。程序从摄像头输入开始,把图像处理成适合模型推理的格式,再把分类结果显示为 num: x,完整展示了 K210 图像分类实验的基本流程。

MNIST 手写数字识别是后续 AI 分类项目的基础入口。掌握这条链路后,可以继续扩展物体分类、数字识别交互、试卷数字采集、上位机结果上传、LCD 结果菜单和外设联动控制等内容。调试时应按"摄像头画面是否正常、LCD 是否显示、模型文件是否存在、预处理后数字是否清晰、分类结果是否稳定"的顺序排查,这样更容易定位问题。

相关推荐
Leo.yuan1 小时前
企业数字化转型选型指南:FineBI如何助力数据驱动决策?
数据仓库·人工智能·信息可视化
TENSORTEC腾视科技1 小时前
让安全驾驶有“AI”相伴|腾视科技DMS视频监控一体机,守护每一次出行
大数据·人工智能·科技·安全·ai·零售·无人叉车及智能调度系统解决方案
日月新著1 小时前
仙踪问道·爱马仕助手:Mac 本地 AI Agent 零门槛部署实战
人工智能·macos
Mr数据杨1 小时前
【CanMV K210】AI 视觉 按键采样自训练识别与现场分类
人工智能·硬件开发·canmv k210
初心未改HD1 小时前
AI应用开发之概率论与贝叶斯定理
人工智能·概率论
CodingPioneer1 小时前
智屏问数 · AI数字人驱动的车间数字大屏
人工智能·信息可视化·数字人·魔珐星云·星云具身
踏着七彩祥云的小丑1 小时前
AI——Dify创建第一个AI聊天机器人
人工智能·ai·机器人
大力财经1 小时前
丰田安全标准融合Momenta智驾大脑 2026款铂智3X正式上市
人工智能
陈天伟教授1 小时前
图解人工智能(2)最智能
人工智能·安全·架构