95 lines
2.7 KiB
Python
95 lines
2.7 KiB
Python
import cv2
|
|
import cv2 as cv
|
|
import dlib
|
|
import joblib
|
|
import numpy as np
|
|
from sklearn.metrics import accuracy_score
|
|
from sklearn.model_selection import train_test_split
|
|
from sklearn.svm import SVC
|
|
from tqdm import tqdm
|
|
|
|
# 方法区
|
|
## 转换为二值图和GRB图
|
|
def img_cvt(img):
|
|
img_gray = cv.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
|
_,img_gray=cv.threshold(img_gray,127,255,cv.THRESH_BINARY)
|
|
img_gray = cv.blur(img_gray,(3,3))
|
|
img_rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)
|
|
return img_gray,img_rgb
|
|
## 提取人脸特征
|
|
def extract_face_feature(img):
|
|
faces=detector(img)
|
|
if len(faces)>0:
|
|
face=faces[0]
|
|
landmarks=predictor(img,face)
|
|
face_descriptor=face_rec_model.compute_face_descriptor(img,landmarks)
|
|
return np.array(face_descriptor)
|
|
else:
|
|
return None
|
|
## 生成伪样品
|
|
def gen_negative_samples(features_dim=128):
|
|
return np.random.uniform(-1,1,features_dim)
|
|
|
|
# 变量区
|
|
dataset_video=cv.VideoCapture('cache/dataset.mp4')
|
|
datasets=[]
|
|
datasets_rgb=[]
|
|
features=[]
|
|
negative_samples=[]
|
|
|
|
# 收集数据集
|
|
## 采用视频的格式收集图片
|
|
while(True):
|
|
ret,frame=dataset_video.read()
|
|
if not ret:
|
|
break
|
|
datasets.append(frame)
|
|
|
|
# 加载人脸检测模型
|
|
detector=dlib.get_frontal_face_detector()
|
|
predictor=dlib.shape_predictor("models/shape_predictor_68_face_landmarks_GTX.dat")
|
|
face_rec_model=dlib.face_recognition_model_v1('models/dlib_face_recognition_resnet_model_v1.dat')
|
|
|
|
# 预处理数据集
|
|
for dataset in tqdm(datasets,desc='正在预处理数据集'):
|
|
_,dataset_rgb = img_cvt(dataset)
|
|
datasets_rgb.append(dataset_rgb)
|
|
|
|
# 求人脸特征
|
|
for dataset in tqdm(datasets_rgb,desc='正在求人脸特征'):
|
|
face_descriptor=extract_face_feature(dataset)
|
|
if face_descriptor is not None:
|
|
features.append(face_descriptor)
|
|
|
|
# 生成负样本
|
|
for i in tqdm(range(len(features)*15),desc='正在生成负样本'):
|
|
negative_sample=gen_negative_samples()
|
|
negative_samples.append(negative_sample)
|
|
|
|
# 编码数据集
|
|
positive_labels=[1]*len(features)
|
|
negative_labels=[0]*len(negative_samples)
|
|
|
|
samples=features+negative_samples
|
|
labels=positive_labels+negative_labels
|
|
|
|
X_train=np.array(samples)
|
|
Y_train=np.array(labels)
|
|
|
|
# 分离数据集和训练集
|
|
X_train,X_test,Y_train,Y_test=train_test_split(X_train,Y_train,test_size=0.2,random_state=42,stratify=Y_train)
|
|
|
|
# 训练
|
|
print('正在训练分类器')
|
|
classifier=SVC(kernel='linear',C=1.0,random_state=42)
|
|
classifier.fit(X_train,Y_train)
|
|
|
|
# 评估分类器性能
|
|
Y_pred=[]
|
|
for test_sample in tqdm(X_test,desc='评估分类器'):
|
|
Y_pred.append(classifier.predict(test_sample.reshape(1,-1)))
|
|
accuracy=accuracy_score(Y_test,Y_pred)
|
|
print(f'准确率:{accuracy*100:.2f}%')
|
|
|
|
# 保存模型
|
|
joblib.dump(classifier,'models/classifier.pkl') |