OpenCV+Tensorflow实现实时人脸识别演示
点击上方“小白学视觉”,选择加"星标"或“置顶”
重磅干货,第一时间送达
本文转自|OpenCV学堂
Facenet网络介绍
FaceNet是谷歌提出的人脸识别模型,它跟其他人脸识别模型最大的一个不同就是它不是一个中间层输出,而是直接在欧几里德低维空间嵌入生成人脸特征,这个对以后的各种识别、分类、相似度比较都非常方便。相比其他的深度学习方法,FaceNet仅需要128个字节来表示一张脸。FaceNet网络设计目标任务有如下
1.验证-验证是否为同一张脸
2.识别-识别是否为同一个人
3.聚类-发现人脸具有相同之处的人关于什么是神经网络嵌入,这个解释比较复杂,简单的说神经网络的嵌入学习可以帮助我们把离散变量表示为连续的向量,在低维空间找到最近邻,tensorflow中的word2vec就是用了嵌入。一旦嵌入神经网络训练好以后,目标任务就变得很简单:
人脸验证 – 就变成相似度比较问题
人脸识别 – 就变成KNN分类问题
人脸聚类 – 就变成通过K-Means可以完成的问题相比其它的人脸识别网络,通过添加分类层实现人脸识别,在分类层之前输出的人脸特征数据动则就几千个维度数据,而且不能很好表达一张新的人脸。FaceNet使用三元损失函数基于LMNN训练输出128维的连续向量。三元损失包含了两个匹配人脸的指纹与一个不匹配的人脸指纹,损失函数训练的目标是训练它在匹配人脸指纹与不匹配人脸指纹之间距离margin足够大为止。人脸指纹来自人脸区域图像,没有经过对齐,只是结果简单的几何变换。整个网络架构与三元表示如下:
其中
对正负样本的选择需要选择难样本得到triplet,有利于更好的训练效果与模型收敛。
代码实现:
借用了Github上的一个tensorflow版本facenet实现,下载了预训练的facenet模型,基于得到embedding数据,这个会输出512个维度数据,进行比较实现人脸相似度计算。相似度计算采用了余弦相似度度量,两个嵌入数据距离为0表示完全一致,距离为1表示完全不同。0.5或者90度表示二者相互独立。
facenet预训练模型下载:
https://github.com/davidsandberg/facenet加载模型与样本数据代码如下
with tf.Graph().as_default():
with tf.Session() as sess:
# Load the model
facenet.load_model("D:/python/facenet/data/20180408-102900")
# Get input and output tensors
images_placeholder = tf.get_default_graph().get_tensor_by_name("input:0")
embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0")
phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0")
# Run forward pass to calculate embeddings
images, names = load_face_labels()
num_labels = len(names)
feed_dict = {images_placeholder: images, phase_train_placeholder: False}
labels_embeddings = sess.run(embeddings, feed_dict=feed_dict)人脸比较的代码如下
def face_compare(face_image):
# Run forward pass to calculate embeddings
feed_dict = {images_placeholder: face_image, phase_train_placeholder: False}
embedding_result = sess.run(embeddings, feed_dict=feed_dict)
minDist = 1000000
label_index = -1
for i in range(num_labels):
# 余弦相似
dist = facenet.distance([labels_embeddings[i]], [embedding_result[0]], 1)
if minDist > dist:
label_index = i
minDist = dist
print("minDist: %1.4f"%minDist)
if minDist > 0.25:
return "unknown"
if names[label_index] == 3:
return "zhigang"
if names[label_index] == 2:
return "peter"
if names[label_index] == 1:
return "balvin"OpenCV实时摄像头调用与输出
capture = cv.VideoCapture(0)
height = capture.get(cv.CAP_PROP_FRAME_HEIGHT)
width = capture.get(cv.CAP_PROP_FRAME_WIDTH)
out = cv.VideoWriter("D:/faces.mp4", cv.VideoWriter_fourcc('D', 'I', 'V', 'X'), 15,
(np.int(width), np.int(height)), True)
while True:
ret, frame = capture.read()
if ret is True:
frame = cv.flip(frame, 1)
cv.imshow("frame", frame)
rgb = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
result, bb = mtcnn_align_demo(rgb)
if result is not None:
name = face_compare(result)
cv.rectangle(frame, (bb[0], bb[1]), (bb[2], bb[3]), (0, 0, 255), 1, 8, 0)
cv.putText(frame, name, (bb[0], bb[1]), cv.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2, 8)
cv.imshow("face recognition demo", frame)
out.write(frame)
cv.imwrite("D:/face_recognition.png", frame)
c = cv.waitKey(10)
if c == 27:
break
else:
break
out.release()
capture.release()
cv.destroyAllWindows()人脸数据采集
通过MTCNN进行人脸实时检测,采集了待比较的每个人的人脸数据,进行了数据采选,打上了标签。采集数据代码如下:
while True:
ret, frame = capture.read()
if ret is True:
frame = cv.flip(frame, 1)
cv.imshow("frame", frame)
rgb = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
result = detection(rgb)
out.write(result)
c = cv.waitKey(10)
if c == 27:
break
else:
break
cv.destroyAllWindows()更详细的关于MTCNN可以看推荐阅读
运行效果
balvin与我
交流群
欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~