准备部分:

  1. Maix系列开发板
    我这里用的是MaixDock
    请添加图片描述
    连接硬件:
    在这里插入图片描述
  2. MaixPy_IDE
    下载链接:MaixPy_IDE
    选择exe,下载后直接点击安装即可,打开后像这样,用过openmv的应该十分熟悉这个界面了。
    在这里插入图片描述
    如果打开后没有显示右边的帧缓冲区,点击右边有个按钮,把帧缓冲区拖出来即可。

    运行第一个程序,点亮lcd
    将开发板接到电脑上,如果之前没有用过CH340,可以在设备管理器里看一下有没有读取到这个设备,如果没有的话,可以下载这个驱动:USB转串口Windows驱动程序.
    打开IDE,在工具栏里可以选择开发板。不过目前来看似乎选哪个都一样,不管是例程还是指向的github库都一样

    在这里插入图片描述

IDE中自带了一个例程,每一句的含义如下

import sensor, image, time, lcd    #导入摄像头,图像,时钟,lcd屏幕库

lcd.init(freq=15000000)            #设置lcd的频率,如果屏幕体质比较差就减小点,体质比较好就增大点
sensor.reset()                      # 摄像头初始化

sensor.set_pixformat(sensor.RGB565) # 选择图像格式,可以选择RGB565或者灰度
sensor.set_framesize(sensor.QVGA)   # 设置图像分辨率
sensor.skip_frames(time = 2000)     # 刚初始化图像不稳定,跳过前面的一段图像
clock = time.clock()                # Create a clock object to track the FPS.

while(True):
    clock.tick()                    # 跟踪运行的时间
    img = sensor.snapshot()         # 读取摄像头的一帧图像并放到img里
    lcd.display(img)                # 将img,也就是那帧图像用lcd显示
    print(clock.fps())              # 输出当前帧率,由于传输图像到IDE是需要消耗性能的,所以裸机跑是要比在IDE上帧率高

要知道这些函数具体的用法,可以参考这个文档API手册
之后点击下方的连接
在这里插入图片描述
选择当前对应的串口,不知道的可以去设备管理器中查看
在这里插入图片描述
在这里插入图片描述
点击运行
在这里插入图片描述
过几秒之后,就可以看到IDE和LCD屏幕都实时显示了摄像头的画面
在这里插入图片描述

实现人脸检测

在实现人脸检测之前,我们先了解如何完成固件的更新,因为可能一些板子自带的固件不是最新的,然后也可能导致一些问题。

先下载一个工具,用来写入固件以及模型
下载链接:kflash_gui
选择对应平台的,我这里是windows的,下载后解压,找到kflash_gui.exe执行就可以。


在这里插入图片描述

然后下载最新的固件,固件下载地址
选最新的点进去,然后就会出现一堆不同类型的固件,我们只看.bin结尾的文件。
在这里插入图片描述

这是官方的说明,但是现在命名方式有了点小变化。我这里用的是:

在这里插入图片描述

下载完之后,用刚才的工具把固件烧进去。
点击打开文件,选择刚才下载的固件(.bin结尾的),起始地址就默认为0x00000 ,然后选择开发板,然后是选择下到Flash还是SRAM,下载到Flash里后断电再上电依然有效,但是下到SRAM里的话断电后就失效了,所以建议下到Flash里。端口还是选择自己电脑里设备管理器上CH340的端口。波特率用默认的,速度模式选择高速。如果下载失败的话,可以尝试选择低速模式,然后降低波特率试试。
在这里插入图片描述

固件烧录之后,再次连接MaixPy IDE,没问题的话就可以下一步,下载模型了。
人脸检测的模型下载链接:官方模型
选择这个:
在这里插入图片描述

之后解压,别看他的后缀看似没见过,其实就是类似.zip。解压后可以看到一个.kmodel文件,一个json文件。
打开json文件,可以看到我们应该将这个固件下载到的地址0x300000.
在这里插入图片描述

现在打开刚才更新固件的软件Kflash_gui.起始地址就选0x300000.注意这里不要少打了个0,0x300000也就是3M多一点,不会影响到刚才写入的固件,如果少了个0,刚才写入的固件就用不了,打开IDE也会发现连接不上了。其余都和之前一样,选好了点下载就行。
在这里插入图片描述

再次打开IDE,连接成功之后就说明以上都没问题了。
然后人脸检测的代码在这里:demo_find_face.py
github现在需要科学上网,不行的话,gitee上也有这个的镜像:demo_find_face.py
打开后将代码复制到IDE里,注意这里的地址是不是和上面一致
在这里插入图片描述

不一致的话可能就会有这个错:
在这里插入图片描述
都没问题的话,连接后点击运行就可以看到效果了:

在这里插入图片描述

可以看到yolo2识别一帧只需要24ms,还是非常快的。但是我这里其实识别率并不高,它似乎在图像比较小的时候识别率高一些,待我再研究研究。
另外这里是将模型写入到flash里的,我们也可以将其写入到SD卡中。
以下是我写的注释

import sensor, image, lcd, time     #导入模块
import KPU as kpu                   #导入KPU模块
import gc, sys                      #导入模块,gc是内存回收相关模块,sys是系统的一些内置的模块


# 定义一个函数,用来将错误打印到lcd屏幕上,(这些错误也同时会答应到IDE的串行终端上)
def lcd_show_except(e):
    import uio                      #uio输入/输出流
    err_str = uio.StringIO()        #创建一个用于文本形式输入/输出的内存文件类对象
    sys.print_exception(e, err_str) #打印异常
    err_str = err_str.getvalue()    #获取保存数据的底层缓冲区的内容。
    img = image.Image(size=(224,224)) #创建图像,并将异常信息写入
    img.draw_string(0, 10, err_str, scale=1, color=(0xff,0x00,0x00))
    lcd.display(img)                #打印到LCD上


def main(model_addr=0x300000, lcd_rotation=0, sensor_hmirror=False, sensor_vflip=False):   #设置了模块的起始地址,lcd上图像的旋转角度,图像的水平以及垂直方向是否翻转
    try:
        sensor.reset()                 #重启摄像头
    except Exception as e:
        raise Exception("sensor reset fail, please check hardware connection, or hardware damaged! err: {}".format(e))
    sensor.set_pixformat(sensor.RGB565)
    sensor.set_framesize(sensor.QVGA)
    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)                #清屏

    anchors = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025)  #模型的锚点,不能改动
    try:
        task = None
        task = kpu.load(model_addr)         #从flash或者文件系统中加载模型,不需要关键词,传入参数即可,比如0x300000;"/sd/m.kmodel"
        print(task)                         #{"model_addr": 3145728, "model_size": 388776, "model_path": "(null)", "net_args": "(null)"}
        #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:            #列表不为空的话,遍历并画出个矩形框
                    img.draw_rectangle(obj.rect())
            img.draw_string(0, 200, "t:%dms" %(t), scale=2)  #在图像上显示时间
            lcd.display(img)                   #将图像打印到lcd上
    except Exception as e:
        raise e
    finally:
        if not task is None:
            kpu.deinit(task)                  #释放模型占用的内存, 立即释放, 但是变量还在


if __name__ == "__main__":
    try:
        main( model_addr=0x300000, lcd_rotation=0, sensor_hmirror=False, sensor_vflip=False)  #运行main函数
        # main(model_addr="/sd/m.kmodel")
    except Exception as e:
        sys.print_exception(e)
        lcd_show_except(e)
    finally:
        gc.collect()          #运行垃圾回收。