前面我们搭建好了相关环境和最麻烦的 caffe 环境,接下来我们用 python 训练出来基于 caffe 的人脸识别 caffemodel。成功后我们再将它转化为海思开发板可以使用的 wk 文件。
这里我们先整理下我们的思路,首先 caffemodel 文件可以转化为海思可以读取的 wk 文件,但只是读取 caffemodel 文件中的网络参数,所以我们最好使用 YOLOv3 来进行人脸识别,方便后续的算法修改。我设定的流程为先用 PC 端的 python 进行人脸识别的开发,在 PC 端实现完整的人脸识别算法后,训练出合适的 caffemodel 文件,再转为 wk 文件。在海思开发板上实现人脸识别功能。
在算法的选择上,(算法原理到时再分别写一篇)
人脸检测使用 ResNet-10 + SSD
人脸识别可以使用 基于 LBPH 特征。(使用小数据集测试,有点不准)
后面可以尝试别的算法
(resnet model+arc head+softmax loss)
华为海思 AI 芯片 (Hi3559A V100) 算法开发(五) 在 Hi3559 上运行 YOLOv3
需要了解的一些基础概念,写在这里有点冗杂。分开写到另一篇文章好了,写好了附上链接
Caffe (1) 文件与数据介绍
import numpy as np
import argparse
import cv2
import os
我们先看看在 PC 端怎么设计人脸识别算法模型,并且训练模型,这篇文章的目标是设计一个人脸识别算法并在 PC 端跑起来
训练的话,估计得放到下一篇文章去
这里的读取设置,有两种方法,第一种是用 argparse 包,在运行文件是设定好路径,第二种是直接在里面写好
先讲解一下第一种数据读取方式(如果看着有点晕,可以先百度了解一下这个包)
创建解析器,添加参数,字典存放
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
help="path to input image")
ap.add_argument("-p", "--prototxt", required=True,
help="path to Caffe 'deploy' prototxt file")
ap.add_argument("-m", "--model", required=True,
help="path to Caffe pre-trained model")
ap.add_argument("-c", "--confidence", type=float, default=0.5,
help="minimum probability to filter weak detections")
args = vars(ap.parse_args())
总结一下使用方法,就是在命令栏,
带图片
python detect_faces.py -i ./iron_chic.jpg -p ./models/deploy.prototxt -m ./res10_300x300_ssd_iter_140000.caffemodel
视频流
python detect_faces_video.py -p ./models/deploy.prototxt -m ./res10_300x300_ssd_iter_140000.caffemodel
p代表什么,m代表什么,由自己设定,需要读取别的数据 ,可以自己再设定一个 -i
第二种读取方法:
构建图像或视频读取函数
def loadData(path):
#新建图像数据集与类别数据集
dataSet = []
label = []
# 读取路径下的文件名
person_list = os.listdir(path)
# 将一个可遍历的数列组合为索引序列
for i, a_person in enumerate(person_list):
# 将路径与文件名组合在一起
dir = os.path.join(path, a_person)
# 分别对每个文件下的文件名进行读取
img_list = os.listdir(dir)
# 对读取到的文件名的图片进行读取
for a_img in img_list:
ima = cv2.imread(os.path.join(dir, a_img), 0)
ima = cv2.resize(ima, (92, 92))
dataSet.append(ima)
# 将代表某个人的文件夹名的索引作为 label
label.append(i)
label = np.asarray(label)
return dataSet, label
第二种方法读取出来的数据如下:
[[48 49 44 ... 55 55 54]
[45 51 40 ... 51 51 51]
[47 48 45 ... 45 51 50]
...
[47 50 46 ... 45 47 45]
[47 52 49 ... 45 47 47]
[50 51 51 ... 47 46 46]] 1
前面为数据,后面为 label
这一步有一个函数十分的方便
net = cv2.dnn.readNetFromCaffe(args["prototxt"], args["model"])
这样就成功的将训练好的 Res-10 + SSD 算法模型加载进来
(训练的代码后面再挂出来)
读取神经网络相当于省掉了人脸检测的模型训练步骤,但人脸识别还是需要训练的。
这里如果理论不太懂的话,可以看我的另一篇博文 LBPH
dataSet, label = loadData(r'./img') # 加载人脸图像, 类别
lbfh = cv2.face.LBPHFaceRecognizer_create() # 创建LBPH人脸分类器
lbfh.train(dataSet, label) # 训练模型
lbfh.save('./my_lbph.xml') # 保存模型
第二次运行的话,就可以把第一步注释掉
创建人脸分类器,并加载模型参数到分类器内
读取数据并再训练,保存模型。不需要的话,可以注释掉
getLabels 用于读取标签
lbfh = cv2.face.LBPHFaceRecognizer_create() # 下次运行时,无需训练之间创建LBPH,然后read即可
lbfh.read('./my_lbph.xml') # 重载模型
dataSet, label = loadData('./img')
lbfh.update(dataSet, label) # 还提供了再训练方法
lbfh.save('./my_lbph.xml')
lbs = lbfh.getLabels() # 还可以展示所有已训练的图像的各个类别
print(lbs)
创建摄像头
cap = cv2.VideoCapture(0) # 创建摄像头
画面存储变量
result = None
置信度
CF = 0.3
读取图片并修改图片大小为 300*300
这里就代表获取宽和高
while 1:
_, frame = cap.read()
frame = cv2.resize(frame, (300, 300))
(h, w) = frame.shape[0:2]
print((h, w))
将图像输入到神经网络算法中
其中的 blobFromImage 主要用于对图像进行预处理
blobFromImage 详情
并将数据输入
blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 1.0, # 送入网络
(300, 300), (104.0, 177.0, 123.0))
net.setInput(blob)
detections = net.forward() # 网络前向预测
对识别置信度高于 CF 的物体进行显示
并给出起始坐标 X Y ,终点坐标 X Y
并抠出人脸,保存到 testImg
将人脸转化为灰度图,切换大小与数据库人脸一致
对人脸进行身份检测
将身份信息挂上
for i in range(0, detections.shape[2]):
confidence = detections[0, 0, i, 2]
print(confidence)
# filter out weak detections by ensuring the `confidence` is
# greater than the minimum confidence
if confidence < CF: # 置信度阈值
continue
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype("int")
testImg = frame[startY:endY, startX:endX] # 将人脸抠出
if testImg.shape[0] * testImg.shape[1] == 0:
continue
#
testImg = cv2.cvtColor(testImg, cv2.COLOR_BGR2GRAY)
testImg = cv2.resize(testImg, (IMAGE_SIZE, IMAGE_SIZE))
# predict face ID
result = lbfh.predict(testImg) # (id, a_float)
text = "{:.2f}%-{}".format(confidence * 100, result)
y = startY - 10 if startY - 10 > 10 else startY + 10
cv2.rectangle(frame, (startX, startY), (endX, endY),
(0, 0, 255), 2)
cv2.putText(frame, text, (startX, y),
cv2.FONT_HERSHEY_SIMPLEX, 0.45, (0, 0, 255), 2)
# show the output frame
cv2.imshow("Frame", frame)
key = cv2.waitKey(1) & 0xFF
# if the `q` key was pressed, break from the loop
if key == ord("q"):
break