人脸识别实战:使用Opencv+SVM实现人脸识别

2022-07-23 0 513

在本文中,您将学习如何使用 OpenCV 进行人脸识别。文章分三部分介绍:

第一,将首先执行人脸检测,使用深度学习从每个人脸中提取人脸量化为128位的向量。

第二, 在嵌入基础上使用支持向量机(SVM)训练人脸识别模型。

第三,最后使用 OpenCV 识别图像和视频流中的人脸。

项目结构
facedetection
├─dataset
│ ├─Biden
│ ├─chenglong
│ ├─mayun
│ ├─Trump
│ ├─yangmi
│ └─zhaoliying
├─face_dete_model
│ ├─deploy.proto.txt
│ └─res10_300x300_ssd_iter_140000_fp16.caffemodel

├─output
├─face_embeddings.py
├─nn4.small2.v1.t7
├─recognize_face.py
├─recognize_video.py
└─train_face.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
编码
新建face_embeddings.py脚本,写入如下代码:

# import the necessary packages
import numpy as np
import pickle
import cv2
import os
import os
1
2
3
4
5
6
导入需要的包。然后定义几个函数:

def list_images(basePath, contains=None):
# return the set of files that are valid
return list_files(basePath, validExts=image_types, contains=contains)

def list_files(basePath, validExts=None, contains=None):
# loop over the directory structure
for (rootDir, dirNames, filenames) in os.walk(basePath):
# loop over the filenames in the current directory
for filename in filenames:
# if the contains string is not none and the filename does not contain
# the supplied string, then ignore the file
if contains is not None and filename.find(contains) == -1:
continue
# determine the file extension of the current file
ext = filename[filename.rfind(“.”):].lower()
# check to see if the file is an image and should be processed
if validExts is None or ext.endswith(validExts):
# construct the path to the image and yield it
imagePath = os.path.join(rootDir, filename)
yield imagePath

def resize(image, width=None, height=None, inter=cv2.INTER_AREA):
dim = None
(h, w) = image.shape[:2]
# 如果高和宽为None则直接返回
if width is None and height is None:
return image
# 检查宽是否是None
if width is None:
# 计算高度的比例并并按照比例计算宽度
r = height / float(h)
dim = (int(w * r), height)
# 高为None
else:
# 计算宽度比例,并计算高度
r = width / float(w)
dim = (width, int(h * r))
resized = cv2.resize(image, dim, interpolation=inter)
# return the resized image
return resized
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
list_images函数,读取数据集文件夹下面的图片。

resize函数,等比例resize图片。接下来定义一些变量:

dataset_path=’dataset’
embeddings_path=’output/embeddings.pickle’
detector_path=’face_dete_model’
embedding_model=’nn4.small2.v1.t7′
confidence_low=0.5
1
2
3
4
5
dataset_path:数据集路径

embeddings_path:输出编码文件的路径

detector_path:人脸检测模型的路径

embedding_model:编码模型

confidence_low:最低的置信度。

接下来就是代码的最重要的部分:

print(“loading face detector…”)
protoPath = os.path.sep.join([detector_path, “deploy.proto.txt”])
modelPath = os.path.sep.join([detector_path,”res10_300x300_ssd_iter_140000_fp16.caffemodel”])
detector = cv2.dnn.readNetFromCaffe(protoPath, modelPath)
# 加载序列化的人脸编码模型
print(“loading face recognizer…”)
embedder = cv2.dnn.readNetFromTorch(embedding_model)
# 获取数据集中输入图像的路径
print(“quantifying faces…”)
imagePaths = list(list_images(dataset_path))
# 初始化我们提取的面部编码列表和相应的人名
knownEmbeddings = []
knownNames = []
# 初始化处理的人脸总数
total = 0
# loop over the image paths
for (i, imagePath) in enumerate(imagePaths):
# extract the person name from the image path
print(“processing image {}/{}”.format(i + 1,len(imagePaths)))
name = imagePath.split(os.path.sep)[-2]
# 加载图像,将其调整为宽度为 600 像素(同时保持纵横比),然后抓取图像尺寸
image = cv2.imread(imagePath)
image = resize(image, width=600)
(h, w) = image.shape[:2]
# 从图像构建一个 blob
imageBlob = cv2.dnn.blobFromImage(
cv2.resize(image, (300, 300)), 1.0, (300, 300),
(104.0, 177.0, 123.0), swapRB=False, crop=False)
# 使用 OpenCV 的基于深度学习的人脸检测器来定位输入图像中的人脸
detector.setInput(imageBlob)
detections = detector.forward()
# ensure at least one face was found
if len(detections) > 0:
# 假设每个图像只有一张脸,所以找到概率最大的边界框
i = np.argmax(detections[0, 0, :, 2])
confidence = detections[0, 0, i, 2]
# 确保最大概率的检测也意味着我们的最小概率测试(从而帮助过滤掉弱检测)
if confidence > confidence_low:
# 计算人脸边界框的 (x, y) 坐标
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype(“int”)
# 提取人脸ROI并抓取ROI维度
face = image[startY:endY, startX:endX]
(fH, fW) = face.shape[:2]
# 确保人脸宽度和高度足够大
if fW < 20 or fH < 20:
continue
# 为人脸 ROI 构造一个 blob,然后将 blob 通过我们的人脸嵌入模型来获得人脸的 128-d 量化
faceBlob = cv2.dnn.blobFromImage(face, 1.0 / 255,
(96, 96), (0, 0, 0), swapRB=True, crop=False)
embedder.setInput(faceBlob)
vec = embedder.forward()
# 将人名+对应的人脸嵌入添加到各自的列表中
knownNames.append(name)
knownEmbeddings.append(vec.flatten())
total += 1
# 保存编码文件
print(“serializing {} encodings…”.format(total))
data = {“embeddings”: knownEmbeddings, “names”: knownNames}
f = open(embeddings_path, “wb”)
f.write(pickle.dumps(data))
f.close()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
加载人脸检测器和编码器:

检测器:使用基于Caffe的DL人脸检测器来定位图像中的人脸。

编码器:模型基于Torch,负责通过深度学习特征提取来提取人脸编码。

接下来,让我们抓取图像路径并执行初始化。

遍历 imagePaths。从路径中提取人名。

构造了一个 blob。

然后,通过将 imageBlob 通过检测器网络来检测图像中的人脸。

检测列表包含定位图像中人脸的概率和坐标。

假设我们至少有一个检测,将进入 if 语句的主体。

假设图像中只有一张脸,因此提取具有最高置信度的检测并检查以确保置信度满足用于过滤弱检测的最小概率阈值。

假设已经达到了这个阈值,提取面部 ROI 并抓取/检查尺寸以确保面部 ROI 足够大。

然后,我们将利用编码器 并提取人脸编码。

继续构建另一个 blob。

随后,将 faceBlob 通过编码器 。 这会生成一个 128 维向量 (vec) 来描述面部。

然后我们简单地将名称和嵌入 vec 分别添加到 knownNames 和 knownEmbeddings 中。

继续循环图像、检测人脸并为数据集中的每个图像提取人脸编码的过程。

循环结束后剩下的就是将数据转储到磁盘。

运行结果:

loading face detector…
loading face recognizer…
quantifying faces…
processing image 1/19
processing image 2/19
processing image 3/19
processing image 4/19
processing image 5/19
processing image 6/19
processing image 7/19
processing image 8/19
processing image 9/19
processing image 10/19
processing image 11/19
processing image 12/19
processing image 13/19
processing image 14/19
processing image 15/19
processing image 16/19
processing image 17/19
processing image 18/19
processing image 19/19
serializing 19 encodings…

Process finished with exit code 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
训练人脸识别模型
已经为每张脸提取了 128 维编码——但是我们如何根据这些嵌入来识别一个人呢?

答案是我们需要在嵌入之上训练一个“标准”机器学习模型(例如 SVM、k-NN 分类器、随机森林等)。

今天我们使用SVM实现

打开 train_face.py 文件并插入以下代码:

from sklearn.preprocessing import LabelEncoder
from sklearn.svm import SVC
import pickle

embeddings_path=’output/embeddings.pickle’
recognizer_path=’output/recognizer.pickle’
lable_path=’output/le.pickle’
# 加载编码模型
print(“[INFO] loading face embeddings…”)
data = pickle.loads(open(embeddings_path, “rb”).read())

# 给label编码
print(“[INFO] encoding labels…”)
le = LabelEncoder()
labels = le.fit_transform(data[“names”])
# 训练用于接受人脸 128-d 嵌入的模型,然后产生实际的人脸识别
recognizer = SVC(C=1.0, kernel=”linear”, probability=True)
recognizer.fit(data[“embeddings”], labels)
# 保存模型
f = open(recognizer_path, “wb”)
f.write(pickle.dumps(recognizer))
f.close()
# 保存lable
f = open(lable_path, “wb”)
f.write(pickle.dumps(le))
f.close()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
导入包和模块。 我们将使用 scikit-learn 的支持向量机 (SVM) 实现,这是一种常见的机器学习模型。

定义变量。

embeddings_path:序列化编码。

recognizer_path:这将是我们识别人脸的输出模型。 它基于 SVM。

lable_path:标签编码器输出文件路径

加载编码。

然后初始化 scikit-learn LabelEncoder 并编码名称标签。

训练模型。本文使用的是线性支持向量机 (SVM),但如果您愿意,您可以尝试使用其他机器学习模型进行试验。

训练模型后,我们将模型和标签编码器保存到电脑上。

运行train_face.py 脚本。

识别图像中的人脸
新建脚本文件recognize_face.py,插入一下代码:

import numpy as np
import pickle
import cv2
import os
1
2
3
4
导入包,然后我们需要新增一个resize方法。

def resize(image, width=None, height=None, inter=cv2.INTER_AREA):
dim = None
(h, w) = image.shape[:2]
# 如果高和宽为None则直接返回
if width is None and height is None:
return image
# 检查宽是否是None
if width is None:
# 计算高度的比例并并按照比例计算宽度
r = height / float(h)
dim = (int(w * r), height)
# 高为None
else:
# 计算宽度比例,并计算高度
r = width / float(w)
dim = (width, int(h * r))
resized = cv2.resize(image, dim, interpolation=inter)
# return the resized image
return resized
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
等比例resize图像,定义变量:

image_path = ’11.jpg’
detector_path = ‘face_dete_model’
embedding_path = ‘nn4.small2.v1.t7’
recognizer_path = ‘output/recognizer.pickle’
label_path = ‘output/le.pickle’
confidence_low = 0.5
1
2
3
4
5
6
这六个变量的含义如下:

image_path :输入图像的路径。

detector_path:OpenCV 深度学习人脸检测器的路径。 使用这个模型来检测人脸 ROI 在图像中的位置。

embedding_path : OpenCV 深度学习人脸编码模型的路径。 我们将使用这个模型从人脸 ROI 中提取 128 维人脸嵌入——然后将把数据输入到识别器中。

recognizer_path :识别器模型的路径。

label_path : 标签编码器的路径。

confidence_low:过滤弱人脸检测的可选阈值。

接下来是代码的主体部分:

# 加载序列化人脸检测器
print(“[INFO] loading face detector…”)
protoPath = os.path.sep.join([detector_path, “deploy.proto.txt”])
modelPath = os.path.sep.join([detector_path,”res10_300x300_ssd_iter_140000_fp16.caffemodel”])
detector = cv2.dnn.readNetFromCaffe(protoPath, modelPath)
# 加载我们序列化的人脸编码模型
print(“[INFO] loading face recognizer…”)
embedder = cv2.dnn.readNetFromTorch(embedding_path)
# 加载实际的人脸识别模型和标签编码器
recognizer = pickle.loads(open(recognizer_path, “rb”).read())
le = pickle.loads(open(label_path, “rb”).read())
# 加载图像,将其调整为宽度为 600 像素(同时保持纵横比),然后抓取图像尺寸
image = cv2.imread(image_path)
image = resize(image, width=600)
(h, w) = image.shape[:2]
# 从图像构建一个 blob
imageBlob = cv2.dnn.blobFromImage(
cv2.resize(image, (300, 300)), 1.0, (300, 300),
(104.0, 177.0, 123.0), swapRB=False, crop=False)

# 应用 OpenCV 的基于深度学习的人脸检测器来定位输入图像中的人脸
detector.setInput(imageBlob)
detections = detector.forward()

# loop over the detections
for i in range(0, detections.shape[2]):
# 提取与预测相关的置信度(即概率)
confidence = detections[0, 0, i, 2]
# filter out weak detections
if confidence > confidence_low:
# 计算人脸边界框的 (x, y) 坐标
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype(“int”)
# 提取人脸ROI
face = image[startY:endY, startX:endX]
(fH, fW) = face.shape[:2]
# 确保人脸宽度和高度足够大
if fW < 20 or fH < 20:
continue

# 为人脸 ROI 构造一个 blob,然后将 blob 通过我们的人脸嵌入模型来获得人脸的 128-d 量化
faceBlob = cv2.dnn.blobFromImage(face, 1.0 / 255, (96, 96),
(0, 0, 0), swapRB=True, crop=False)
embedder.setInput(faceBlob)
vec = embedder.forward()
# 执行分类以识别人脸
preds = recognizer.predict_proba(vec)[0]
j = np.argmax(preds)
proba = preds[j]
name = le.classes_[j]
# 绘制人脸的边界框以及相关的概率
text = “{}: {:.2f}%”.format(name, proba * 100)
y = startY – 10 if startY – 10 > 10 else startY + 10
cv2.rectangle(image, (startX, startY), (endX, endY),
(0, 0, 255), 2)
cv2.putText(image, text, (startX, y),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)

# 展示结果
cv2.imshow(“Image”, image)
cv2.waitKey(0)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
我们在这个块中加载三个模型。 冒着冗余的风险,我想明确提醒您模型之间的差异:

检测器:一个预训练的 Caffe DL 模型,用于检测人脸在图像中的位置。

embedder:一个预训练的 Torch DL 模型,用于计算我们的 128-D 人脸嵌入。

识别器:线性 SVM 人脸识别模型。
1 和 2 都是预先训练好的,这意味着它们是由 OpenCV 按原样提供给您的

加载标签编码器,其中包含我们的模型可以识别的人的姓名。

将图像加载到内存中并构建一个 blob。

通过我们的检测器定位图像中的人脸。

您将从步骤 1 中识别出此块。 我在这里再解释一遍:

遍历检测并提取每个检测的置信度。

然后将置信度与命令行 最小概率检测阈值进行比较,确保计算出的概率大于最小概率。

我们提取人脸 ROI并确保它的空间维度足够大。
下面是识别人脸 ROI代码:

首先,构建一个 faceBlob)并将其通过编码器以生成描述面部的 128 维向量

然后,我们将 vec 通过我们的 SVM 识别器模型,其结果是我们对面部 ROI 中的人的预测。

我们取最高概率指数并查询我们的标签编码器以找到名称。

循环中识别每一张脸(包括“未知”)人:

在构造了一个包含名称和概率的文本字符串。

然后在脸部周围绘制一个矩形并将文本放在框上方。

最后我们在屏幕上可视化结果,直到按下某个键。

可以看出使用机器学习的方式准确率还是比较低的,但是优点是速度快。

摄像头识别人脸
这里我用视频代替,代码和图像中识别人脸的步骤一致,直接上代码。

新建recognize_video.py脚本,插入一下代码:

import numpy as np
import pickle
import time
import cv2
import os

def resize(image, width=None, height=None, inter=cv2.INTER_AREA):
dim = None
(h, w) = image.shape[:2]
# 如果高和宽为None则直接返回
if width is None and height is None:
return image
# 检查宽是否是None
if width is None:
# 计算高度的比例并并按照比例计算宽度
r = height / float(h)
dim = (int(w * r), height)
# 高为None
else:
# 计算宽度比例,并计算高度
r = width / float(w)
dim = (width, int(h * r))
resized = cv2.resize(image, dim, interpolation=inter)
# return the resized image
return resized

out_put=’output.avi’
video_path = ‘1.mp4’
detector_path = ‘face_dete_model’
embedding_path = ‘nn4.small2.v1.t7’
recognizer_path = ‘output/recognizer.pickle’
label_path = ‘output/le.pickle’
confidence_low = 0.5
# load our serialized face detector from disk
print(“[INFO] loading face detector…”)
protoPath = os.path.sep.join([detector_path, “deploy.proto.txt”])
modelPath = os.path.sep.join([detector_path,”res10_300x300_ssd_iter_140000_fp16.caffemodel”])
detector = cv2.dnn.readNetFromCaffe(protoPath, modelPath)

# load our serialized face embedding model from disk
print(“[INFO] loading face recognizer…”)
embedder = cv2.dnn.readNetFromTorch(embedding_path)

# load the actual face recognition model along with the label encoder
recognizer = pickle.loads(open(recognizer_path, “rb”).read())
le = pickle.loads(open(label_path, “rb”).read())

# initialize the video stream, then allow the camera sensor to warm up
print(“[INFO] starting video stream…”)
#vs = cv2.VideoCapture(0) #摄像头
vs=cv2.VideoCapture(video_path)# 视频
time.sleep(2.0)

# start the FPS throughput estimator

writer=None
# loop over frames from the video file stream
while True:
# grab the frame from the threaded video stream
ret_val, frame = vs.read()

if ret_val is False:
break
# resize the frame to have a width of 600 pixels (while
# maintaining the aspect ratio), and then grab the image
# dimensions
frame = resize(frame, width=600)
(h, w) = frame.shape[:2]

# construct a blob from the image
imageBlob = cv2.dnn.blobFromImage(
cv2.resize(frame, (300, 300)), 1.0, (300, 300),
(104.0, 177.0, 123.0), swapRB=False, crop=False)

# apply OpenCV’s deep learning-based face detector to localize
# faces in the input image
detector.setInput(imageBlob)
detections = detector.forward()

# loop over the detections
for i in range(0, detections.shape[2]):
# extract the confidence (i.e., probability) associated with
# the prediction
confidence = detections[0, 0, i, 2]

# filter out weak detections
if confidence >confidence_low:
# compute the (x, y)-coordinates of the bounding box for
# the face
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype(“int”)
# extract the face ROI
face = frame[startY:endY, startX:endX]
(fH, fW) = face.shape[:2]

# ensure the face width and height are sufficiently large
if fW < 20 or fH < 20:
continue

# construct a blob for the face ROI, then pass the blob
# through our face embedding model to obtain the 128-d
# quantification of the face
faceBlob = cv2.dnn.blobFromImage(face, 1.0 / 255,
(96, 96), (0, 0, 0), swapRB=True, crop=False)
embedder.setInput(faceBlob)
vec = embedder.forward()

# perform classification to recognize the face
preds = recognizer.predict_proba(vec)[0]
j = np.argmax(preds)
proba = preds[j]
name = le.classes_[j]

# draw the bounding box of the face along with the
# associated probability
text = “{}: {:.2f}%”.format(name, proba * 100)
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)

if writer is None and out_put is not None:
fourcc = cv2.VideoWriter_fourcc(*”MJPG”)
writer = cv2.VideoWriter(out_put, fourcc, 20,
(frame.shape[1], frame.shape[0]), True)
# 如果 writer 不是 None,则将识别出人脸的帧写入磁盘
if writer is not None:
writer.write(frame)
# 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

# do a bit of cleanup
cv2.destroyAllWindows()
vs.release()
if writer is not None:
writer.release()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
运行结果:

完整的代码:
https://download.csdn.net/download/hhhhhhhhhhwwwwwwwwww/64761335
————————————————
版权声明:本文为CSDN博主「AI浩」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/hhhhhhhhhhwwwwwwwwww/article/details/121973738

收藏 (0) 打赏

感谢您的支持,我们会继续努力的!

打开支付宝/微信/QQ扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

1. 本站所有教学内容和资源均来源于本站原创和网络收集以及用户自主上传,如有侵权请带证联系本站客服进行处理!邮箱:team@lcwl.fun
2. 对于非本站原创的资源不保证所提供下载资源的准确性、安全性和完整性,资源仅供下载学习之用!如有链接无法下载、失效或广告,请联系本站客服处理,有奖励!
3. 除本站原创教学或资源外其余资源您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容资源!如用于商业或者非法用途,与本站无关,一切后果请用户自负!
4. 本站原创资源如需商用还请申请商业授权,否则本站有权追究其法律责任!
5. 如果您也有好的资源或教程,您可以投稿发布,成功分享后有学币奖励额外收入!

凌晨资源网 技术新知 人脸识别实战:使用Opencv+SVM实现人脸识别 https://www.lingchenw.cn/868.html

常见问题
  • 本站所有付费教程均可单独付费或者开会员学习,自己购买或者开了会员就可以学习,来凌晨学院报名学习送会员,并且有讲师一对一辅导培训教学,师生互动化,定期布置作业等
查看详情
  • 本站所有资源版权均属于原作者所有,资源中标注可商用的可以商用的代表是本团队自主研发公布可商用的产品,未标注可商用所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。
查看详情

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务

学习手机编程软件开发
手机编程软件开发

你知道吗?用手机也能开发制作软件,满足自己的编程心,做属于自己的软件

报名学习
自媒体短视频
副业做自媒体短视频

想做自媒体短视频剪辑给自己多一份副业,只需一部手机你也可以

报名学习
搭建网站必备云互联主机
链未云互联

搭建网站,后台云服务等必备云服务器互联主机,IDC云主机

现在使用
Fa快捷助手
用手点一点就能开发做软件

不用记编程语法,不用一行一行手敲代码,用手点一点就能开发制作软件

点击下载