【嵌入式开发】在maixhub平台自主训练模型 k210图像检测

1.准备好要下载的软件(用到再下载)

CanMV IDE 图像化编程Python软件
kflash_gui.exe k210开发板烧录固件软件
labelImg.exe 图像打标签软件(这个软件安装路径千万不能有中文)
SDFormatter_v4.0 u盘格式化软件
CH9102x驱动 驱动安装
固件 烧录固件

2.创建数据集(如果你要做的项目本身有数据集,那使用别人的模型,没有就要自己训练得到模型)

拍摄图片,用作数据集,图片拍摄的角度最好要一样,重复多张。数据集图片大小要完全一致,拍摄时候角度一致,不要一会儿竖着拍,一会儿横着拍。
提示:图像识别的数据集是指用于图像识别任务的大量图像及其对应的标签或注释的集合。这些数据集为机器学习模型提供了学习和推理的基础,使得模型能够识别和理解图像中的内容。

图像识别的数据集通常包括多种不同类型的图像,涵盖了广泛的场景、物体和特征。这些图像被仔细标注,以便机器学习算法能够学习如何识别图像中的关键信息。标注可以是标签(例如,图像中的物体类别)、边界框(用于定位图像中的特定物体)或其他形式的注释。

常见的图像识别数据集包括ImageNet、CIFAR、COCO等。这些数据集被广泛应用于计算机视觉领域的研究和实际应用中,为图像分类、目标检测、图像分割等任务提供了丰富的训练数据。

通过使用这些数据集,机器学习模型可以学习如何提取图像中的特征、识别物体并理解它们之间的关系。经过训练后,模型可以对新的、未见过的图像进行识别和分析,从而实现各种图像识别任务。

maixhub平台给出的数据集要求是这样的:
数据集包括了训练集和验证集。
但我们只需要收集训练集即可,验证集平台会自动分割。
在这里插入图片描述

以瞌睡举例子,拍摄50张学生不打瞌睡的图片,拍摄50张学生打瞌睡的图片。图片数量越多检测精度越准确。

把拍摄完的图片上传到电脑,创建文件夹,一个总文件名(任意英文名),里面包括images、xml、label.txt,这三个名字不可以任意取名。
在这里插入图片描述
把拍摄完的图片放入images文件夹
然后打开labelImg.exe软件

3.给图片打标签

打开labelImg.exe软件后,会出现一个黑框,不要关掉黑框。
在这里插入图片描述
先对这个软件进行一些设置,在view里面点击auto saving,进行打标签文件的自动化保存。
在这里插入图片描述
点击open dir,打开images文件
在这里插入图片描述
在这里插入图片描述点击change save dir,点击xml文件 在这里插入图片描述
点击create rectbox,或者使用w快捷键,就可以打标签了,框柱物体后(尽量框住物体即可,不要框多,背景会有影响)
在这里插入图片描述
这里以是否有人打瞌睡为例子,打瞌睡的图片标签为yes,不打瞌睡的图片标签为no。
在这里插入图片描述在这里插入图片描述
每次打完一张图片后,可以按d键快捷键来进入下一张图片,a键快捷键是上一张,直到打完所有图片的标签。images文件夹的文件数量要和xml的文件数量一致。(这里只有115张图片)
在这里插入图片描述
在这里插入图片描述
在labels.txt里面写yes、no。标签是什么就写什么,一个标签一行。
在这里插入图片描述

4.maixhub平台获取模型

打开maixhub模型训练网站,点击新建训练。
在这里插入图片描述

训练项目名称任意写,类型选择图像检测,点击确定。
在这里插入图片描述

进入总览页面(这里也会告诉你要怎么得到训练模型)
在这里插入图片描述

点击数据集,创建数据集
在这里插入图片描述

同样也写成训练项目一样的名称
在这里插入图片描述

点击查看
在这里插入图片描述

点击导入数据集(其实也可以在平台里面进行打标签,不过没这么方便),选择导入压缩包,把刚刚做好的数据集文件夹进行压缩,整个压缩,压缩文件格式是zip,等待加载完毕后,然后点击开始上传。
在这里插入图片描述
在这里插入图片描述
上传完毕后
在这里插入图片描述

点击模型训练,再点击项目1
在这里插入图片描述

点击数据集,选择1数据集,点击确定
在这里插入图片描述
点击确定即可
在这里插入图片描述

点击创建任务,参数里面的高度宽度不要改变224*224,可以选择随机镜像,随机模糊,随机旋转,部署平台选择nncase,迭代参数默认。
下一步是训练配置。配置通常很重要,但我们大部分使用默认的就行,深入了解这些配置的意义可能需要学习一些深度学习方面的知识。

随机处理:可以全勾上;增强模型抗环境条件干扰的能力。
数据均衡:如果上传数据集中,不同类别之间的图片数量差距比较大,就需要打开。每个标签(每个类)都是差不多,那就不用开。

在YOLOv2模型的训练中,迭代次数(或称为“轮数”、“epoch数”)的具体设置取决于训练数据集的大小、模型的复杂度、计算资源以及期望的模型性能等多个因素。通常,迭代次数是通过实验和经验来确定的,以在过拟合和欠拟合之间找到一个平衡点。

在这里插入图片描述

点击创建训练任务,名字还是和项目名字一样。

然后就等待吧
YOLOv2(You Only Look Once version 2)是一种用于实时目标检测的卷积神经网络,由Joseph Redmon和Ali Farhadi等人于2016年提出1。它是基于深度学习的物体检测算法,通过在一张输入图片中,将图片分成多个网格,每个网格预测出一些边界框和类别信息,并通过非极大值抑制(NMS)去除冗余检测框,最终输出所有的物体检测结果2。

YOLO算法非常强大,现在已经更新到v8版本,这里平台用的只是v2,v8的训练要自己搭建神经网络的训练环境.....耗时非常长,还很多错,初学者建议先不要尝试

训练完毕后点击部署。虽然这里的准确率是1,但是数量是越多越好的,真正的模型训练集是上千上万张…
在这里插入图片描述

点击手动部署,点击下载模型。
在这里插入图片描述

5.k210主板配置

用的是创乐博的k210板。
请添加图片描述

请添加图片描述

打开电脑的设备管理器,先用数据线连接k210主板和电脑的usb接口,端口那里会识别到新设备,出现叹号要安装驱动。驱动本文章有自己下载,点击SETUP.EXE,再点安装。

已经安装了驱动的,不用管这一步。
在这里插入图片描述

已经烧写完固件的不用管这一步。

K210的固件是指嵌入在K210芯片中的软件,它包含了芯片启动和运行所需的各种程序和数据。固件对于K210的功能实现和性能发挥至关重要。

K210是一款集成机器视觉与机器听觉能力的系统级芯片,具有双核64位处理器,拥有较好的功耗性能、稳定性与可靠性。其固件的作用主要体现在以下几个方面:

功能实现:固件中包含了实现K210各种功能所需的程序代码,如物体识别、语音识别和自然语言处理等。这些功能使得K210能够广泛应用于智能家居、环境监测、教育机器人等领域。

就是说我们平时写c++用到的库文件,直接在dev软件上写include就可以,那是因为dev安装已经包含了库文件,直接用就可以。硬件不一样,硬件没有库文件,要自己烧录进去。

性能优化:固件还负责优化芯片的性能,通过合理的调度和管理资源,确保芯片在各种场景下都能保持高效、稳定的运行。

驱动安装完后,使用kflash_gui.exe进行固件烧写,打开kflash_gui.exe,选择擦除,选择部分擦除,点击擦除。
在这里插入图片描述

擦除完后,进行烧写。选择固件,打开文件(这个固件文件本文章有下载链接),然后点击下载。
在这里插入图片描述
在这里插入图片描述

6.使用CanMV IDE改写代码

把刚刚部署好下载的文件压缩包打开,其中kmodel是模型文件,main.py是程序文件,用CanMV IDE打开main.py。
解压下载得到的压缩包,里面包含如下文件:

main.py:python代码文件,执行它调用模型,MaixHub自动生成。相当于c++的主函数程序。
kmodel:模型文件。
report.json:没有什么用处,训练过程中的一些记录。

在这里插入图片描述

CanMV IDE工具栏里面选项的文本编辑器能改变字体的尺寸大小。
在这里插入图片描述

看懂代码先

# generated by maixhub, tested on maixpy3 v0.4.8
# copy files to TF card and plug into board and power on
import sensor, image, lcd, time #导入模块
import KPU as kpu #导入KPU模块
import gc, sys #导入模块,gc是内存回收相关模块,sys是系统的一些内置的模块
from fpioa_manager import fm

#图片大小224*224  标签yes和no 
#在YOLOv2中,anchors(先验框)是人为设定的先验边界框,用于在训练过程中作为物体位置的初始预测。
#不用改这里
input_size = (224, 224)
labels = ['yes', 'no']
anchors = [3.22, 2.41, 3.09, 2.19, 3.38, 3.19, 2.75, 3.44, 2.97, 3.41]

# 定义一个函数,用来将错误打印到lcd屏幕上,(这些错误也同时会答应到IDE的串行终端上)
# 不用改
def lcd_show_except(e):
    import uio
    err_str = uio.StringIO()
    sys.print_exception(e, err_str)
    err_str = err_str.getvalue()
    img = image.Image(size=input_size)
    img.draw_string(0, 10, err_str, scale=1, color=(0xff,0x00,0x00))
    lcd.display(img)

#串口输入输出不用改
class Comm:
    def __init__(self, uart):
        self.uart = uart

    def send_detect_result(self, objects, labels):
        msg = ""
        for obj in objects:
            pos = obj.rect()
            p = obj.value()
            idx = obj.classid()
            label = labels[idx]
            msg += "{}:{}:{}:{}:{}:{:.2f}:{}, ".format(pos[0], pos[1], pos[2], pos[3], idx, p, label)
        if msg:
            msg = msg[:-2] + "\n"
        self.uart.write(msg.encode())

#串口配置不用改
def init_uart():
    fm.register(10, fm.fpioa.UART1_TX, force=True)
    fm.register(11, fm.fpioa.UART1_RX, force=True)

    uart = UART(UART.UART1, 115200, 8, 0, 0, timeout=1000, read_buf_len=256)
    return uart

#主函数 设置了模块的起始地址,lcd上图像的旋转角度,图像的水平以及垂直方向是否翻转
def main(anchors, labels = None, model_addr="/sd/m.kmodel", sensor_window=input_size, lcd_rotation=0, sensor_hmirror=False, sensor_vflip=False):
    sensor.reset() #重启摄像头
    sensor.set_pixformat(sensor.RGB565) #摄像头的色彩
    sensor.set_framesize(sensor.QVGA) #摄像头的帧大小
    sensor.set_windowing(sensor_window)
    sensor.set_hmirror(sensor_hmirror) #摄像头的翻转设置
    sensor.set_vflip(sensor_vflip) #摄像头的翻转设置
    sensor.run(1)  #1表示开始抓取图像

    lcd.init(type=1) #lcd初始化
    lcd.rotation(lcd_rotation)  #lcd旋转角度
    lcd.clear(lcd.WHITE) #清屏

    if not labels:
        with open('labels.txt','r') as f:
            exec(f.read())
    if not labels:
        print("no labels.txt")
        img = image.Image(size=(320, 240))
        img.draw_string(90, 110, "no labels.txt", color=(255, 0, 0), scale=2)
        lcd.display(img)
        return 1
    try:
        img = image.Image("startup.jpg")
        lcd.display(img)
    except Exception:
        img = image.Image(size=(320, 240))
        img.draw_string(90, 110, "loading model...", color=(255, 255, 255), scale=2)
        lcd.display(img)

    uart = init_uart()
    comm = Comm(uart)

    try:
        task = None
        task = kpu.load(model_addr) #从flash或者文件系统中加载模型,不需要关键词,传入参数即可,比如0x300000;"/sd/m.kmodel"
        
        
        #yolo2初始化函数 参数分别为:
        #模型对象
        #概率阈值, 只有是这个物体的概率大于这个值才会输出结果
        #box_iou 门限, 为了防止同一个物体被框出多个框,当在同一个物体上框出了两个框,这两个框的交叉区域占两个框总占用面积的比例 如果小于这个值时, 就取其中概率最大的一个框
        #anchor 的锚点数, 这里固定为 len(anchors)//2
        #锚点
        kpu.init_yolo2(task, 0.5, 0.3, 5, anchors) # threshold:[0,1], nms_value: [0, 1]
        while(True):
            img = sensor.snapshot() #读取一帧图像
            t = time.ticks_ms() #记录当前时间
            objects = kpu.run_yolo2(task, img) #运行yolo2, 返回一个kpu_yolo2_find 列表
            t = time.ticks_ms() - t #记录当前时间,与上一次的做差,得到运行一帧需要的时间
            if objects:
                for obj in objects:  #列表不为空的话,遍历并画出个矩形框
                    print("检测结果是:",labels[obj.classid()],"   概率为:",100*obj.value())
                    pos = obj.rect() #返回一个坐标元组x y w h
                    img.draw_rectangle(pos) #把图片框起来
                    img.draw_string(pos[0], pos[1], "%s : %.2f" %(labels[obj.classid()], obj.value()), scale=2, color=(255, 0, 0))
                
                
                
                comm.send_detect_result(objects, labels)
            img.draw_string(0, 200, "t:%dms" %(t), scale=2, color=(255, 0, 0))
            lcd.display(img) #将图像打印到lcd上
    except Exception as e:
        raise e
    finally:
        if not task is None:
            kpu.deinit(task) #释放模型占用的内存,立即释放,但是变量还在


if __name__ == "__main__":
    try:
        # main(anchors = anchors, labels=labels, model_addr=0x300000, lcd_rotation=0) 这种方法是将模型烧写进flash
        main(anchors = anchors, labels=labels, model_addr="/sd/model-122483.kmodel") #这种方法是将模型保存进sd卡中,从sd卡中直接加载模型
    except Exception as e:
        sys.print_exception(e)
        lcd_show_except(e)
    finally:
        gc.collect() #运行垃圾回收


这个代码不用完全看懂,知道哪里要改的地方就行了

比如检测到人在睡觉震动传感器震动,检测到人没有睡觉震动传感器不震动。
(1)导入库文件
在这里插入图片描述

from fpioa_manager import fm
from machine import Timer,PWM,UART
from Maix import GPIO
import utime

在库文件的下面直接添加震动传感器的震动引脚配置(灯可以加可以不加,当时只是用k210通过串口通信把检测标签传到arduino,实现arduino的开关灯罢了)

# 震动传感器用pwm 引脚为15
tim = Timer(Timer.TIMER0, Timer.CHANNEL0, mode=Timer.MODE_PWM)
ch = PWM(tim, freq=500, duty=50, pin=15) # 设置PWM频率为500Hz

# 设置震动强度的函数
def set_vibration_intensity(duty_cycle):
    ch.duty(duty_cycle)  # 设置PWM占空比
    utime.sleep(1)  # 持续震动1秒钟
    ch.duty(0)  # 停止震动


# 震动传感器不用pwm
# LED灯连接在8号管脚上
# CanMV 开发板引脚配置
fm.register(8, fm.fpioa.GPIO0)

# 配置引脚为输出
zhen_onboard = GPIO(GPIO.GPIO0, GPIO.OUT) #构建LED对象

在img.draw_string(pos[0], pos[1], “%s : %.2f” %(labels[obj.classid()], obj.value()), scale=2, color=(255, 0, 0))代码下面添加判断语句。
请注意缩进,Python使用缩进来定义代码块,而不是像其他一些语言(如C或Java)那样使用大括号 {}。
在这里插入图片描述

if labels[obj.classid()]=="no":
   #zhen_onboard.value(0) #灯灭
    set_vibration_intensity(0)  #震动传感器频率为0不震动
    uart.write('n') #串口传输n到arduino

if labels[obj.classid()]=="yes":
    #zhen_onboard.value(1) #灯开
    set_vibration_intensity(40) #震动传感器频率为40,这个可以调节
    uart.write('y') #串口传输y到arduino

重点!!!!!!
把代码里面的两个"/sd/m.kmodel"改了,把/sd/删了就行。
在这里插入图片描述
在这里插入图片描述
代码就改好了。

7.把模型复制到sd卡中

拿出sd卡和读卡器,第一次使用先格式化吧,其实sd卡就相当于u盘。
在这里插入图片描述
在这里插入图片描述
把解压出来的模型文件拷贝到sd卡里面。在根目录创建sd文件夹,再把模型文件拷贝到sd文件里面。
在这里插入图片描述
(以防万一,有时候复制到u盘根目录会读取不到文件,看情况),把u盘弹出。
在这里插入图片描述

(1)在电脑运行main.py

把sd卡重新插入k210开发板里面,连数据线。点击CanMV IDE的连接按钮。
在这里插入图片描述
选择串口,这里是11
在这里插入图片描述

连上的图案是这样
在这里插入图片描述

震动传感器连线
在这里插入图片描述

点击运行就行。

(2)把main.py拷贝到k210的sd卡,直接在开发板上加载运行

重新用读卡器打开sd卡,然后拷贝已经编程好的main.py文件,注意:main.py里面的模型名字要一致。
加粗样式
在这里插入图片描述

将main.py文件也拷贝到sd文件夹里面。
在这里插入图片描述

弹出U盘,重新插上sd卡,上电后,按k210的RST键即可。
在这里插入图片描述

8.错误出现

如果出现这种错误,就是拷贝文件出错了。
在这里插入图片描述
把第5到第7重新做一遍即可

  • 16
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

relizi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值