第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > 【Dlib人脸识别】1. Dlib人脸检测的基本原理

【Dlib人脸识别】1. Dlib人脸检测的基本原理

时间:2019-08-07 17:36:28

相关推荐

【Dlib人脸识别】1. Dlib人脸检测的基本原理

Dlib中,人脸识别的基本思路为:

计算已知图片中所有人脸对应的特征向量;计算要识别的未知图片中所有人脸对应的特征向量;计算人脸之间的欧式距离;如果两张人脸之间的欧式距离小于设定的阈值,则认为是同一个人,否则认为不是同一个人

【 1. 计算特征向量 】

在人脸特征点检测中,我们学会了如何获取人脸的特征点。但是特征点只是用于标识人脸关键点的坐标而已,如果想要实现人脸识别,那么必须将特征点转换为特征向量。

1. 加载人脸识别模型

链接:dlib_face_recognition_resnet_model_v1.dat

提取码:b8zu

首先,我们得通过dlib.face_recognition_model_v1()加载人脸识别的模型:

dlib.face_recognition_model_v1(人脸识别模型路径)

import dlibimport cv2#人脸识别模型的路径face_rec_model_path = 'dlib_face_recognition_resnet_model_v1.dat'# 加载人脸识别模型facerec = dlib.face_recognition_model_v1(face_rec_model_path)

2. 计算特征向量

在加载完模型之后,我们需要先使用前面学到的知识,先检测特征点:

import cv2# 加载人脸识别模型face_rec_model_path = 'dlib_face_recognition_resnet_model_v1.dat'facerec = dlib.face_recognition_model_v1(face_rec_model_path)# 加载特征点识别模型predictor_path = "shape_predictor_5_face_landmarks.dat"predictor = dlib.shape_predictor(predictor_path)# 读取图片img_path = "step1/image/face.jpg"img = cv2.imread(img_path)# 转换为灰阶图片gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 正向人脸检测器将图像detector = dlib.get_frontal_face_detector()# 使用人脸识别模型来检测图像中的人脸faces = detector(gray, 1)# 使用特征点识别模型来检测人脸中的特征for i, face in enumerate(faces):# 获取人脸特征点shape = predictor(img, face)

通过上面的代码,我们检测到人脸的特征点,并将它们保存在shape中。下面我们通过pute_face_descriptor()来计算特征向量,它的函数声明如下:

pute_face_descriptor(图片对象, 特征点)

具体代码如下:

face_descriptor = pute_face_descriptor(img,shape)

这样,我们就计算出了人脸特征向量。

【 2. 计算欧氏距离 】

欧氏距离(也称欧几里得距离)是一个常用的的距离度量,它指的是在空间中两个向量(点)之间的直线距离。

欧氏距离越小,说明两个向量越接近,也就是两个向量差异越小。

假设在两个向量分别为 x(x1,x2,…,xm) 和 y(y1,y2,…,ym),则这两个向量的欧氏距离的计算公式为:

( x 1 − y 1 ) 2 + ( x 2 − y 2 ) 2 + . . + ( x m − y m ) 2 ( x 1 − y 1 ) \sqrt{(x_1-y_1)^2+(x_2-y_2)^2+..+(x_m-y_m)^2}\sqrt{(x_1−y_1)} (x1​−y1​)2+(x2​−y2​)2+..+(xm​−ym​)2 ​(x1​−y1​) ​

在Python中可以通过长度为 m 的列表来表示维数为 m 的向量。

例如x为(1,2,3,4,5),那么它可以表示为x=[1,2,3,4,5]。

在Python中计算两个长度相同的列表的欧氏距离:

import numpy as np #导入numpy库x = [1,2,3,4,5] # 声明两个长度相同的列表y = [3,4,5,2,1]x_array = np.array(x)# 将列表转换为numpy数组y_array = np.array(y)distance = np.linalg.norm(x_array-y_array) # 计算x_array与y_array之间的欧氏距离

【 3. 识别人脸 】

上面我们提到,两个向量的欧氏距离越小,说明两个向量越接近。将这个结论放在人脸识别中,可以得出以下结论:

两张人脸特征向量的欧氏距离越小,说明两个人越相似。当欧氏距离小于某一个值时,则可以认为他们是同一个人。

基于这个结论,我们可以实现人脸识别。

1. 准备数据

我们将事先准备的人脸图片作为本次识别的数据,并把图片分成两个部分。第一个部分为已知的图片,另一部分为待识别的图片。

已知图片:

待识别图片:

理想情况下,我们的人脸识别算法应该做到:如果待识别图片中的人出现在了已知图片中,那么应该正确地输出姓名,否则,就输出Unknow。

2. 计算所有已知图片中人脸的特征向量

因为需要获取所有已知图片中的特征向量,首先得获取到图片。

在这里我们借助glob模块下的glob()来获取图片:

glob(正则表达式):#glob()返回匹配的文件列表,

glob()会返回匹配的文件列表,这样我们就可以获取到在known_image_path下所有以jpg结尾的的图片,如下:

import globglob.glob(os.path.join(known_image_path, "*.jpg"))

然后我们就可以来计算所有已知图片中人脸的特征向量,代码如下所示:

known_image_path = "step1/image/known_image"# 声明descriptors,用于存放已知图片对应的人脸特征向量descriptors = []# 声明names,用于存放于人脸特征向量对应的名字。names = ["TongDaWei","XiaYu","ZhangYiShan"] # 遍历known_image_path文件夹下所有以.jpg结尾的文件。for f in glob.glob(os.path.join(known_image_path, "*.jpg")):img = dlib.load_rgb_image(f)# 1.人脸检测dets = detector(img, 1)for k, d in enumerate(dets):# 2.关键点检测shape = predictor(img, d)# 3.计算特征向量(也成为人脸描述符)descriptor = pute_face_descriptor(img, shape)# 转换为numpy数组v = np.array(descriptor)descriptors.append(v)

3. 识别人脸

当欧氏距离小于某个阈值时,则可以认为他们是同一个人。那这个阈值应该设定为多少呢?

原理:计算待识别的图片特征向量与已知图片特征向量的欧氏距离,如果欧氏距离小于阈值,则认为是同一张图片。在Dlib中,对于在LFW人脸数据集,当阈值设置为0.6时,的识别精度能达到99.38%。但是,当阈值设置为0.6时,对于小孩和亚洲人的识别率不是很高。故我们要识别的图片是亚洲人时,要将阈值适当地降低,在这里我们设置为0.4。

具体代码片段如下

tolerance = 0.4current_name = "Unknow"for i in range(len(descriptors)):#假设当前带识别的图片特征为currentdistance = np.linalg.norm(descriptors[i]-current)if distance<tolerance:#names用于存放于已知人脸特征向量对应的名字current_name = names[i]breakprint("当前图片识别结果为:"+current_name)

【 4. 范例 】

# 0. 导入模块import osimport dlibimport globimport numpy as npimport cv2# 1. 加载模型、图片## 正向人脸检测器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)## 已知图片known_image_path = 'know'## 测试图片test_image_path = "unknow"# 2. 声明存放数据的变量## 声明descriptors,用于存放已知图片对应的人脸特征向量descriptors = []## 声明names,用于存放于人脸特征向量对应的名字。names = ["reba"]# 3. 开始检测## 遍历known_image_path文件夹下所有以.jpg结尾的文件。for f in glob.glob(os.path.join(known_image_path, "*.jpg")):img = dlib.load_rgb_image(f)## 使用 detector 检测器来检测图像中的人脸dets = detector(img, 1)for k, d in enumerate(dets):## 获取人脸特征点shape = predictor(img, d)## 计算特征向量face_descriptor = pute_face_descriptor(img, shape)## 特征向量转换为numpy arrayv = np.array(face_descriptor)## 把此次数据存到人脸特征向量列表里面descriptors.append(v)# 4. 进行判断## 遍历test_image_path文件夹下所有以.jpg结尾的文件。for f in glob.glob(os.path.join(test_image_path, "*.jpg")):img = dlib.load_rgb_image(f)## 使用 detector 检测器来检测图像中的人脸dets = detector(img, 1)for k, d in enumerate(dets):## 获取人脸特征点shape = predictor(img, d)## 计算特征向量face_descriptor = pute_face_descriptor(img, shape)## 将当前待判断的图片特征向量转化为 currentcurrent = np.array(face_descriptor)## 计算欧式距离,识别人脸### 设置阈值tolerance = 0.1### 设置该图片名字初值为:Unknowcurrent_name = "Unknow name"### 对这个存放着已知图片特征向量的列表descriptors[]遍历for i in range(len(descriptors)):### 计算欧氏距离distance = np.linalg.norm(descriptors[i] - current)### 对欧氏距离判断if distance < tolerance:### names用于存放着人脸特征向量对应的名字current_name = names[i]break## 输出对当前图片的识别结果print("当前图片识别结果为:" + current_name)

运行结果:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。