人脸识别《二、 基于Dlib库实现人脸检测、特征点检测、人脸对齐、人脸识别》

  首先需要安装dlib库以及opencv,上一节已经说明如何安装dlib,这边需要再安装一下opencv

pip install numpy 

  由于我安装的python版本是3.6,直接使用pip install opencv-python安装会报错。

pip install -i https://pypi.douban.com/simple/ pip install opencv-python==4.3.0.38

  以下demo是基于shape_predictor_68_face_landmarks.dat的模型进行推理的。该模型在上一节有下载地址。

1.人脸检测

# encoding:utf-8

import dlib
import numpy as np
import cv2

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():
    image_file = "test.jpg"
    detector = dlib.get_frontal_face_detector()
    image = cv2.imread(image_file)
    image = resize(image, width=1200)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    rects = detector(gray, 1)
    for (i, rect) in enumerate(rects):
        (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)

    cv2.imshow("Output", image)
    cv2.waitKey(0)

if __name__ == "__main__":

    detect()

结果:

 

2.特征点检测

# encoding:utf-8

import dlib
import numpy as np
import cv2

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, dtype="int"): # 将包含68个特征的的shape转换为numpy array格式
    coords = np.zeros((68, 2), dtype=dtype)
    for i in range(0, 68):
        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():
    image_file = "test.jpg"
    detector = dlib.get_frontal_face_detector()
    predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
    image = cv2.imread(image_file)
    image = resize(image, width=1200)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    rects = detector(gray, 1)
    shapes = []
    for (i, rect) in enumerate(rects):
        shape = predictor(gray, rect)
        shape = shape_to_np(shape)
        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)

    for shape in shapes:
        for (x, y) in shape:
            cv2.circle(image, (x, y), 2, (0, 0, 255), -1)
    cv2.imshow("Output", image)
    cv2.waitKey(0)

if __name__ == "__main__":

    feature()

结果:

 

3. 人脸对齐

执行:

pip install matplotlib

代码:

# encoding:utf-8

import dlib
import cv2
import matplotlib.pyplot as plt
import numpy as np
import math

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 face_alignment(faces):

    predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat") # 用来预测关键点
    faces_aligned = []
    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 demo():

    im_raw = cv2.imread('test.jpg').astype('uint8')

    detector = dlib.get_frontal_face_detector()
    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)
        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)

    faces_aligned = face_alignment(src_faces)

    cv2.imshow("src", im_raw)
    i = 0
    for face in faces_aligned:
        cv2.imshow("det_{}".format(i), face)
        i = i + 1
    cv2.waitKey(0)

if __name__ == "__main__":

    demo()

 

结果:

 

4. 人脸识别

问题:

ModuleNotFoundError: No module named 'skimage'

解决:

pip install scikit-image

 

代码:

# encoding:utf-8

import dlib
import cv2
import matplotlib.pyplot as plt
import numpy as np
import math
import os, glob
from skimage import io

def create_face_space():

    # 对文件夹下的每一个人脸进行:
    # 1.人脸检测
    # 2.关键点检测
    # 3.描述子提取

    # 候选人脸文件夹
    faces_folder_path = "candidate-faces/"
    # 候选人脸描述子list
    descriptors = []
    for f in glob.glob(os.path.join(faces_folder_path, "*.jpeg")):
        print("Processing file: {}".format(f))
        img = io.imread(f)

        # 1.人脸检测
        dets = detector(img, 1)
        print("Number of faces detected: {}".format(len(dets)))

        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)

    return descriptors


def predict(descriptors,path):
    # 对需识别人脸进行同样处理
    # 提取描述子

    img = io.imread(path)
    dets = detector(img, 1)

    dist = []
    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_)
    return dist

def demo():
    global detector, sp, facerec
    # 加载正脸检测器
    detector = dlib.get_frontal_face_detector()

    # 加载人脸关键点检测器
    sp = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

    # 3. 加载人脸识别模型
    facerec = dlib.face_recognition_model_v1("dlib_face_recognition_resnet_model_v1.dat")

    descriptors = create_face_space()
    # 候选人名单
    candidate = ['zhaoliying', 'liuyifei',
                 'liushishi', 'tangyan',
                 'tongliya', 'yangzi']

    predict_path = "test--faces/"
    for f in glob.glob(os.path.join(predict_path, "*.jpeg")):
        dist = predict(descriptors, f)
        # 候选人和距离组成一个dict
        c_d = dict(zip(candidate, dist))

        cd_sorted = sorted(c_d.items(), key=lambda d:d[1])
        print ("The person_{} is: ".format(f),cd_sorted[0][0])

if __name__ == "__main__":

    demo()

  在candidate-faces/文件夹中放6个明星的照片,格式要转换成jpg,不能直接改后缀名,不然会报错。

  在test--faces/放入待检测的图片

 

posted @ 2023-04-27 15:42  一个不知道干嘛的小萌新  阅读(51)  评论(0编辑  收藏  举报