148 lines
4.9 KiB
Python
148 lines
4.9 KiB
Python
import face_recognition
|
||
import numpy as np
|
||
import cv2
|
||
import base64
|
||
from PIL import Image, ImageDraw, ImageFont
|
||
|
||
|
||
class FaceNotFoundException(Exception):
|
||
|
||
def __init__(self):
|
||
err = "Compare Failure,cannot find face in image"
|
||
Exception.__init__(self, err)
|
||
|
||
|
||
# base64转opencv图片
|
||
def convert_to_image(base64_code):
|
||
"""
|
||
base64转图片
|
||
:param base64_code:需要转换的base64码:
|
||
:return image:openCv格式图片:
|
||
"""
|
||
# base64解码
|
||
b64image = base64.b64decode(base64_code)
|
||
# 转opencv图片
|
||
image_array = np.frombuffer(b64image, np.uint8)
|
||
result_image = cv2.imdecode(image_array, cv2.COLOR_BGR2RGB)
|
||
# 返回opencv图片对象
|
||
if result_image is None:
|
||
return "error"
|
||
else:
|
||
return result_image
|
||
|
||
|
||
# 缩放图片
|
||
def resize_image(image, multiple=1.0):
|
||
"""
|
||
缩放图片
|
||
:param image:需要缩放的图片:
|
||
:param multiple:可选缩放倍数,默认120大小基准缩放:
|
||
:return:
|
||
"""
|
||
# 默认以基准120大小等比例缩小
|
||
base_height = 120
|
||
image_height = image.shape[0]
|
||
if multiple == 1:
|
||
multiple = base_height / image_height
|
||
result_image = cv2.resize(image, (0, 0), fx=multiple, fy=multiple)
|
||
|
||
return result_image
|
||
|
||
|
||
# 获取单个人脸128特征点向量
|
||
def get_face_encoding(face_image, face_locations=None):
|
||
"""
|
||
获取人脸特征点向量
|
||
:param face_image: 已知人脸图片:
|
||
:param face_locations: 人脸位置:
|
||
:return face_encoding: 人脸特征点向量:
|
||
"""
|
||
face_encoding = face_recognition.face_encodings(face_image, face_locations)
|
||
return face_encoding
|
||
|
||
|
||
# 人脸比对
|
||
def contrast_faces(known_image, unknown_image, tolerance=0.4):
|
||
"""
|
||
人脸比对
|
||
:param known_image: 已知图片:
|
||
:param unknown_image: 待检测图片:
|
||
:param tolerance: 检测基准,数值越小结果越精确,同时可能出现比对失败:
|
||
:return result:检测结果:
|
||
"""
|
||
# noinspection PyBroadException
|
||
try:
|
||
known_image_encoding = get_face_encoding(resize_image(known_image))[0]
|
||
unknown_image_encoding = get_face_encoding(resize_image(unknown_image))[0]
|
||
result = face_recognition.compare_faces([known_image_encoding], unknown_image_encoding, tolerance)
|
||
return result
|
||
except IndexError:
|
||
return "nf"
|
||
except Exception as e:
|
||
print("recognition error!\n cause:{}".format(e))
|
||
return "err"
|
||
|
||
|
||
# 摄像头实时比对
|
||
def real_time_comparison(known_face_encodings, known_face_names, tolerance=0.4):
|
||
"""
|
||
人脸实时比对
|
||
:param known_face_encodings:已知人脸特征点向量数组:
|
||
:param known_face_names:已知人脸名称:
|
||
:param tolerance:检测基准,数值越小结果越精确,同时可能出现比对失败:
|
||
:return None:无返回值:
|
||
"""
|
||
process_this_frame = True
|
||
face_locations = ""
|
||
face_names = ""
|
||
cap = cv2.VideoCapture(0)
|
||
while True:
|
||
ret, frame = cap.read()
|
||
|
||
frame = cv2.flip(frame, 1, dst=None)
|
||
|
||
small_frame = resize_image(frame, 0.5)
|
||
|
||
rgb_small_frame = small_frame[:, :, ::-1]
|
||
|
||
if process_this_frame:
|
||
face_locations = face_recognition.face_locations(rgb_small_frame)
|
||
face_encodings = get_face_encoding(rgb_small_frame, face_locations)
|
||
|
||
face_names = []
|
||
for face_encoding in face_encodings:
|
||
matches = face_recognition.compare_faces(known_face_encodings, face_encoding, tolerance)
|
||
name = "Unknown"
|
||
mmax_index = matches.index(max(matches))
|
||
mmax_value = matches[mmax_index]
|
||
for index, match in enumerate(matches):
|
||
matches[index] = False
|
||
if mmax_value > (1-tolerance)*100:
|
||
matches[mmax_index] = True
|
||
if True in matches:
|
||
first_match_index = matches.index(True)
|
||
name = known_face_names[first_match_index]
|
||
face_names.append(name)
|
||
|
||
process_this_frame = not process_this_frame
|
||
for (top, right, bottom, left), name in zip(face_locations, face_names):
|
||
top *= 2
|
||
right *= 2
|
||
bottom *= 2
|
||
left *= 2
|
||
cv2.rectangle(frame, (left - 10, top - 10), (right + 10, bottom + 10), (0, 0, 255), 1)
|
||
cv2.rectangle(frame, (left, bottom - 20), (right, bottom), (0, 0, 100), cv2.FILLED)
|
||
cv2_im = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||
pil_im = Image.fromarray(cv2_im)
|
||
draw = ImageDraw.Draw(pil_im)
|
||
font = ImageFont.truetype("simhei.ttf", 25, encoding="utf-8")
|
||
draw.text((left + 20, bottom - 25), name, (255, 255, 255), font=font)
|
||
frame = cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR)
|
||
|
||
cv2.imshow('Video', frame)
|
||
|
||
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||
break
|
||
cap.release()
|
||
cv2.destroyAllWindows()
|