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

共1条 1/1 1 跳转至

【SIPEEDM1DOCKSUITEVALBRD试用】数字识别

工程师
2026-03-04 23:52:44     打赏

做车牌识别主要还是数字识别,简单的搞个数字识别试试效果

由于本开发版比较早,只能使用maixpy-v1的固件,好几个KPU的函数与新版本不一样,在使用的时候要注意版本

直接上代码,用AI注释一下方便快捷

# ==================== 导入必要的库 ====================
import sensor, image, time, lcd  # 导入摄像头、图像处理、时间和LCD模块
import KPU as kpu          # 导入KPU神经网络处理单元模块
import math              # 导入数学库,用于softmax计算

# ==================== LCD初始化 ====================
lcd.init()                         # 初始化LCD显示屏
lcd.clear(lcd.WHITE)               # 将LCD清屏为白色背景

# ==================== 摄像头初始化 ====================
sensor.reset()                      # 复位摄像头
sensor.set_vflip(1)                 # 垂直翻转图像(根据摄像头安装方向调整)
sensor.set_hmirror(1)               # 水平翻转图像(根据摄像头安装方向调整)
sensor.set_pixformat(sensor.RGB565) # 设置像素格式为RGB565(16位彩色)
sensor.set_framesize(sensor.QVGA)   # 设置帧大小为QVGA (320x240像素)
sensor.set_windowing((224, 224))    # 设置窗口大小为224x224(居中裁剪)
sensor.set_contrast(2)               # 设置对比度为2(适当增加,范围通常是-3到3)
sensor.set_brightness(0)             # 设置亮度为0(保持默认)
sensor.set_auto_gain(False)          # 关闭自动增益控制,保持图像稳定
sensor.set_auto_whitebal(False)       # 关闭自动白平衡,避免颜色变化
sensor.skip_frames(time=1000)         # 跳过前1000ms的帧,等待摄像头稳定
clock = time.clock()                  # 创建时钟对象,用于计算FPS

# ==================== 加载KPU模型 ====================
print("正在加载模型...")
task = kpu.load("/sd/uint8_mnist_cnn_model.kmodel")  # 从SD卡加载模型文件
kpu.set_outputs(task, 0, 1, 1, 10)    # 设置模型输出层形状:
                                       # task: 模型任务句柄
                                       # 0: 第0个输出层
                                       # 1,1,10: 输出形状为(1,1,10),即10个类别的概率
print("模型加载成功!")

# ==================== Softmax函数定义 ====================
def softmax(x):
    """
    将logits转换为概率值
    参数:
        x: 输入的原始输出值列表(logits)
    返回:
        概率值列表,总和为1
    """
    max_x = max(x)                    # 找到最大值,用于数值稳定性
    exp_sum = 0                       # 初始化指数和
    exp_vals = []                      # 存储指数值
    
    # 计算每个值的指数(减去最大值防止溢出)
    for v in x:
        e = math.exp(v - max_x)        # 计算exp(v - max_x)
        exp_vals.append(e)              # 存储指数值
        exp_sum += e                     # 累加指数和
    
    # 计算概率(每个指数值除以总和)
    return [e/exp_sum for e in exp_vals]

# ==================== 图像预处理函数 ====================
def preprocess_for_model(img):
    """
    为模型预处理图像(不修改原图)
    步骤:灰度化 -> 直方图均衡 -> 缩放到28x28 -> 反转颜色 -> 二值化 -> 缩放到112x112
    
    参数:
        img: 输入的原始图像
    返回:
        img_input: 处理后的模型输入图像(112x112)
        img_28: 28x28的二值化图像(用于调试显示)
    """
    # 1. 转换为灰度图(单通道图像)
    img_gray = img.to_grayscale()
    
    # 2. 直方图均衡化增强对比度
    # 让图像的灰度分布更均匀,提高数字和背景的对比度
    img_gray.histeq()
    
    # 3. 调整到28x28(MNIST数据集的原始大小)
    img_28 = img_gray.resize(28, 28)
    
    # 4. 反转颜色(确保白底黑字)
    # MNIST数据集是白底黑字,而摄像头通常得到的是黑底白字
    img_28.invert()
    
    # 5. 二值化处理
    # 将图像转换为纯粹的黑白两色,减少噪声干扰
    for y in range(28):
        for x in range(28):
            if img_28.get_pixel(x, y) > 200:    # 如果像素值大于200(接近白色)
                img_28.set_pixel(x, y, 255)      # 设置为白色背景
            else:                                 # 否则(像素值<=200,接近黑色)
                img_28.set_pixel(x, y, 0)         # 设置为黑色数字
    
    # 6. 放大到模型输入大小(112x112)
    # 因为我们的模型可能是在112x112的图像上训练的
    img_input = img_28.resize(112, 112)
    img_input.pix_to_ai()              # 将图像数据复制到AI内存区域,供KPU使用
    
    return img_input, img_28            # 返回处理后的图像

# ==================== 主程序开始 ====================
print("开始识别...")
print("请使用黑笔在白纸上写数字")

while True:
    clock.tick()                       # 记录开始时间,用于计算FPS
    
    # 获取原始图像(用于LCD显示)
    # 这保持原始亮度,不会过黑
    img_display = sensor.snapshot()
    
    # 复制一份用于模型预处理
    # 这样就不会修改用于显示的原始图像
    img_copy = img_display.copy()
    
    # 对副本进行预处理(不修改原图)
    img_input, img_28 = preprocess_for_model(img_copy)
    
    # 运行模型推理
    # 将预处理后的图像输入KPU,得到输出结果
    out = kpu.forward(task, img_input)
    
    # 如果推理成功,处理输出结果
    if out is not None:
        # 获取输出数据
        # 输出可能是元组形式,取第一个元素
        if isinstance(out, tuple):
            logits = out[0]              # 取第一个输出张量
        else:
            logits = out                  # 直接使用输出
        
        # 提取10个数字的原始值(logits)
        values = [float(logits[i]) for i in range(10)]
        
        # 使用softmax转换为概率
        probs = softmax(values)
        
        # 找到最大概率及其对应的数字
        max_prob = max(probs)             # 最大概率值
        digit = probs.index(max_prob)      # 最大概率对应的数字(0-9)
        
        # 在原始图像上显示识别结果
        if max_prob > 0.5:                 # 只显示置信度>50%的结果
            # 识别结果 - 使用红色大字体
            display_str = "Num: %d" % digit
            prob_str = "%.1f%%" % (max_prob * 100)
            
            # 在图像左上角显示数字和置信度
            img_display.draw_string(10, 10, display_str, color=(255, 0, 0), scale=2)
            img_display.draw_string(10, 40, prob_str, color=(255, 0, 0), scale=2)
            
            # 显示所有数字的概率分布(小字体,绿色)
            # 每行显示两个数字的概率,共5行
            for i in range(0, 10, 2):
                if i+1 < 10:  # 如果有两个数字可以显示
                    line = "%d:%.2f %d:%.2f" % (i, probs[i], i+1, probs[i+1])
                else:          # 最后一个数字单独显示
                    line = "%d:%.2f" % (i, probs[i])
                # 计算y坐标:70 + 行号*15
                img_display.draw_string(10, 70 + (i//2)*15, line, color=(0, 255, 0), scale=1)
            
            # 打印识别结果到串口终端
            print("识别: %d (%.1f%%)" % (digit, max_prob*100))
        else:
            # 置信度太低,显示提示信息
            img_display.draw_string(10, 10, "Low confidence", color=(255, 255, 0), scale=1)
    
    # 在右下角显示预处理后的缩略图(用于调试)
    # 将28x28的二值化图像放大到56x56,方便观察预处理效果
    img_thumb = img_28.resize(56, 56)
    img_display.draw_image(img_thumb, 224-70, 224-70)  # 放在右下角
    
    # 将最终图像显示到LCD上
    lcd.display(img_display)
    
    # 打印当前的FPS(帧率)到串口终端
    print("FPS: %.2f" % clock.fps())

实际效果如下,还是不错的。

本次分享到这,下次分享一下如何完成自己的模型与训练




关键词: SIPEEDM1DOCKSUITEVALBRD         

共1条 1/1 1 跳转至

回复

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