上一篇博客是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