专栏首页AI科技大本营的专栏实战 | 如何用最快的速度学会Dlib人脸识别开发?

实战 | 如何用最快的速度学会Dlib人脸识别开发?

作者 | 小宋是呢 来源 | 转载自小宋是呢

项目GitHub地址:https://github.com/xiaosongshine/dlib_face_recognition

1.背景介绍

Dlib是一个深度学习开源工具,基于C++开发,也支持Python开发接口,功能类似于TensorFlow与PyTorch。但是由于Dlib对于人脸特征提取支持很好,有很多训练好的人脸特征提取模型供开发者使用,所以Dlib人脸识别开发很适合做人脸项目开发。

上面所说的人脸识别开发,主要是指人脸验证,就是输入两张人脸照片,系统会对比输出0或者1,代表判断是否是同一个人。一般的人脸识别开发可以简单分为1.人脸特征建模与2.使用人脸特征模型进行验证(其实还应包括人脸对齐等,这些也可以划分到1中)。使用Dlib进行开发时,我们直接可以使用训练好的人脸特征提取模型,主要的工作就变成了如何进行人脸的验证。

人脸的验证其实就是计算相似度,同一个人的相似度就会大,不同的人就会比较小。可以采用余弦相似度或者欧式距离来计算相似度。其中余弦相似度就是计算角度,欧式距离就是指平方差。都可以用来表示两个特征的相似度(距离)。

2.环境搭建

安装可以参考我的这篇博客:[深度学习工具]·极简安装Dlib人脸识别库,下面说一下需要注意的点::

此博文针对Windows10安装,其他平台可以仿照这个步骤来安装

  • 安装Miniconda

使用conda指令来安装Dlib库,使用Miniconda与Anaconda都可以,我习惯用Miniconda,简单占用内存小。

推荐使用清华源,下载安装,选择合适的平台版本。python==3.6

  • 安装dlib

注意一定要以管理员身份进入CMD,执行(如果是Linux Mac 就使用 sudo)

conda install -c conda-forge dlib

需要imageio 库,可以使用下述命令安装

conda install imageio

3.开发实战

1.实现人脸检测标记

face_test.py
import dlib
from imageio import imread
import glob
detector = dlib.get_frontal_face_detector()
win = dlib.image_window()
path = "f1.jpg"
img = imread(path)
dets = detector(img)
print('检测到了 %d 个人脸' % len(dets))
for i, d in enumerate(dets):
print('- %d:Left %d Top %d Right %d Bottom %d' % (i, d.left(), d.top(), d.right(), d.bottom()))

win.clear_overlay()
win.set_image(img)
win.add_overlay(dets)
dlib.hit_enter_to_continue()

代码很简单,通过imread读取照片,然后进行检测,输出结果为dets的list,有几张人脸就会有几个item, 每个item都有.left(), .top(), .right(), .bottom()四个元素,代表人脸框的四个边界位置。最后通过win.add_overlay(dets)可以将标记的框显示在原图上。

原始照片

输出照片

其实我们就可以使用这个功能做一个简单的应用,用来检测图片或者视频中人脸的个数。

2.人脸特征点提取

在实战1的基础上添加人脸特征提取功能。

import dlib
from imageio import imread
import glob
detector = dlib.get_frontal_face_detector()
win = dlib.image_window()
predictor_path = 'shape_predictor_68_face_landmarks.dat'
predictor = dlib.shape_predictor(predictor_path)
path = "f2.jpg"
img = imread(path)
dets = detector(img)
print('检测到了 %d 个人脸' % len(dets))
for i, d in enumerate(dets):
print('- %d: Left %d Top %d Right %d Bottom %d' % (i, d.left(), d.top(), d.right(), d.bottom()))

shape = predictor(img, d)

    # 第 0 个点和第 1 个点的坐标

print('Part 0: {}, Part 1: {}'.format(shape.part(0), shape.part(1)))

win.clear_overlay()
win.set_image(img)
win.add_overlay(dets)
win.add_overlay(shape)
dlib.hit_enter_to_continue()

这段代码就是在test.py基础上加入了shape_predictor功能,使之可以在检测出人脸基础上,找到人脸的68个特征点。反映在图中就是蓝色的线。

原始图片

输出图片

注意运行这段代码需要这个文件predictor_path = 'shape_predictor_68_face_landmarks.dat',我会放在我的github中,方便大家下载使用。

3.人脸识别验证

在第二步的基础上,我们再进一步,实现将人脸提取为特征向量,从而我们就可以对特征向量进行比对来实现人脸的验证,这里采用的是对比欧式距离的方法。

face_recognition.py
import dlib
from imageio import imread
import glob
import numpy as np
detector = dlib.get_frontal_face_detector()
predictor_path = 'shape_predictor_68_face_landmarks.dat'
predictor = dlib.shape_predictor(predictor_path)
face_rec_model_path = 'dlib_face_recognition_resnet_model_v1.dat'
facerec = dlib.face_recognition_model_v1(face_rec_model_path)
def get_feature(path):
img = imread(path)

dets = detector(img)

print('检测到了 %d 个人脸' % len(dets))

# 这里假设每张图只有一个人脸

shape = predictor(img, dets[0])

face_vector = facerec.compute_face_descriptor(img, shape)

return(face_vector)

def distance(a,b):
a,b = np.array(a), np.array(b)

sub = np.sum((a-b)**2)

add = (np.sum(a**2)+np.sum(b**2))/2.

return sub/add

path_lists1 = ["f1.jpg","f2.jpg"]
path_lists2 = ["赵丽颖照片.jpg","赵丽颖测试.jpg"]
feature_lists1 = [get_feature(path) for path in path_lists1]
feature_lists2 = [get_feature(path) for path in path_lists2]
print("feature 1 shape",feature_lists1[0].shape)
out1 = distance(feature_lists1[0],feature_lists1[1])
out2 = distance(feature_lists2[0],feature_lists2[1])
print("diff distance is",out1)
print("same distance is",out2)
out1 = distance(feature_lists1[0],feature_lists1[1])
out2 = distance(feature_lists2[0],feature_lists2[1])

输出结果

检测到了 1 个人脸
检测到了 1 个人脸
检测到了 1 个人脸
检测到了 1 个人脸
feature 1 shape (128, 1)
diff distance is 0.254767715912
same distance is 0.0620976363391

我们可以看出,每张人脸都被提取为了128维的向量,我们可以理解为128维的坐标(xyz是三维,128维就是有128个轴组成),我们下面需要做的就是计算两个特征的距离,设定好合适的阈值,小于这个阈值则识别为同一个人。代码正确运行需要这个文件face_rec_model_path = 'dlib_face_recognition_resnet_model_v1.dat',我已经放在自己的github(https://github.com/xiaosongshine/dlib_face_recognition)中,方便大家使用。

我们从上面测试的结果可以看出,不同的距离为0.25,同一个人为0.06,阈值就可以先设置为其间的一个值。我这里先设置为0.09,这个阈值也是需要大量数据来计算的,选择的准则为使错误识别为最低。

下面我们把阈值设置为0.09,来测试系统能否区分出不同的人:在face_recognition.py加入下面代码

def classifier(a,b,t = 0.09):
if(distance(a,b)<=t):

    ret = True

else :

    ret = False

return(ret)

print("f1 is 赵丽颖",classifier(feature_lists1[0],feature_lists2[1]))
print("f2 is 赵丽颖",classifier(feature_lists1[1],feature_lists2[1]))
print("赵丽颖照片.jpg is 赵丽颖测试.jpg",classifier(feature_lists2[0],feature_lists2[1]))

输出结果

f1 is 赵丽颖 False
f2 is 赵丽颖 False
赵丽颖照片.jpg is 赵丽颖测试.jpg True

从上面可以看出,已基本满足对人脸区分的功能,如果如要实用化则需要继续调优阈值与代码,调优的准则就是选择合适的阈值使错误识别为最低。

Hope this helps

原文链接:https://blog.csdn.net/xiaosongshine/article/details/89496667

本文分享自微信公众号 - AI科技大本营(rgznai100),作者:小宋是呢

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-06-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 资源 |“从蒙圈到入坑”,推荐新一波ML、DL、RL以及数学基础等干货资源

    编译| AI科技大本营(rgznai100) 参与 | suiling 此前营长曾发过一篇高阅读量、高转发率,高收藏量的文章《爆款 | Medium上6900...

    AI科技大本营
  • 别瞎搞!对自己定位不准,看再多机器学习资料也是白搭(附资源)

    找资料也是门学问,别抓着机器学习就一拥而上。 作者 | Jason Brownlee 编译 | AI100(ID:rgznai100) 来看个小故事:机器学习火...

    AI科技大本营
  • 干货 | 目标检测入门,看这篇就够了(下)

    ? 作者 | 李家丞( 同济大学数学系本科在读,现格灵深瞳算法部实习生) 近年来,深度学习模型逐渐取代传统机器视觉方法而成为目标检测领域的主流算法,本系列文...

    AI科技大本营
  • [深度应用]·实战掌握Dlib人脸识别开发教程

    Dlib是一个深度学习开源工具,基于C++开发,也支持Python开发接口,功能类似于TensorFlow与PyTorch。但是由于Dlib对于人脸特征提取支持...

    小宋是呢
  • 手把手教学从0到1搭建人脸融合小程序(下)

    由于本文主要介绍小程序端调用人脸融合云接口,所以前端这里简单设计,整个前端页面分为三个区域:

    MIKADO
  • 90行代码,15个元素实现无限滚动

    无限下拉加载技术使用户在大量成块的内容面前一直滚动查看。这种方法是在你向下滚动的时候不断加载新内容。

    前端劝退师
  • 探索:怎样将单个vue文件转换为小程序所需的四个文件(wxml, wxss, json, js)

    比如JavaScript在执行之前,会经过词法分析和语法分析两个步骤之后,得到一个抽象语法树。

    极乐君
  • 构造Python中的常量类

    通过命名风格来提示使用者该变量代表的意义为常量,比如MAX_NUMBER、TOTAL。然而这种方式并没有真正实现常量,其对应的值仍然可以被改变,这只是一种约定俗...

    py3study
  • 深度:从零编写一个微前端框架

    那么现在我们需要手写一个微前端框架,首先得让大家知道什么是微前端,现在微前端模式分很多种,但是大都是一个基座+多个子应用模式,根据子应用注册的规则,去展示子应用...

    Peter谭金杰
  • Golang之变量去哪儿

    写过C/C++的同学都知道,调用著名的malloc和new函数可以在堆上分配一块内存,这块内存的使用和销毁的责任都在程序员。一不小心,就会发生内存泄露,搞得胆战...

    梦醒人间

扫码关注云+社区

领取腾讯云代金券