利用av和dlib来实现人脸识别

上一篇博客是opencv来读取视频或者照片,但是使用opencv有一个弊端,就是在centos服务器上,opencv不能读取视频,照片是可以的,如果想读取视频,需要大量的安装包来安装,很不方便,这里就使用av来代替opencv来读取视频,识别还是交给dlib来实现:

import datetime
import redis
from skimage import io
import numpy as np
import cv2
import dlib
import av
from PIL import Image



# 要读取人脸图像文件的路径 / Path of cropped faces
path_images_from_camera = "/home/image_recognition/image/"

# Dlib 正向人脸检测器 / Use frontal face detector of Dlib
detector = dlib.get_frontal_face_detector()

# Dlib 人脸 landmark 特征点检测器 / Get face landmarks
predictor = dlib.shape_predictor('/home/image_recognition/code/shape_predictor_68_face_landmarks.dat')

# Dlib Resnet 人脸识别模型,提取 128D 的特征矢量 / Use Dlib resnet50 model to get 128D face descriptor
face_reco_model = dlib.face_recognition_model_v1("/home/image_recognition/code/dlib_face_recognition_resnet_model_v1.dat")


class ReadVideo:

    def __init__(self, path):
        self.container = av.open(path)

        self.video = self.container.streams.video[0]
        self.size = self.video.width, self.video.height
        self.frames = self.video.frames
        self.duration = self.container.duration / 1000
        self.rate = self.video.rate
        self.bit_rate = self.video.bit_rate

    def read(self):
        for packet in self.container.demux(self.video):
            for frame in packet.decode():
                yield frame

# 连接数据库redis,存放数据
def sava_redis_info(key, value):
    if not isinstance(value, list):
        print('数据类型错误')
        return

    r = redis.Redis(host='47.xxx.xxx.61', port=6379, password='', db=1, decode_responses=True)
    # 对values进行处理
    end_info = str(value)[1:len(str(value))-1].replace(" ", "")
    r.lpush(key, end_info)
    r.expire(key, 3600)
    print("保存成功!")


# 连接数据库redis, 取出数据
def get_redis_info(key):
    r = redis.Redis(host='47.xxx.xxx.xxx', port=6379, password='', db=1, decode_responses=True)
    index_res = r.llen(key)
    if index_res == 0:
        print("数据不存在")
        return 0
    redis_list = r.lrange(key, 0, index_res)
    new_list = []
    for i in redis_list:
        new_list.append(list(i.split(",")))

    return new_list


# 计算图片到128d特征
def return_128d_features(path_img):
    # img_rd = io.imread(path_img)

    # 判断图片中是否有人脸
    faces = detector(path_img, 1)

    if len(faces) != 0:
        shape = predictor(path_img, faces[0])
        face_descriptor = face_reco_model.compute_face_descriptor(path_img, shape)
    else:
        # print("未检测到人脸")
        return 0
    return face_descriptor

# 计算两个128D向量间的欧式距离
def return_euclidean_distance(feature_1, feature_2):
    feature_1 = np.array(feature_1)
    feature_2 = np.array(feature_2)
    dist = np.sqrt(np.sum(np.square(feature_1 - feature_2)))

    return dist


# 将视频变为一张张图片
def video_save_image(frame, save_path, image_name, frame_count):
    resize_frame = cv2.resize(frame, (576, 1024), interpolation=cv2.INTER_AREA)
    cv2.imwrite(save_path + "{}-{}.jpg".format(image_name, frame_count), resize_frame)


# 对视频进行处理
def video_dispose(video_path, key):
    """
    :param video_path: 视频路径
    :return:
    3 帧宽
    4 帧高
    """
    time1 = datetime.datetime.now()

    r_video = ReadVideo(video_path)

    image_num = 0
    image_num_no = 1

    try:
        for frame in r_video.read():
            img = frame.to_image()
            # 检测人脸
            faces = detector(np.array(img), 0)

            # 如果检测到有人脸
            if len(faces) != 0:
                vector_list = []
                for i in range(len(faces)):
                    shape = predictor(np.array(img), faces[i])
                    vector_list.append(face_reco_model.compute_face_descriptor(np.array(img), shape))

                # 取出数据
                res_list = get_redis_info(key)
                redis_list_len = len(res_list)
                res_dist = 0

                # 计算欧式距离
                for i in res_list:
                    s_list = []
                    for m in i:
                        s_list.append(float(m))

                    res_dist = res_dist + return_euclidean_distance(s_list, list(vector_list))

                new_res_dist = res_dist / redis_list_len
                if new_res_dist <= 0.4:
                    image_num += 1

                    # 保存图片
                    # video_save_image(frame, path_images_from_camera, "video", image_num)

                    print("是同一个人,相似度为{}".format(1-float(new_res_dist)))
                else:
                    image_num_no += 1
                    print("不是同一个人,相似度为{}".format(1 - float(new_res_dist)))

    except Exception as e:
        time2 = datetime.datetime.now()
        print("视频结束!一共识别图片{}张!未识别图片{}张,耗时{}".format(image_num, image_num_no, time2-time1))


# 图片识别运行入口
def main2(identification, path, type=2):

    # 1. 获取要识别图片对路径
    # path_images_from_camera = "/home/image_recognition/image/"
    # image_path = path_images_from_camera + path

    # 2. 获取要识别图片对128d特征
    face_descriptor = return_128d_features(path)
    if not face_descriptor:
        return False

    # 2.1 如果是保存特征值
    if type == 1:
        sava_redis_info(identification, list(face_descriptor))
        return

    # 2.2 获取数据库中存储的128d特征
    res_128d = get_redis_info(identification)
    redis_list_len = len(res_128d)
    res_dist = 0

    if not res_128d:
        return

    for i in res_128d:
        s_list = []
        for m in i:
            s_list.append(float(m))

        # 3. 计算两个128D向量间的欧式距离
        res_dist = res_dist + return_euclidean_distance(list(face_descriptor), s_list)

    new_res_dist = res_dist / redis_list_len
    # 4. 判断是否是同一个人
    if new_res_dist <= 0.40:
        # print("是同一个人,相似度为{}".format(1-float(new_res_dist)))
        return True
    else:
        # print("不是同一个人,相似度为{}".format(1-float(new_res_dist)))
        return False


# res = main2("13781972862", "img_face_2.jpg", type=2)
# print(res)
video_dispose("/home/image_recognition/code/2.mp4", "13781972862")

使用av和opencv读取视频都是可以的,看个人选择,如果dlib不能满足你的需求,那么我使用srcfd封装了人脸识别,速度比dlib提高了8倍,大家可以下载使用:
Dlib 人脸 landmark 特征点检测器和
Dlib Resnet 人脸识别模型,提取 128D 的特征矢量的库可以使用云盘下载:
链接: https://pan.baidu.com/s/1nQ6BTiWsOtlvB_Qoh3bqzA
提取码: 69e1

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值