前言:本文主要是以记录V831使用过程中一些经典历程使用笔记以及踩过的坑
一步一步向前走
1.介绍
2.例程
1.串口
先看这里https://wiki.sipeed.com/soft/maixpy3/zh/usage/hardware/UART.html
在 Linux 系统中,串口是以设备的形式存在(/dev/ttyS*),所使用的方式和原来的单片机方式有所不同。这是系统标准的 UART 通讯,和 Linux 系统中的串口操作相似。下面以 MaixII-Dock 为例子,来简单的简述一下如何使用 UART。
1.简单发送
import serial
ser = serial.Serial("/dev/ttyS1",115200) # 连接串口
print('serial test start ...')
ser.write(b"Hello Wrold !!!\n") # 输入需要通讯的内容
for i in range(3):
tmp = ser.readline()
print(tmp)
ser.write(tmp)
2.str与b
一、str转bytes:
第一种:在str类型前加b,即b"str"
第二种:在str后加.encode("utf-8"),即str.encode("utf-8"),编码方式默认是utf-8,里面 的"utf- 8"可以省略,下同。
二、bytes转str:
只有一种方法:在bytes后加.decode("utf-8"),即bytes.encode("utf-8")
3.DOME
1.人脸识别
1.代码(2023.4.21修正)
1.经典
废话不多讲,先上代码
from maix import nn, camera, image, display
from maix.nn.app.face import FaceRecognize
import time
from evdev import InputDevice
from select import select
import pickle
score_threshold = 70 #识别分数阈值
input_size = (224, 224, 3) #输入图片尺寸
input_size_fe = (128, 128, 3) #输入人脸数据
feature_len = 256 #人脸数据宽度
steps = [8, 16, 32] #
channel_num = 0 #通道数量
users = [] #初始化用户列表
names = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] #人脸标签定义
model = {
"param": "/home/model/face_recognize/model_int8.param",
"bin": "/home/model/face_recognize/model_int8.bin"
}
model_fe = {
"param": "/home/model/face_recognize/fe_res18_117.param",
"bin": "/home/model/face_recognize/fe_res18_117.bin"
}
for i in range(len(steps)):
channel_num += input_size[1] / steps[i] * (input_size[0] / steps[i]) * 2
channel_num = int(channel_num) #统计通道数量
options = { #准备人脸输出参数
"model_type": "awnn",
"inputs": {
"input0": input_size
},
"outputs": {
"output0": (1, 4, channel_num) ,
"431": (1, 2, channel_num) ,
"output2": (1, 10, channel_num)
},
"mean": [127.5, 127.5, 127.5],
"norm": [0.0078125, 0.0078125, 0.0078125],
}
options_fe = { #准备特征提取参数
"model_type": "awnn",
"inputs": {
"inputs_blob": input_size_fe
},
"outputs": {
"FC_blob": (1, 1, feature_len)
},
"mean": [127.5, 127.5, 127.5],
"norm": [0.0078125, 0.0078125, 0.0078125],
}
keys = InputDevice('/dev/input/event0')
threshold = 0.5 #人脸阈值
nms = 0.3
max_face_num = 1 #输出的画面中的人脸的最大个数
print("-- load model:", model)
m = nn.load(model, opt=options)
print("-- load ok")
print("-- load model:", model_fe)
m_fe = nn.load(model_fe, opt=options_fe)
print("-- load ok")
face_recognizer = FaceRecognize(m, m_fe, feature_len, input_size, threshold, nms, max_face_num)
def get_key(): #按键检测函数
r,w,x = select([keys], [], [],0)
if r:
for event in keys.read():
if event.value == 1 and event.code == 0x02: # 右键
return 1
elif event.value == 1 and event.code == 0x03: # 左键
return 2
elif event.value == 2 and event.code == 0x03: # 左键连按
return 3
return 0
def map_face(box,points): #将224*224空间的位置转换到240*240或320*240空间内
# print(box,points)
if display.width() == display.height():
def tran(x):
return int(x/224*display.width())
box = list(map(tran, box))
def tran_p(p):
return list(map(tran, p))
points = list(map(tran_p, points))
else:
# 168x224(320x240) > 224x224(240x240) > 320x240
s = (224*display.height()/display.width()) # 168x224
w, h, c = display.width()/224, display.height()/224, 224/s
t, d = c*h, (224 - s) // 2 # d = 224 - s // 2 == 28
box[0], box[1], box[2], box[3] = int(box[0]*w), int((box[1]-28)*t), int(box[2]*w), int((box[3])*t)
def tran_p(p):
return [int(p[0]*w), int((p[1]-d)*t)] # 224 - 168 / 2 = 28 so 168 / (old_h - 28) = 240 / new_h
points = list(map(tran_p, points))
# print(box,points)
return box,points
def darw_info(draw, box, points, disp_str, bg_color=(255, 0, 0), font_color=(255, 255, 255)): #画框函数
box,points = map_face(box,points)
font_wh = image.get_string_size(disp_str)
for p in points:
draw.draw_rectangle(p[0] - 1, p[1] -1, p[0] + 1, p[1] + 1, color=bg_color)
draw.draw_rectangle(box[0], box[1], box[0] + box[2], box[1] + box[3], color=bg_color, thickness=2)
draw.draw_rectangle(box[0], box[1] - font_wh[1], box[0] + font_wh[0], box[1], color=bg_color, thickness = -1)
draw.draw_string(box[0], box[1] - font_wh[1], disp_str, color=font_color)
def recognize(feature): #进行人脸匹配
def _compare(user): #定义映射函数
return face_recognizer.compare(user, feature) #推测匹配分数 score相关分数
face_score_l = list(map(_compare,users)) #映射特征数据在记录中的比对分数
return max(enumerate(face_score_l), key=lambda x: x[-1]) #提取出人脸分数最大值和最大值所在的位置
def run():
img = camera.capture() #获取224*224*3的图像数据
AI_img = img.copy().resize(224, 224)
if not img:
time.sleep(0.02)
return
faces = face_recognizer.get_faces(AI_img.tobytes(),False) #提取人脸特征信息
if faces:
for prob, box, landmarks, feature in faces:
key_val = get_key()
if key_val == 1: # 右键添加人脸记录
if len(users) < len(names):
print("add user:", len(users))
users.append(feature)
with open("/root/face_data.pickle",'wb') as f:
pickle.dump(users, f)
else:
print("user full")
elif key_val == 2: # 左键删除人脸记录
if len(users) > 0:
print("remove user:", names[len(users) - 1])
users.pop()
with open("/root/face_data.pickle",'wb') as f:
pickle.dump(users, f)
else:
print("user empty")
if len(users): #判断是否记录人脸
maxIndex = recognize(feature)
if maxIndex[1] > score_threshold: #判断人脸识别阈值,当分数大于阈值时认为是同一张脸,当分数小于阈值时认为是相似脸
darw_info(img, box, landmarks, "{}:{:.2f}".format(names[maxIndex[0]], maxIndex[1]), font_color=(0, 0, 255, 255), bg_color=(0, 255, 0, 255))
print("user: {}, score: {:.2f}".format(names[maxIndex[0]], maxIndex[1]))
else:
darw_info(img, box, landmarks, "{}:{:.2f}".format(names[maxIndex[0]], maxIndex[1]), font_color=(255, 255, 255, 255), bg_color=(255, 0, 0, 255))
print("maybe user: {}, score: {:.2f}".format(names[maxIndex[0]], maxIndex[1]))
else: #没有记录脸
darw_info(img, box, landmarks, "error face", font_color=(255, 255, 255, 255), bg_color=(255, 0, 0, 255))
display.show(img)
import os
if os.path.exists("/root/face_data.pickle"):
with open("/root/face_data.pickle",'rb')as f:
users = pickle.load(f)
else:
with open("/root/face_data.pickle",'wb') as f:
pickle.dump(users, f)
while True:
run()
2.加入串口
from maix import nn, camera, image, display
from maix.nn.app.face import FaceRecognize
import time
from evdev import InputDevice
from select import select
import pickle
from maix import pwm
import time
import pickle
import serial
ser = serial.Serial("/dev/ttyS1",115200) # 连接串口
score_threshold = 70 #识别分数阈值
input_size = (224, 224, 3) #输入图片尺寸
input_size_fe = (128, 128, 3) #输入人脸数据
feature_len = 256 #人脸数据宽度
steps = [8, 16, 32] #
channel_num = 0 #通道数量
users = [] #初始化用户列表
names = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] #人脸标签定义
model = {
"param": "/home/model/face_recognize/model_int8.param",
"bin": "/home/model/face_recognize/model_int8.bin"
}
model_fe = {
"param": "/home/model/face_recognize/fe_res18_117.param",
"bin": "/home/model/face_recognize/fe_res18_117.bin"
}
for i in range(len(steps)):
channel_num += input_size[1] / steps[i] * (input_size[0] / steps[i]) * 2
channel_num = int(channel_num) #统计通道数量
options = { #准备人脸输出参数
"model_type": "awnn",
"inputs": {
"input0": input_size
},
"outputs": {
"output0": (1, 4, channel_num) ,
"431": (1, 2, channel_num) ,
"output2": (1, 10, channel_num)
},
"mean": [127.5, 127.5, 127.5],
"norm": [0.0078125, 0.0078125, 0.0078125],
}
options_fe = { #准备特征提取参数
"model_type": "awnn",
"inputs": {
"inputs_blob": input_size_fe
},
"outputs": {
"FC_blob": (1, 1, feature_len)
},
"mean": [127.5, 127.5, 127.5],
"norm": [0.0078125, 0.0078125, 0.0078125],
}
keys = InputDevice('/dev/input/event0')
threshold = 0.5 #人脸阈值
nms = 0.3
max_face_num = 1 #输出的画面中的人脸的最大个数
print("-- load model:", model)
m = nn.load(model, opt=options)
print("-- load ok")
print("-- load model:", model_fe)
m_fe = nn.load(model_fe, opt=options_fe)
print("-- load ok")
face_recognizer = FaceRecognize(m, m_fe, feature_len, input_size, threshold, nms, max_face_num)
def get_key(): #按键检测函数
r,w,x = select([keys], [], [],0)
if r:
for event in keys.read():
if event.value == 1 and event.code == 0x02: # 右键
return 1
elif event.value == 1 and event.code == 0x03: # 左键
return 2
elif event.value == 2 and event.code == 0x03: # 左键连按
return 3
return 0
def map_face(box,points): #将224*224空间的位置转换到240*240空间内
def tran(x):
return int(x/224*240)
box = list(map(tran, box))
def tran_p(p):
return list(map(tran, p))
points = list(map(tran_p, points))
return box,points
def darw_info(draw, box, points, disp_str, bg_color=(255, 0, 0), font_color=(255, 255, 255)): #画框函数
box,points = map_face(box,points)
font_wh = draw.get_string_size(disp_str)
for p in points:
draw.draw_rectangle(p[0] - 1, p[1] -1, p[0] + 1, p[1] + 1, color=bg_color)
draw.draw_rectangle(box[0], box[1], box[0] + box[2], box[1] + box[3], color=bg_color, thickness=2)
draw.draw_rectangle(box[0], box[1] - font_wh[1], box[0] + font_wh[0], box[1], color=bg_color, thickness = -1)
draw.draw_string(box[0], box[1] - font_wh[1], disp_str, color=font_color)
def recognize(feature): #进行人脸匹配
def _compare(user):
global users
return face_recognizer.compare(user, feature) #推测匹配分数 score相关分数
face_score_l = list(map(_compare,users)) #映射特征数据在记录中的比对分数
return max(enumerate(face_score_l), key=lambda x: x[-1]) #提取出人脸分数最大值和最大值所在的位置
def run():
img = camera.capture() #获取224*224*3的图像数据
AI_img = img.copy().resize(224, 224)
if not img:
time.sleep(0.02)
return
faces = face_recognizer.get_faces(AI_img.tobytes(),False) #提取人脸特征信息
if faces:
for prob, box, landmarks, feature in faces:
key_val = get_key()
if key_val == 1: # 右键添加人脸记录
if len(users) < len(names):
print("add user:", len(users))
users.append(feature)
with open("/root/face_data.pickle",'wb') as f:
pickle.dump(users, f)
else:
print("user full")
elif key_val == 2: # 左键删除人脸记录
if len(users) > 0:
print("remove user:", names[len(users) - 1])
users.pop()
with open("/root/face_data.pickle",'wb') as f:
pickle.dump(users, f)
else:
print("user empty")
if len(users): #判断是否记录人脸
maxIndex = recognize(feature)
if maxIndex[1] > score_threshold: #判断人脸识别阈值,当分数大于阈值时认为是同一张脸,当分数小于阈值时认为是相似脸
darw_info(img, box, landmarks, "{}:{:.2f}".format(names[maxIndex[0]], maxIndex[1]), font_color=(0, 0, 255, 255), bg_color=(0, 255, 0, 255))
# print("user: {}, score: {:.2f}".format(names[maxIndex[0]], maxIndex[1]))
ser.write(str(maxIndex[0]+1).encode("utf-8")) # 输入需要通讯的内容
else:
darw_info(img, box, landmarks, "{}:{:.2f}".format(names[maxIndex[0]], maxIndex[1]), font_color=(255, 255, 255, 255), bg_color=(255, 0, 0, 255))
# print("maybe user: {}, score: {:.2f}".format(names[maxIndex[0]], maxIndex[1]))
ser.write(b"X\n")
else: #没有记录脸
darw_info(img, box, landmarks, "error face", font_color=(255, 255, 255, 255), bg_color=(255, 0, 0, 255))
ser.write(b"X\n")
display.show(img)
import os
if os.path.exists("/root/face_data.pickle"):
with open("/root/face_data.pickle",'rb')as f:
users = pickle.load(f)
else:
with open("/root/face_data.pickle",'wb') as f:
pickle.dump(users, f)
while True:
run()
2.部署
V831和K210区别还是挺大的,V831 AI内存64MB,K210可以使用的也仅仅只有可怜的6MB,摄像头像素也是有很明显的差距,跑人脸识别的时候差距更明显。进入正题吧。
人脸检测模型是内置的,在home里面,直接调用就行,之后原理也不多讲就是特征值。
- 确认 MaixPy3 版本为 0.4.0 以上
- 使用的硬件为 MaixII-Dock
- 内存卡内是最新版本的镜像系统
复制我的代码运行就可以了,哈哈哈。废话一堆。
3.踩过的坑
V831人俩识别maixpy给的教程挺详细的,之后使用的话一开始上手有点难,认真阅读代码后感觉还好。
跑人脸检测例程什么的都是OK,问题就是出现在怎么把人脸特征值储存在本地,困扰了我好久,一上午没找到什么有效地解决方案。。。。。。用官网给的储存例程是OK的,但是读取就出了问题,也尝试移植K210的本地存储,结果有字节模块没法运行,这里也是自己的一个坑。之后看了
import pickle
with open("/root/face_data.pickle",'rb')as f:
users = pickle.load(f)
print(users)
这个代码运行,运行读取是OK的,人脸特征值能读取出来,这里特此感谢https://blog.csdn.net/qq_51963216/article/details/123810347?ops_request_misc=&request_id=&biz_id=102&utm_term=V831%E2%80%94%E2%80%94%E4%BA%BA%E8%84%B8%E8%AF%86%E5%88%AB%E5%BC%80%E9%94%81&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-4-123810347.142v80insert_down38,201v4add_ask,239v2insert_chatgpt&spm=1018.2226.3001.4187
读取出来之后事情就简单的多了,之后在程序里面加入读取也没问题,但是人脸特征值就是添加不上,又是一个小时。。。。。。。。
最后各种调试打印,看到users
列表在recognize
竟然是空的,瞬间无语。很简单就是他只是def的局部变量,之后使用global users
定义为全局变量问题解决。
真的是 山重水复疑无路,柳暗花明又一村 淦