Refere-se principalmente a dois artigos:
https://blog.csdn.net/liuxiao214/article/details/83411820
https://www.jianshu.com/p/577af31ced74
0. Meio Ambiente
windows
python3.6
Dlib
numpy==1.14.5
glob
opencv-python==3.4.3.18
Instale a referência Dlib: https://blog.csdn.net/qq_35975447/article/details/109802787
0.1 Estrutura de arquivo
│ .gitignore
│ faceAlignment.py
│ faceDetect.py
│ faceLandmarks.py
│ faceRecognition.py
│ file.txt
│
├─data
│ │ test_1988.jpg
│ │
│ ├─candidate-faces
│ │ liushishi.jpg
│ │ liuyifei.jpg
│ │ tangyan.jpg
│ │ tongliya.jpg
│ │ yangzi.jpg
│ │ zhaoliying.jpg
│ │
│ └─faces
│ tangyan.jpg
│ zhaoliying.jpg
│
├─models
│ dlib_face_recognition_resnet_model_v1.dat
│ mmod_human_face_detector.dat
│ shape_predictor_5_face_landmarks.dat
│ shape_predictor_68_face_landmarks.dat
│
└─results
├─alignment
│ test_1988_0_Align68.jpg
│ test_1988_1_Align68.jpg
│ test_1988_2_Align68.jpg
│ test_1988_3_Align68.jpg
│ test_1988_4_Align68.jpg
│ test_1988_5_Align68.jpg
│
├─detect
│ test_1988_HOG.jpg
│ test_1988_MMOD.jpg
│
├─landmarks
│ test_1988_5Landmarks.jpg
│ test_1988_68Landmarks.jpg
│
└─recongnition
recognition_reslut.txt
0.2 Download do modelo
https://github.com/davisking/dlib-models
0.3 meu código
https://download.csdn.net/download/qq_35975447/13129563
1. Comparação de dois métodos de detecção de rosto
Os dois métodos incluem principalmente: Dlib vem com e chama o modelo de aprendizado profundo.
1.1 Tempo
PORCO |
MMOD |
1.437422513961792s
|
106.82666826248169s |
1.2 Efeito
Imagem original:
Efeito HOG:
Efeito MMOD:
1.2 Código
O código aqui se refere principalmente ao primeiro link, e então de acordo com o método do próprio Dlib e chamando o modelo de aprendizado profundo, o tempo de teste é executado em um loop, e a imagem é salva no diretório results / detect /:
# encoding:utf-8
import dlib
import cv2
import os
import time
def rect_to_bb(rect): # 获得人脸矩形的坐标信息
x = rect.left()
y = rect.top()
w = rect.right() - x
h = rect.bottom() - y
return (x, y, w, h)
def resize(image, width=1200): # 将待检测的image进行resize
r = width * 1.0 / image.shape[1]
dim = (width, int(image.shape[0] * r))
resized = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
return resized
def detect(isHOG=False):
image_path = "./data/"
image_file = "test_1988.jpg"
startTime = time.time()
if isHOG:
detector = dlib.get_frontal_face_detector() # 基于HOG+SVM分类
else:
model_path = "./models/mmod_human_face_detector.dat" # 基于 Maximum-Margin Object Detector 的深度学习人脸检测方案
detector = dlib.cnn_face_detection_model_v1(model_path)
image = cv2.imread(image_path + image_file)
image = resize(image, width=1200)
# image = resize(image, width=600)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
rects = detector(gray, 1)
print("{} method, detect spend {}s ".format(("HOG" if isHOG else "MMOD"), time.time()-startTime))
for (i, rect) in enumerate(rects):
if isHOG:
(x, y, w, h) = rect_to_bb(rect)
else:
(x, y, w, h) = rect_to_bb(rect.rect)
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.putText(image, "Face: {}".format(i + 1), (x - 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
cv2.imshow("Output", image)
savePath = "./results/detect/"
if not os.path.exists(savePath):
os.makedirs(savePath)
if isHOG:
saveName = image_file[:-4] + "_HOG.jpg"
else:
saveName = image_file[:-4] + "_MMOD.jpg"
cv2.imwrite(savePath + saveName, image)
cv2.waitKey(10)
if __name__ == "__main__":
isHOG = True
detect(isHOG)
if isHOG:
isHOG = not isHOG
detect(isHOG)
2. Duas comparações de detecção de pontos-chave de rosto
Os dois tipos principais incluem: 5 pontos-chave e 68 pontos-chave. Ambos precisam ligar para o modelo.
2.1 Tempo
68 Marcos |
5 Marcos |
0.011994600296020508s |
0,0030002593994140625s |
2.2 Efeito de desempenho
5 marcos
68 marcos
2.3 Código
O código aqui se refere principalmente ao primeiro link, executa os dois métodos respectivamente e, em seguida, salva os resultados em ./results/landmarks/:
# encoding:utf-8
import dlib
import numpy as np
import cv2
import os
import time
def rect_to_bb(rect): # 获得人脸矩形的坐标信息
x = rect.left()
y = rect.top()
w = rect.right() - x
h = rect.bottom() - y
return (x, y, w, h)
def shape_to_np(shape, is68Landmarks=True, dtype="int"): # 将包含68个特征的的shape转换为numpy array格式
if is68Landmarks:
landmarkNum = 68
else:
landmarkNum = 5
coords = np.zeros((landmarkNum, 2), dtype=dtype)
for i in range(0, landmarkNum):
coords[i] = (shape.part(i).x, shape.part(i).y)
return coords
def resize(image, width=1200): # 将待检测的image进行resize
r = width * 1.0 / image.shape[1]
dim = (width, int(image.shape[0] * r))
resized = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
return resized
def feature(is68Landmarks=True):
image_path = "./data/"
image_file = "test_1988.jpg"
detector = dlib.get_frontal_face_detector()
if is68Landmarks:
predictor = dlib.shape_predictor("./models/shape_predictor_68_face_landmarks.dat")
else:
predictor = dlib.shape_predictor("./models/shape_predictor_5_face_landmarks.dat")
image = cv2.imread(image_path + image_file)
image = resize(image, width=1200)# 1200
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
rects = detector(gray, 1)
shapes = []
startTime = time.time()
for (i, rect) in enumerate(rects):
shape = predictor(gray, rect)
shape = shape_to_np(shape, is68Landmarks)
shapes.append(shape)
(x, y, w, h) = rect_to_bb(rect)
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.putText(image, "Face: {}".format(i + 1), (x - 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
print("{} method, detect spend {}s ".format(("68Landmarks" if is68Landmarks else "5Landmarks"), time.time()-startTime))
for shape in shapes:
for (x, y) in shape:
cv2.circle(image, (x, y), 2, (0, 0, 255), -1)
cv2.imshow("Output", image)
savePath = "./results/landmarks/"
if not os.path.exists(savePath):
os.makedirs(savePath)
if is68Landmarks:
saveName = image_file[:-4] + "_68Landmarks.jpg"
else:
saveName = image_file[:-4] + "_5Landmarks.jpg"
cv2.imwrite(savePath + saveName, image)
cv2.waitKey(10)
if __name__ == "__main__":
is68Landmarks = True
feature(is68Landmarks)
if is68Landmarks:
is68Landmarks = not is68Landmarks
feature(is68Landmarks)
3. Alinhamento da face
Tive que testar os dois métodos aqui, mas os 5 pontos principais não pareciam ser fáceis de alterar, então desisti, mas o código de referência ainda está nele e você pode excluí-lo você mesmo.
3.1 Tempo
Alinhamento |
0.04295229911804199s |
3.2 Efeito
Como a imagem é muito vaga, escolha algumas:
3.3 Código
Os pontos-chave aqui são baseados em:
Os resultados serão salvos em ./results/alignment/:
# encoding:utf-8
import dlib
import cv2
import numpy as np
import math
import os
import time
def rect_to_bb(rect): # 获得人脸矩形的坐标信息
x = rect.left()
y = rect.top()
w = rect.right() - x
h = rect.bottom() - y
return (x, y, w, h)
def resize(image, width=1200): # 将待检测的image进行resize
r = width * 1.0 / image.shape[1]
dim = (width, int(image.shape[0] * r))
resized = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
return resized
def face_alignment_68(faces):
# 使用68点关键点模型,根据关键点信息求解变换矩阵,然后把变换矩阵应用到整个图像上。
predictor = dlib.shape_predictor("./models/shape_predictor_68_face_landmarks.dat") # 用来预测关键点
faces_aligned = []
global startTime
startTime = time.time()
for face in faces:
rec = dlib.rectangle(0,0,face.shape[0],face.shape[1])
shape = predictor(np.uint8(face),rec) # 注意输入的必须是uint8类型
order = [36,45,30,48,54] # left eye, right eye, nose, left mouth, right mouth 注意关键点的顺序,这个在网上可以找
for j in order:
x = shape.part(j).x
y = shape.part(j).y
cv2.circle(face, (x, y), 2, (0, 0, 255), -1)
eye_center =((shape.part(36).x + shape.part(45).x) * 1./2, # 计算两眼的中心坐标
(shape.part(36).y + shape.part(45).y) * 1./2)
dx = (shape.part(45).x - shape.part(36).x) # note: right - right
dy = (shape.part(45).y - shape.part(36).y)
angle = math.atan2(dy,dx) * 180. / math.pi # 计算角度
RotateMatrix = cv2.getRotationMatrix2D(eye_center, angle, scale=1) # 计算仿射矩阵
RotImg = cv2.warpAffine(face, RotateMatrix, (face.shape[0], face.shape[1])) # 进行仿射变换,即旋转
faces_aligned.append(RotImg)
return faces_aligned
def face_alignment_5(rgb_img, faces):
startTime = time.time()
faces_aligned = []
for face in faces:
# RotImg = dlib.get_face_chip(rgb_img, face)
RotImg = dlib.get_face_chip(np.uint8(rgb_img), np.uint8(face))
# RotImg = dlib.get_face_chip(rgb_img, face, size=224, padding=0.25)
faces_aligned.append(RotImg)
return faces_aligned
def demo(isAlignment_5=True):
image_path = "./data/"
image_file = "test_1988.jpg"
im_raw = cv2.imread(image_path + image_file).astype('uint8')
# detector = dlib.get_frontal_face_detector()
model_path = "./models/mmod_human_face_detector.dat" # 基于 Maximum-Margin Object Detector 的深度学习人脸检测方案
detector = dlib.cnn_face_detection_model_v1(model_path)
im_raw = resize(im_raw, width=1200)
gray = cv2.cvtColor(im_raw, cv2.COLOR_BGR2GRAY)
rects = detector(gray, 1)
src_faces = []
for (i, rect) in enumerate(rects):
(x, y, w, h) = rect_to_bb(rect.rect)
detect_face = im_raw[y:y+h,x:x+w]
src_faces.append(detect_face)
cv2.rectangle(im_raw, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.putText(im_raw, "Face: {}".format(i + 1), (x - 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
if isAlignment_5:
faces_aligned = face_alignment_5(im_raw, src_faces)
else:
faces_aligned = face_alignment_68(src_faces)
print("{} method, detect spend {}s ".format(("Alignment_5" if isAlignment_5 else "Alignment_68"), time.time()-startTime))
cv2.imshow("src", im_raw)
savePath = "./results/alignment/"
if not os.path.exists(savePath):
os.makedirs(savePath)
if isAlignment_5:
saveName = "_Align5.jpg"
else:
saveName = "_Align68.jpg"
i = 0
for face in faces_aligned:
cv2.imshow("det_{}".format(i), face)
cv2.imwrite(savePath + image_file[:-4] + "_{}".format(i) + saveName, face)
i = i + 1
cv2.waitKey(10)
if __name__ == "__main__":
isAlignment_5 = False
demo(isAlignment_5)
if isAlignment_5:
isAlignment_5 = not isAlignment_5
demo(isAlignment_5)
4. Reconhecimento facial
Esse lugar gasta muito tempo, principalmente quando o reconhecimento não é bom, não me afundou em analisar o código, aqui está modificado de acordo com o código da referência um, não há necessidade de definir manualmente a lista de candidatos, só precisamos para definirmos nós mesmos as faces do candidato A biblioteca candidata na pasta tem o nome da pessoa que pode ser distinguida.
4.1 Processo de preparação
(1) Rostos de candidatos no banco de dados de candidatos, vamos a esse banco de dados para consultar quais são conhecidos e têm a identidade correta.
(2) Nomenclatura das fotos dos rostos dos candidatos:
(3) Rostos a serem questionados:
(4) Resultados
Processing file: ./data/candidate-faces\liushishi.jpg
Number of faces detected: 1
Processing file: ./data/candidate-faces\liuyifei.jpg
Number of faces detected: 1
Processing file: ./data/candidate-faces\tangyan.jpg
Number of faces detected: 1
Processing file: ./data/candidate-faces\tongliya.jpg
Number of faces detected: 1
Processing file: ./data/candidate-faces\yangzi.jpg
Number of faces detected: 1
Processing file: ./data/candidate-faces\zhaoliying.jpg
Number of faces detected: 1
c_d :[('tangyan', 0.45614611065543303), ('liushishi', 0.4777414300544273), ('yangzi', 0.520176500668875), ('tongliya', 0.547071465533885), ('zhaoliying', 0.64414064895386), ('liuyifei', 0.669962308077882)]
The person_test--./data/faces/tangyan.jpg is: tangyan
c_d :[('zhaoliying', 0.4041512584817519), ('liushishi', 0.4681194204229278), ('tangyan', 0.4728928349513442), ('yangzi', 0.47474913579746303), ('tongliya', 0.5446001882500634), ('liuyifei', 0.6104574640831666)]
The person_test--./data/faces/zhaoliying.jpg is: zhaoliying
4.2 Código
Os resultados serão salvos no arquivo ./results/recongnition/recognition_reslut.txt.
# encoding:utf-8
import dlib
import cv2
import numpy as np
import os, glob
def resize(image, width=1200): # 将待检测的image进行resize
r = width * 1.0 / image.shape[1]
dim = (width, int(image.shape[0] * r))
resized = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
return resized
def rect_to_bb(rect): # 获得人脸矩形的坐标信息
x = rect.left()
y = rect.top()
w = rect.right() - x
h = rect.bottom() - y
return (x, y, w, h)
def create_face_space():
# 对文件夹下的每一个人脸进行:
# 1.人脸检测
# 2.关键点检测
# 3.描述子提取
# 候选人脸文件夹
faces_folder_path = "./data/candidate-faces/"
# 候选人脸描述子list
descriptors = []
candidates = []
for f in glob.glob(os.path.join(faces_folder_path, "*.jpg")):
print("Processing file: {}".format(f))
img = cv2.imread(f)
# img = resize(img, width=300)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 1.人脸检测
dets = detector(img, 1)
print("Number of faces detected: {}".format(len(dets)))
candidate = f.split('\\')[-1][:-4]
for k, d in enumerate(dets):
# 2.关键点检测
shape = sp(img, d)
# 3.描述子提取,128D向量
face_descriptor = facerec.compute_face_descriptor(img, shape)
# 转换为numpy array
v = np.array(face_descriptor)
descriptors.append(v)
candidates.append(candidate)
return descriptors, candidates
def predict(descriptors, path):
# 对需识别人脸进行同样处理
# 提取描述子
img = cv2.imread(path)
# img = io.imread(path)
# img = resize(img, width=300)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
dets = detector(gray, 1)
dist = []
if len(dets) == 0:
pass
for k, d in enumerate(dets):
shape = sp(img, d)
face_descriptor = facerec.compute_face_descriptor(img, shape)
d_test = np.array(face_descriptor)
# 计算欧式距离
for i in descriptors:
dist_ = np.linalg.norm(i-d_test)
dist.append(dist_)
# print(dist)
return dist
def demo():
global detector, sp, facerec
# 加载正脸检测器
detector = dlib.get_frontal_face_detector()
# 加载人脸关键点检测器
sp = dlib.shape_predictor("./models/shape_predictor_68_face_landmarks.dat")
# 3. 加载人脸识别模型
facerec = dlib.face_recognition_model_v1("./models/dlib_face_recognition_resnet_model_v1.dat")
# 提取候选人特征与候选人名单
descriptors, candidates = create_face_space()
savePath = "./results/recongnition/"
if not os.path.exists(savePath):
os.makedirs(savePath)
fp = open(savePath + 'recognition_reslut.txt', 'a')
predict_path = "./data/faces/*.jpg"
for f in glob.glob(predict_path):
f = f.replace("\\", '/')
# print("f :{}".format(f))
dist = predict(descriptors, f)
# 候选人和距离组成一个dict
c_d = dict(zip(candidates, dist))
if not c_d:
print(str(c_d) + " is None")
continue
cd_sorted = sorted(c_d.items(), key=lambda d:d[1])
print("c_d :{}".format(cd_sorted))
print("The person_test--{} is: ".format(f), cd_sorted[0][0])
fp.write("\nThe person_test--{} is: with similar : {}".format(f, cd_sorted[0][0]))
fp.close()
if __name__ == "__main__":
demo()
referência
2. [Ferramenta] Aprendizagem da interface Dlib e introdução de funções comuns
4. Detecção de ponto-chave - legenda de 68 pontos
5. Dlib extrai pontos de características faciais (68 pontos, desenho aberto)