硬件平台:K210 Sipeed Maix Dock

软件平台:maixpy 、kmodelv2

实现功能 检测并识别人脸

一、下载模型和示例脚本

需要用到三个模型,

task_fd = kpu.load(0x300000) #从flash 0 0x300000 加载人脸检测模型
task_ld = kpu.load(0x400000) #从flash 0 0x400000 加载人脸五点关键点检测模型
task_fe = kpu.load(0x500000) #从flash 0 0x500000 加载人脸196维特征值模型

脚本如下:

import sensor
import image
import lcd
import KPU as kpu
import time
from Maix import FPIOA, GPIO
import gc
from fpioa_manager import fm
#from board import board_info
import utime
#import 相关库task_fd = kpu.load(0x300000) #从flash 0 0x300000 加载人脸检测模型
task_ld = kpu.load(0x400000) #从flash 0 0x400000 加载人脸五点关键点检测模型
task_fe = kpu.load(0x500000) #从flash 0 0x500000 加载人脸196维特征值模型clock = time.clock()  #初始化系统时钟,计算帧率fm.register(16, fm.fpioa.GPIOHS0) #设置 boot按键 的io
key_gpio = GPIO(GPIO.GPIOHS0, GPIO.IN)
start_processing = FalseBOUNCE_PROTECTION = 50def set_key_state(*_):  #按键中断global start_processingstart_processing = Trueutime.sleep_ms(BOUNCE_PROTECTION)key_gpio.irq(set_key_state, GPIO.IRQ_RISING, GPIO.WAKEUP_NOT_SUPPORT)lcd.init() #初始化 lcd
sensor.reset()#初始化sensor摄像头
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_hmirror(1) #设置摄像头镜像
sensor.set_vflip(1) #设置摄像头翻转
sensor.run(1) #试能摄像头
anchor = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437,6.92275, 6.718375, 9.01025)  # 人脸检测锚
dst_point = [(44, 59), (84, 59), (64, 82), (47, 105),(81, 105)]  # 标准人脸关键点位置  标准正脸的5关键点坐标 分别为 左眼 右眼 鼻子 左嘴角 右嘴角
a = kpu.init_yolo2(task_fd, 0.5, 0.3, 5, anchor) #初始化人脸检测模型
img_lcd = image.Image() #设置显示buf
img_face = image.Image(size=(128, 128))#设置 128*128 人脸图片buf
a = img_face.pix_to_ai() #将图片转换为kpu接受的格式
record_ftr = []  #空列表 用于存储当前196维特征值
record_ftrs = []  #空列表 用于存储按键记录下人脸特征,可以将特征以txt等文件形式保存到sd卡后,读取到此列表,即可实现人脸断电存储。
names = ['Mr.1', 'Mr.2', 'Mr.3', 'Mr.4', 'Mr.5','Mr.6', 'Mr.7', 'Mr.8', 'Mr.9', 'Mr.10']     # # 人名标签,与上面列表特征值一一对应。
ACCURACY = 85   # 设定分数标准 人脸阈值while (1):img = sensor.snapshot()clock.tick()code = kpu.run_yolo2(task_fd, img)  # 运行人脸检测模型,获取人脸坐标位置if code:  #如果检测到人脸for i in code: #迭代坐标框# Cut face and resize to 128x128a = img.draw_rectangle(i.rect()) #在屏幕显示人脸方框face_cut = img.cut(i.x(), i.y(), i.w(), i.h())  #裁剪人脸部分照片到 face_cutface_cut_128 = face_cut.resize(128, 128)  #将裁剪出的人脸照片缩放到 128*128 像素a = face_cut_128.pix_to_ai()   #将裁剪出的照片转换为kpu接受的格式# a = img.draw_image(face_cut_128, (0,0))# Landmark for face 5 pointsfmap = kpu.forward(task_ld, face_cut_128) #运行人脸5点关键点模型plist = fmap[:]  #获取关键点预测结果le = (i.x() + int(plist[0] * i.w() - 10), i.y() + int(plist[1] * i.h()))  #计算左眼位置,这里在w方向-10 用来补偿模型转换带来的精度损失re = (i.x() + int(plist[2] * i.w()), i.y() + int(plist[3] * i.h()))      #计算右眼位置nose = (i.x() + int(plist[4] * i.w()), i.y() + int(plist[5] * i.h()))    #计算鼻子位置lm = (i.x() + int(plist[6] * i.w()), i.y() + int(plist[7] * i.h()))      #计算左嘴角位置rm = (i.x() + int(plist[8] * i.w()), i.y() + int(plist[9] * i.h()))      #计算右嘴角位置#在相应位置处画小圈圈a = img.draw_circle(le[0], le[1], 4)a = img.draw_circle(re[0], re[1], 4)a = img.draw_circle(nose[0], nose[1], 4)a = img.draw_circle(lm[0], lm[1], 4)a = img.draw_circle(rm[0], rm[1], 4) #在相应位置处画小圈圈# align face to standard position 将面对齐到标准位置src_point = [le, re, nose, lm, rm]  #图片中五点坐标的位置T = image.get_affine_transform(src_point, dst_point)  #根据获得的5点坐标和标准正脸坐标获取仿射变换矩阵a = image.warp_affine_ai(img, img_face, T)  #对原始图片人脸图片进行仿射变换,变换为正脸图像a = img_face.ai_to_pix() #将图片转换为kpu接受的格式# a = img.draw_image(img_face, (128,0))del (face_cut_128)  #释放裁剪人脸部分照片# calculate face feature vector  计算人脸特征向量fmap = kpu.forward(task_fe, img_face)  #计算正脸图片的196维特征值feature = kpu.face_encode(fmap[:]) #获得计算结果reg_flag = Falsescores = [] #存储特征比对分数for j in range(len(record_ftrs)):  #迭代已存特征值score = kpu.face_compare(record_ftrs[j], feature)  #计算当前人脸特征值与已存特征值的分数scores.append(score) #添加分数总表max_score = 0index = 0for k in range(len(scores)):  #迭代所有比对分数,找到最大分数和索引值if max_score < scores[k]:max_score = scores[k]index = kif max_score > ACCURACY:  #如果最大分数大于85, 可以被认定为同一个人a = img.draw_string(i.x(), i.y(), ("%s :%2.1f" % (names[index], max_score)), color=(0, 255, 0), scale=2)     # 显示人名 与 分数else:a = img.draw_string(i.x(), i.y(), ("X :%2.1f" % (max_score)), color=(255, 0, 0), scale=2)    #显示未知 与 分数if start_processing:record_ftr = featurerecord_ftrs.append(record_ftr)start_processing = Falsebreakfps = clock.fps()  #计算帧率print("%2.1f fps" % fps) #打印帧率a = lcd.display(img) #刷屏显示gc.collect()# kpu.memtest()# a = kpu.deinit(task_fe)
# a = kpu.deinit(task_ld)
# a = kpu.deinit(task_fd)

上面这个示例脚本 在运行时每次都需要重新录入人脸的特征,将进行拍照。

拓展:

从flash中读取人脸特征:

#人脸检测的阈值
ACCURACY = 85#开机时从flash中读取人脸特征数据
try:with open("/flash/ftrs.dat",'rb') as f:while 1:l = f.read(4)if not l:breaklength = stc.unpack('i', l)[0]s = bytearray(f.read(length))record_ftrs.append(s)
except  :f = open("/flash/ftrs.dat",'w')f.close()print('find ' + str(len(record_ftrs)) + ' faces')while (1):img = sensor.snapshot()#运行人脸检测模型code = kpu.run_yolo2(task_fd, img)#如果存在人脸if code:

也可以改成从sd卡中读取人脸特征,将flash改为sd就可以了:

with open("/sd/ftrs.dat",'rb') as f:passf = open("/sd/ftrs.dat",'w')

二、烧录

老规矩 用kflash

三、运行

直接运行 会出现以下报错,原因是内存不足

解决方法: 烧录>1.5MB的固件,更改gc大小

内存不够 (MemoryError: Out of normal MicroPython Heap Memory!)

解决方法参考:https://neucrack.com/p/325

k210 有 6MiB 通用内存, 需要用到内存的有固件(K210 是一次性将所有代码加载到内存的….),一些功能所需比如摄像头缓冲区等,还有存放模型, 另外有 2MiB 给 KPU 专用的内存(如果使用 KPU 的话)

如果你不需要使用 KPU, 想给更多的内存给 CPU使用, 则最多可以用 8MiB 连续的内存, 方法是不初始化 KPU (时钟), 则可以有连续的 8MiB通用内存使用. 当然,在本文必须要用到 KPU, 所以只作为知识补充

所以需要总内存 = 固件大小 + 静态变量申请内存 + 其它功能动态申请(比如摄像头 屏幕显示申请的缓冲区, RGB888 缓冲区, Micropython 的GC 内存块) + 模型使用 + 剩余内存, 模型使用的内存在使用nncase转换的时候会有输出, V3 输出了 main memory usage, V4 输出了working memory usage.

另外,因为 KPU 专用内存只有 2MiB, 会用来放输入和输出层的数据, 所以在设计模型时, 一个层的输入和输出层, 以及上一层的输出层和下一层的输入层的大小和必须小于 2MiB

MaixPy 固件内有两个内存池,一个是系统内存,一个是 GC 内存,前者主要用来给模型还有系统内的一些功能使用,包括摄像头和屏幕的缓冲区等都来自这里;后者是 maixpy 解析器层面的内存,可以给代码的变量使用。

GC 剩余内存可以用下面的代码来打印

import gcprint(gc.mem_free())

GC 的总内存大小可以通过下面的代码来设置, GC 的大了, 系统的就小了,如果模型大这里就不要设置太大了。 另外注意!!要重启才生效。

from Maix import utilsimport machineold = utils.gc_heap_size()print(old)new = 512*1024utils.gc_heap_size(new)machine.reset()

另外,可以用kpu.memtest()查看一下大致上还剩多少,这个现实的系统内存不一定准确,只作参考

所以,解决内存不足有以下几种方法:

最基础的方法就是减少内存的使用,比如全局变量,不使用了尽量删除(通过del 变量名),删除之后还可以手动回收 GC 内存(通过gc.collect())。图片分辨率也可以尽量不要用太大(一般QVGA)

另一个方法就是压缩固件体积,通过裁减功能来减少内存占用,这个在前面固件升级部分有说明,使用在线编译定制固件,或者自己本机编译,方法见这里

还有一个方法就是设置 GC 内存池总大小,如果 GC 内存不够,就设置大点;如果系统内存不够用比如模型加载不了,在够用的范围内减小 GC 的大小, 留给加载模型使用

另外,如果模型太大,可以使用kpu.load_flash()函数来加载模型(只支持kmodel):
    这会在需要模型时实时从flash读取内容,这样就可以装载大模型了,效率会低一点,帧率会有所降低(原理有兴趣可以见另一篇文章K210 从flash实时加载大模型)。
    使用方法见这里,注意,模型需要先用脚本转一下大小端,别漏了!!

另外, 如果你在操作 image时或者lcd画图时遇到这个问题,可以合理利用lcd的display(img, oft=(x,y))的oft参数来实现在lcd指定区域画图,而不是画整副图。

比如,有个img的大小为200x200,现在需要画到屏幕,周围填充颜色,但是屏幕是320x240,可以先创建一个320x240的image填充颜色,然后拷贝这个200x200的图到这张图上,然后lcd.dispaly这张320x240的图,但是会需要浪费一个320x240图像的内存。可以直接lcd.clear(color)一次,或者lcd.fill_rectangle(0, 0, 320, 20)这样填充四周的颜色, 这个操作只需要一次,然后不断调用lcd.display(img_200x200, oft=(60, 20))刷新中间的区域的图像就好了,周围会保持最开始画的颜色。 画图片同理。

四、运行效果

这次用到了新的运行方法——使用 putty.exe

打开后按开发板的reset按钮,可以看到终端打印了启动信息

可以直接运行python代码

【K210】Maixpy 人脸识别相关推荐

  1. K210实现人脸识别(附代码解读)

    基于K210的人脸识别门禁(一) 进入官网(首次登陆需要注册)获取人脸识别源码 https://wiki.sipeed.com/soft/maixpy/zh/course/ai/image/face_ ...

  2. K210视觉体验—人脸识别

    K210视觉体验-人脸识别 使用设备 ZTFR开发板 人脸识别 构造函数 导入模型 示例代码 基础测试 炫酷识别 使用设备 ZTFR开发板 人脸识别 首先简单介绍一下 K210 的 KPU.KPU 是 ...

  3. 基于亚博K210的人脸识别

    前言 博主是通信方向,主要学习的是FPGA,但因和同学参加某个嵌入式比赛,题目是智能门禁系统,需要进行人脸识别,故博主快速学习了K210和Python,最终实现人脸识别.博主是速成而不是专业选手,故代 ...

  4. 【K210】人脸识别 KPU-kpu.run_yolo2()函数说明

    零.摄像头采集图像 img = sensor.snapshot() 这里 img 就可以直接作为输入, 这里需要 注意: snapshot() 函数采集到图片后,会将图片数据放到两个地方 (1) RG ...

  5. 零基础K210实现人脸识别(YOLO2)

    使用yolo2进行人脸识别,可进行人脸注册.人脸检测与人脸识别. 一.获取机器码 下载ken_gen固件:ken_gen  .打开ken_gen固件,使用kflash烧录.烧录完成,打开串口,按下复位 ...

  6. K210人脸识别+RFID录入信息

    K210系列教程 使用MaixPy IDE开发K210 K210实现人脸识别(附代码解读) K210人脸识别+人脸信息存储 K210人脸识别+RFID录入信息 (置顶:有位码友看了这篇博客后尝试了RF ...

  7. K210人脸识别+人脸信息存储

    K210系列教程 使用MaixPy IDE开发K210 K210实现人脸识别(附代码解读) K210人脸识别+人脸信息存储 K210人脸识别+RFID录入信息 在我的上一篇博客中已经介绍了如何使用K2 ...

  8. K210开发板学习笔记(一)——K210人脸识别门禁+SD卡实现人脸数据存储(附代码解读)

    基于K210的人脸门禁系统演示(按键录入人脸ID.人脸断电存储) 哔哩哔哩链接:https://b23.tv/MHXjhGa K210人脸识别门禁系统 一个按键实现所有功能. 具体功能: 在线人脸录入 ...

  9. 物联网毕设选题 机器视觉人脸识别系统 - 单片机 stm32 嵌入式

    文章目录 0 前言 1 简介 2 主要器件 3 实现效果 4 设计原理 4.1 K210实现人脸识别 5 部分核心代码 6 最后 0 前言

最新文章

  1. 计算机日期无法更改吗,电脑时间不能修改怎么办 电脑系统时间总是不对怎么办...
  2. linux 文件系统检查命令
  3. 【模板】割点(割顶)
  4. WinForm 实现拖拽功能
  5. css深入浅出 宽度和高度
  6. 流利的接口不利于维护
  7. doceker模拟数据的生成
  8. 超级实用的浏览器插件
  9. 2017年“达内杯”台州学院第十届大学生程序设计竞赛 非官方题解
  10. 蓝桥杯2014年(第5届)省赛b组c/c++ 史丰收速算
  11. npm安装任何包都报错解决方法
  12. 287. 寻找重复数
  13. 如何搞定不懂IT的领导
  14. Linux终端设备解析
  15. uniapp返回上一页携带参数,两种方法,实测有效
  16. Linux系统vim命令总结
  17. 用我一辈子去忘记(昆明-大理-丽江-香格里
  18. 1153 - 三个整数
  19. 编译与代码安全之认识(二):Source2Source源码混淆方法
  20. webuploader常用知识及方法、网站

热门文章

  1. C++重温笔记(十二): C++多文件编程
  2. bios 刷 灵耀14_华硕p8z77vlx2主板
  3. leetcode 19. 删除链表的倒数第 N 个结点(双指针应用)
  4. [论文速览] Probing Neural Network Comprehension of Natural Language Arguments
  5. 关于大一新生的一些话
  6. box-shadow:单边阴影与多边阴影
  7. python——三角函数用法
  8. 中国嵌入式应用市场四大热点及趋势
  9. 日志易之Agent统一IP地址开通多个端口
  10. 什么是日志服务(事件日志服务)