mirror of
https://github.com/Yshelgi/face_web.git
synced 2026-05-25 16:00:28 +00:00
first commit
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
# 人脸检测识别&&活体识别
|
||||
|
||||
## 1. 运行环境
|
||||
|
||||
`conda create -n py39 python=3.9`
|
||||
|
||||
`conda activate py39`
|
||||
|
||||
运行所需依赖库
|
||||
`pip install tensorflow==2.11.0 scipy scikit-learn==1.0.2 numpy imutils opencv-python gradio`
|
||||
|
||||
## 2. 文件
|
||||
|
||||
+ **models:** 包含各模型权重文件
|
||||
+ **pickles:** 包含不同模型对应类别编码以及人脸识别中SVM分类器模型
|
||||
+ **infer.py** 包含封装后的推理模型,包括人脸识别和活体识别的推理
|
||||
+ **app.py** 包含gradio创建的web服务
|
||||
|
||||
## 3. 运行
|
||||
|
||||
`python main.py`
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,35 @@
|
||||
import cv2
|
||||
import numpy as np
|
||||
import gradio as gr
|
||||
from infer import Face_inference
|
||||
|
||||
|
||||
# 当设置置信度阈值较大时,人脸检测返回值为空,此时直接返回原图
|
||||
def inference(image,thresh,model_type):
|
||||
global name
|
||||
if image is None:
|
||||
yield image
|
||||
if model_type == "人脸识别":
|
||||
if m_model.face_detect(image,thresh,is_show=True) is None:
|
||||
yield image
|
||||
else:
|
||||
name,prob,res_frame = m_model.face_detect(image,thresh,is_show=True)
|
||||
yield res_frame
|
||||
else:
|
||||
if m_model.live_detect(image,name,thresh,is_show=True) is None:
|
||||
yield image
|
||||
else:
|
||||
label,prob,res_frame = m_model.live_detect(image,name,thresh,is_show=True)
|
||||
yield res_frame
|
||||
|
||||
|
||||
model_name = gr.Radio(["人脸识别","活体检测"],value="人脸识别",label="Model",info="选择需要的模型")
|
||||
threshold = gr.Slider(0.001,1,value=0.1,label="threshold",info="设置置信度阈值")
|
||||
inputs_webcam = gr.Image(sources=["webcam"],streaming=True)
|
||||
outputs_image = gr.Image(type="numpy",label="结果图片")
|
||||
|
||||
if __name__ == "__main__":
|
||||
m_model = Face_inference()
|
||||
name = ""
|
||||
demo = gr.Interface(inference,inputs=[inputs_webcam,threshold,model_name],outputs=outputs_image,live=True,title="检测")
|
||||
demo.queue().launch(max_threads=8)
|
||||
@@ -0,0 +1,163 @@
|
||||
from tensorflow.keras.preprocessing.image import img_to_array
|
||||
from tensorflow.keras.models import load_model
|
||||
import numpy as np
|
||||
import pickle
|
||||
import cv2
|
||||
import time
|
||||
import os
|
||||
|
||||
|
||||
def resize(image, width=None, height=None, inter=cv2.INTER_AREA):
|
||||
dim = None
|
||||
(h, w) = image.shape[:2]
|
||||
# 如果高和宽为None则直接返回
|
||||
if width is None and height is None:
|
||||
return image
|
||||
# 检查宽是否是None
|
||||
if width is None:
|
||||
# 计算高度的比例并并按照比例计算宽度
|
||||
r = height / float(h)
|
||||
dim = (int(w * r), height)
|
||||
# 高为None
|
||||
else:
|
||||
# 计算宽度比例,并计算高度
|
||||
r = width / float(w)
|
||||
dim = (width, int(h * r))
|
||||
resized = cv2.resize(image, dim, interpolation=inter)
|
||||
# return the resized image
|
||||
return resized
|
||||
|
||||
# 构建脸部/活体识别检测器
|
||||
class Face_inference():
|
||||
def __init__(self):
|
||||
self.face_detector_path = "./models/face_detector/"
|
||||
self.recognize_embed_path = "./models/nn4.small2.v1.t7"
|
||||
self.liveness_model_path = "./models/liveness.model"
|
||||
self.recognize_pickle = "./pickles/face_label/recognizer.pickle"
|
||||
self.recognize_class_pickle = "./pickles/face_label/le.pickle"
|
||||
self.liveness_class_pickle = "./pickles/liveness/le.pickle"
|
||||
|
||||
# 人脸检测
|
||||
self.face_detector = cv2.dnn.readNetFromCaffe(
|
||||
self.face_detector_path + "deploy.prototxt",
|
||||
self.face_detector_path + "res10_300x300_ssd_iter_140000.caffemodel"
|
||||
)
|
||||
|
||||
# 人脸embedding
|
||||
self.face_embed_model = cv2.dnn.readNetFromTorch(self.recognize_embed_path)
|
||||
|
||||
# embedding SVM 分类
|
||||
with open(self.recognize_pickle,"rb") as f:
|
||||
self.face_recog_model = pickle.loads(f.read())
|
||||
|
||||
# 活体分类
|
||||
self.liveness_model = load_model(self.liveness_model_path)
|
||||
|
||||
# 对应类别标签
|
||||
|
||||
# 人脸类别
|
||||
with open(self.recognize_class_pickle,"rb") as f:
|
||||
self.face_class = pickle.loads(f.read()).classes_
|
||||
|
||||
# 活体类别
|
||||
with open(self.liveness_class_pickle,"rb") as f:
|
||||
self.liveness_class = pickle.loads(f.read()).classes_
|
||||
|
||||
def face_detect(self,img,conf_threshold = 0.1,is_show = False):
|
||||
if img is None:
|
||||
return img
|
||||
frame = resize(img,width = 600)
|
||||
h,w = frame.shape[:2]
|
||||
blob = cv2.dnn.blobFromImage(
|
||||
cv2.resize(frame,(300,300)),1.0,(300,300),
|
||||
(104.0,177.0,123.0),swapRB = False,crop = False
|
||||
)
|
||||
|
||||
self.face_detector.setInput(blob)
|
||||
detections = self.face_detector.forward()
|
||||
|
||||
for i in range(detections.shape[2]):
|
||||
conf = detections[0,0,i,2]
|
||||
if conf > conf_threshold:
|
||||
iou = detections[0,0,i,3:7] * np.array([w,h,w,h])
|
||||
(start_x,start_y,end_x,end_y) = iou.astype('int')
|
||||
face = frame[start_y:end_y,start_x:end_x]
|
||||
|
||||
fh,fw = face.shape[:2]
|
||||
if fh < 20 or fw < 20:
|
||||
continue
|
||||
face_blob = cv2.dnn.blobFromImage(
|
||||
face,1.0/255.,(96,96),
|
||||
(0,0,0),swapRB = True , crop = False
|
||||
)
|
||||
|
||||
self.face_embed_model.setInput(face_blob)
|
||||
vec = self.face_embed_model.forward()
|
||||
|
||||
preds = self.face_recog_model.predict_proba(vec)[0]
|
||||
pred_index = np.argmax(preds)
|
||||
pred_class,pred_prob = self.face_class[pred_index],preds[pred_index]
|
||||
pred_class = pred_class if pred_prob > conf_threshold else "err"
|
||||
|
||||
if is_show:
|
||||
text = f"{pred_class}: {pred_prob*100:.2f}%"
|
||||
cv2.rectangle(frame,(start_x,start_y),(end_x,end_y),
|
||||
(0,0,255,2))
|
||||
y = start_y - 10 if start_y - 10 > 10 else start_y + 10
|
||||
cv2.putText(frame,text,(start_x,y),cv2.FONT_HERSHEY_SIMPLEX, 0.45, (0, 0, 255), 2)
|
||||
|
||||
return pred_class,pred_prob,frame
|
||||
else:
|
||||
return pred_class,pred_prob
|
||||
|
||||
|
||||
|
||||
def live_detect(self,img,name = "",conf_threshold = 0.1,is_show = False):
|
||||
if img is None:
|
||||
return img
|
||||
frame = resize(img,width=600)
|
||||
h,w = frame.shape[:2]
|
||||
blob = cv2.dnn.blobFromImage(
|
||||
cv2.resize(frame,(300,300)),1.0,(300,300),
|
||||
(104.0,177.0,123.0),swapRB = False,crop = False
|
||||
)
|
||||
|
||||
self.face_detector.setInput(blob)
|
||||
detections = self.face_detector.forward()
|
||||
|
||||
for i in range(detections.shape[2]):
|
||||
conf = detections[0,0,i,2]
|
||||
if conf > conf_threshold:
|
||||
iou = detections[0,0,i,3:7] * np.array([w,h,w,h])
|
||||
(start_x,start_y,end_x,end_y) = iou.astype('int')
|
||||
face = frame[start_y:end_y,start_x:end_x]
|
||||
|
||||
face = cv2.resize(face,(32,32))
|
||||
face = face.astype('float')/255.
|
||||
face = img_to_array(face)
|
||||
face = np.expand_dims(face,axis = 0)
|
||||
|
||||
preds = self.liveness_model(face)[0]
|
||||
index = np.argmax(preds)
|
||||
pred_class,pred_prob = self.liveness_class[index],preds[index]
|
||||
|
||||
if is_show:
|
||||
text = f"{name} , {pred_class}: {pred_prob*100:.4f}%"
|
||||
cv2.rectangle(frame,(start_x,start_y),(end_x,end_y),
|
||||
(0,0,255,2))
|
||||
y = start_y - 10 if start_y - 10 > 10 else start_y + 10
|
||||
cv2.putText(frame,text,(start_x,y),cv2.FONT_HERSHEY_SIMPLEX, 0.45, (0, 0, 255), 2)
|
||||
|
||||
return pred_class,pred_prob,frame
|
||||
else:
|
||||
return pred_class,pred_prob
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
model = Face_inference()
|
||||
img = cv2.imread("R.jpg")
|
||||
name,prob,res_frame = model.face_detect(img,is_show=True)
|
||||
cv2.imshow("face",res_frame)
|
||||
label,prob,res_frame = model.live_detect(img,name,is_show=True)
|
||||
cv2.imshow("live",res_frame)
|
||||
cv2.waitKey(0)
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user