重磅!!!!代码来了~~~~

连续更新的第二篇,这边是上一篇的续集,在这里我已经假设你已经完成了,上一篇的环境安装的工作,今天我们就来手撕代码,注入灵魂。今天正式就进入代码篇了。我局的我已经把代码掰开揉碎了来讲了,大家肯定看的明白。

所以先不啰嗦,直接先把代码提贴出来,一共两个脚本,一个是收集人脸特征的代码,一个是判断人脸相似度的代码。在这之前还是先贴出一张检测后的图片,目的是为了吸引观众朋友们。

pytorch行人重识别跨摄像头 pytorch人脸检测_opencv

1.收集人脸特征的代码

import cv2
import dlib
import os
import numpy as np

def drawrec_drawdot(shape,image):
    landmarks = shape.parts()
    landmarks = np.matrix([[p.x, p.y] for p in landmarks])
    #画图
    for idx, point in enumerate(landmarks):
        # 68点的坐标
        pos = (point[0, 0], point[0, 1])
        # 利用cv2.circle给每个特征点画一个圈,共68个
        cv2.circle(image, pos, 2, color=(0, 255, 0), thickness=3)
        # 利用cv2.putText输出1-68
        font = cv2.FONT_HERSHEY_SIMPLEX
        cv2.putText(image, str(idx + 1), None, font, 0.8, (0, 0, 255), 1, cv2.LINE_AA)

    return image


if __name__ == '__main__':
    #定义图片文件夹路径
    folder_path = r'D:\DATAS\manhua\manhua_tou'
    upper_path = '\\'.join(folder_path.split('\\')[:-1])
    numpy_data_save_folder = os.path.join(upper_path,'TENSOR')
    output_image_folder = os.path.join(upper_path,'OUTPUT')
    if not os.path.exists(numpy_data_save_folder):
        os.makedirs(numpy_data_save_folder)
    if not os.path.exists(output_image_folder):
        os.makedirs(output_image_folder)
    #定义定位人脸的定位器
    detector = dlib.get_frontal_face_detector()
    #定义检测人脸特征点的检测器
    predictor = dlib.shape_predictor("./shape_predictor_68_face_landmarks.dat")
    feature_value_detctor = dlib.face_recognition_model_v1('./dlib_face_recognition_resnet_model_v1.dat')

    for i in os.listdir(folder_path):
        for j in os.listdir(os.path.join(folder_path, i)):
            # 图片路径
            image_path = os.path.join(folder_path, i, j)
            image = cv2.imread(image_path)

            # 获取人脸坐标
            locations = detector(image)
            if len(locations) != 0:
                for location in locations:
                    #获取64个特征点
                    shape_64 = predictor(image,location)
                    #将64个特征点转变成128维的向量
                    face_descriptor = feature_value_detctor.compute_face_descriptor(image, shape_64)
                    value_128 = np.array(face_descriptor)
                    # print(value_128)
                    np.save(numpy_data_save_folder + '/' + image_path.split('\\')[-1].split('.')[0],value_128)
                    # 画人脸位置和64个特征点
                    draw_image = drawrec_drawdot(shape_64,image)
                    # 保存图像
                    cv2.imwrite(os.path.join(output_image_folder,j),draw_image)

从主函数看起:

1.1定义图片文件和创建两个必要的文件夹

if __name__ == '__main__':
    #定义图片文件夹路径
    folder_path = r'D:\DATAS\manhua\manhua_tou'
    upper_path = '\\'.join(folder_path.split('\\')[:-1])
    numpy_data_save_folder = os.path.join(upper_path,'TENSOR')
    output_image_folder = os.path.join(upper_path,'OUTPUT')
    if not os.path.exists(numpy_data_save_folder):
        os.makedirs(numpy_data_save_folder)
    if not os.path.exists(output_image_folder):
        os.makedirs(output_image_folder)

首先我定义了一个文件夹路径 folder_path,它是图片所在的文件夹,这个文件下,是这样的

pytorch行人重识别跨摄像头 pytorch人脸检测_opencv_02

以人的名称直接来命名,因为我的数据集只有pangpang和shouhsou,所以只有两个子文件夹,还是给大家看看里面吧,哈哈,别羡慕,题外话了,哈哈。

pytorch行人重识别跨摄像头 pytorch人脸检测_opencv_03

pytorch行人重识别跨摄像头 pytorch人脸检测_人工智能_04

里面的图片最好也以人的名称命名,方便以后操作

好了,好了,说回代码

然后我又定义了一个numpy_data_save_folder 和 output_image_folder,然后创建了这个两个文件夹,以便后面程序往这两个文件中生成文件。

1.2定义人脸定位器和检测器

#定义定位人脸的定位器
    detector = dlib.get_frontal_face_detector()
    #定义检测人脸特征点的检测器
    predictor = dlib.shape_predictor("./shape_predictor_68_face_landmarks.dat")
    feature_value_detctor = dlib.face_recognition_model_v1('./dlib_face_recognition_resnet_model_v1.dat')

这个你就看到了,昨天我的那篇文章让你配置环境的重要性了吧,我在这里再提供一下,下载路径

够意思了吧。

简单说一下,detector 是用于定位人脸位置的,predictor是用于检测人脸的64个特征点的,feature_value_detctors是用于将64个特征点转变成128维向量的工具

1.3遍历读图,进行检测,存储人脸128维特征向量和检测图

for i in os.listdir(folder_path):
        for j in os.listdir(os.path.join(folder_path, i)):
            # 图片路径
            image_path = os.path.join(folder_path, i, j)
            image = cv2.imread(image_path)

            # 获取人脸坐标
            locations = detector(image)
            if len(locations) != 0:
                for location in locations:
                    #获取64个特征点
                    shape_64 = predictor(image,location)
                    #将64个特征点转变成128维的向量
                    face_descriptor = feature_value_detctor.compute_face_descriptor(image, shape_64)
                    value_128 = np.array(face_descriptor)
                    # print(value_128)
                    np.save(numpy_data_save_folder + '/' + image_path.split('\\')[-1].split('.')[0],value_128)
                    # 画人脸位置和64个特征点
                    draw_image = drawrec_drawdot(shape_64,image)
                    # 保存图像
                    cv2.imwrite(os.path.join(output_image_folder,j),draw_image)

先利用os库来找到图片的路径,然后读图,这两步都没问题吧,默认没问题

locations = detector(image)

这一行代码,就是在定位图片中人脸的位置了,图片上有几个人,会定位到几个,所以你看我命名的时候用用的locations,有一个‘s’,表示多个,哈哈,严谨!

shape_64 = predictor(image,location)

这一行代码就是提取人脸的64个特征点了,文章最开头的那张美女图上的那些绿点就是画上去的特征点,不是麻子,应该没问题吧

face_descriptor = feature_value_detctor.compute_face_descriptor(image, shape_64)

这一行代码就是把64个特征点变成128维的向量,我们来看看这个128维向量长什么样子吧

pytorch行人重识别跨摄像头 pytorch人脸检测_opencv_05

这绝对是128个数,不信你数一数。

np.save(numpy_data_save_folder + '/' + image_path.split('\\')[-1].split('.')[0],value_128)
# 画人脸位置和64个特征点
draw_image = drawrec_drawdot(shape_64,image)
# 保存图像
cv2.imwrite(os.path.join(output_image_folder,j),draw_image)

这个时候1.1里面个建立的两个文件夹就派上用场了,他们一个用来存储128维度的数据,一个用来保存生成后的图,运行脚本完成后,如下

pytorch行人重识别跨摄像头 pytorch人脸检测_深度学习_06

看看里面

pytorch行人重识别跨摄像头 pytorch人脸检测_深度学习_07

pytorch行人重识别跨摄像头 pytorch人脸检测_人工智能_08

 这个npy文件存储的numpy格式的数据

好了,收集人脸特征到这里就结束了,大家一起来试一试吧。

2.判断人脸相似度

老规矩,先上代码

import cv2
import dlib
import os
import numpy as np


def load_tensor(tensor_folder):
    feature_list = []  # 用于存放人物128维特征值列表
    class_name = []  # 用于存放类别信息
    for i in os.listdir(tensor_folder):
        tensor_path = os.path.join(tensor_folder,i)
        tensor = np.load(tensor_path)

        feature_list.append(tensor)
        class_name.append(tensor_path.split('\\')[-1].split('.')[0])

    return feature_list,class_name

if __name__ == '__main__':
    #--------------init--------------------------
    detector = dlib.get_frontal_face_detector()
    predictor = dlib.shape_predictor("./shape_predictor_68_face_landmarks.dat")
    feature_value_detctor = dlib.face_recognition_model_v1('./dlib_face_recognition_resnet_model_v1.dat')
    #-------------加载信息------------------------
    tensor_folder = r'D:\DATAS\manhua\TENSOR'
    feature_list, class_name = load_tensor(tensor_folder)
    #-------------开始测试------------------------
    test_image_path = r'D:\DATAS\test\pangpang (28).jpg'
    test_image = cv2.imread(test_image_path)
    locations = detector(test_image)

    dist = []
    for k, loc in enumerate(locations):
        shape = predictor(test_image, loc)
        face_descriptor = feature_value_detctor.compute_face_descriptor(test_image, shape)
        d_test = np.array(face_descriptor)
        for i in feature_list:                #计算距离
            distance = np.linalg.norm(i-d_test)
            dist.append(distance)

    distance_dict = dict(zip(class_name, dist))
    distance_sorted = sorted(distance_dict.items(), key=lambda x:x[1])
    print ("识别到的人物最有可能是: ",distance_sorted[0][0].split('(')[0])
    font = cv2.FONT_HERSHEY_SIMPLEX
    cv2.putText(test_image, distance_sorted[0][0].split('(')[0], (int(test_image.shape[0]//2)-50,test_image.shape[1]-50), font, 0.8, (0, 0, 255), 3, cv2.LINE_AA)
    cv2.imshow('test_image', test_image)
    cv2.waitKey()

2.1 定义人脸定位器和检测器和加载刚刚提取的人脸特征数据

if __name__ == '__main__':
    #--------------init--------------------------
    detector = dlib.get_frontal_face_detector()
    predictor = dlib.shape_predictor("./shape_predictor_68_face_landmarks.dat")
    feature_value_detctor = dlib.face_recognition_model_v1('./dlib_face_recognition_resnet_model_v1.dat')
    #-------------加载信息------------------------
    tensor_folder = r'D:\DATAS\manhua\TENSOR'
    feature_list, class_name = load_tensor(tensor_folder)

我们来看看 load_tensor 这个函数

def load_tensor(tensor_folder):
    feature_list = []  # 用于存放人物128维特征值列表
    class_name = []  # 用于存放类别信息
    for i in os.listdir(tensor_folder):
        tensor_path = os.path.join(tensor_folder,i)
        tensor = np.load(tensor_path)

        feature_list.append(tensor)
        class_name.append(tensor_path.split('\\')[-1].split('.')[0])

    return feature_list,class_name

传入的参数是 tensor_folder,这个参数就是刚刚第一个程序里创建的那个TENSOR文件夹的路径

最后返回值是,所有的128维特征的列表和特征对应的类别,也是pangpang或者shoushou。

2.2开始检测求欧氏距离

test_image_path = r'D:\DATAS\test\pangpang (28).jpg'
    test_image = cv2.imread(test_image_path)
    locations = detector(test_image)

    dist = []
    for k, loc in enumerate(locations):
        shape = predictor(test_image, loc)
        face_descriptor = feature_value_detctor.compute_face_descriptor(test_image, shape)
        d_test = np.array(face_descriptor)
        for i in feature_list:                #计算距离
            distance = np.linalg.norm(i-d_test)
            dist.append(distance)

 test_image_path 是你要用来测试的图片的路径,然后就是先得到测试图的128维度的特征向量,然后计算这个向量和你刚刚第一个程序里面保存的那些特征向量的欧式距离,np.linalg.norm 这个函数就是用来求欧式距离的,i-d_test,就是两个向量之间的差值,np.linalg.norm就是实现

pytorch行人重识别跨摄像头 pytorch人脸检测_深度学习_09

这么说吧,v1是一个128维度的向量,v2是一个128维度的向量,要求得他们的欧氏距离

此时,这里面的x1就相当于v1[0]-v2[0],这么说清晰了吧,你要是还是想不明白,你就想想初中数学,求直角坐标系中的任意两点p1,p2的距离怎么求,p1点坐标(x1,y1),拍p2点坐标(x2,y2)

pytorch行人重识别跨摄像头 pytorch人脸检测_人脸识别_10

 这样说应该清楚了吧,这样就求到了,这个测试图的128维度特征向量和之前每个128维特征向量的距离了,保存成了一个了列表dist

2.3开始求最小的距离

距离也就意味着最为相似,这样我们就认为他们是同一个人。

distance_dict = dict(zip(class_name, dist))
    distance_sorted = sorted(distance_dict.items(), key=lambda x:x[1])
    print ("识别到的人物最有可能是: ",distance_sorted[0][0].split('(')[0])
    font = cv2.FONT_HERSHEY_SIMPLEX
    cv2.putText(test_image, distance_sorted[0][0].split('(')[0], (int(test_image.shape[0]//2)-50,test_image.shape[1]-50), font, 0.8, (0, 0, 255), 3, cv2.LINE_AA)
    cv2.imshow('test_image', test_image)
    cv2.waitKey()

2.4结果展示

pytorch行人重识别跨摄像头 pytorch人脸检测_opencv_11

 到这里,基于dlib的人脸识别就此结束了,接下来我们要用手动搭建网络的网络的方式,进行深度学习训练的方式来判定人脸的类别了。敬请期待

至此,敬礼,salute!!!