【参考视频网址:】https://space.bilibili.com/45151802/video
(老师讲的特别好,良心推荐)
【github代码下载:】https://github.com/Seasea77/keras_small_project_19_07_26
文章目录
1. 实现功能:使用keras opencv实现人脸实时检测与识别
2. 文件目录
Face_image用于存放收集的人脸照片,每个子文件夹收集20张照片
collect_image_video.py, 使用视频识别人脸,收集人脸照片存放在Face_image文件夹下
face.h5是train_model.py,生成的训练模型
predict_face.py,用于实时显示人脸识别
train_model.py,生成训练模型
3. collect_image_video.py
- 功能:
- 程序执行时,要打开摄像头采集人脸照片,程序默认是电脑摄像头。
- 需要输入人名,在Face_img文件夹创建人名文件夹。
- 摄像头采集20张人脸照片放在人名文件夹下面。
- 更改20可以更改采集到图片的数量。
- 注意:37行,换成自己电脑上人脸识别级联分类器所在目录。
import os
import cv2
import random
from PIL import Image
from time import sleep
class Collect_image(object):
def __init__(self):
pass
# 为新用户创建文件夹
def mkdir(self, Face_folder, name):
if not os.path.exists(Face_folder):
os.mkdir(Face_folder)
Face_sub_folder_list = os.listdir(Face_folder)
if Face_sub_folder_list == []:
os.mkdir(os.path.join(Face_folder, "0_" + name))
name_path = os.path.join(Face_folder, "0_" + name)
folder_num = 0
else:
name_num = []
for sub_name in Face_sub_folder_list:
name_num.append(int(sub_name.split("_")[0])) # 此处必须要加一个int,否则出来的就是str,str会导致"10"排在9的前面
name_num.sort()
os.mkdir(os.path.join(Face_folder, str(name_num[-1] + 1) + "_" + name))
folder_num = name_num[-1] + 1
name_path = os.path.join(Face_folder, str(name_num[-1] + 1) + "_" + name)
return folder_num, name_path
def collect_image(self, Face_folder, collect_face_num):
# 1创建用户文件夹
name = input("请输入名字-->")
folder_num, name_path = self.mkdir(Face_folder, name)
# 2获取用户图片
FACE_DETECTOR = cv2.CascadeClassifier("D:\\software-installation\\opencv\\opencv\\build\\etc\\haarcascades\\haarcascade_frontalface_alt.xml")
capture = cv2.VideoCapture(0)
face_counter = 0
sleep(2) # opencv在调用摄像头时会有启动时间
while(True):
print(face_counter)
ret, frame = capture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY) # COLOR_RGB2GRAY不要写错了 写成COLOR_RGB2GBGRA就会报错
faces = FACE_DETECTOR.detectMultiScale(gray, scaleFactor=1.2)
print(faces)
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=2)
if face_counter < collect_face_num:
cv2.putText(img=frame,
text="collect%simage" % str(face_counter),
org=(x, y - 20),
fontFace=cv2.FONT_HERSHEY_COMPLEX,
fontScale=1,
color=(0, 255, 0),
thickness=1)
random_num = random.randint(100000, 999999)
gray_img = Image.fromarray(gray) # ***********************************1
gray_img.save(os.path.join(name_path, str(folder_num) + "_" + name + "_" + str(random_num) + ".jpg"))
gray_face = gray_img.crop((x - 40, y - 40, x + w + 40, y + h + 40))
# (1)4个点的坐标,(2)且4个点坐标单独加括号***********************************2
# crop_img = img.crop((x-40, y-40), (x+w+40, y+h+40)) # 只能接受一个参数
gray_face.save(os.path.join(name_path, str(folder_num) + "_" + name + "_" + str(random_num) + ".jpg"))
else:
cv2.putText(img=frame,
text="images have collected ",
org=(x, y - 20),
fontFace=cv2.FONT_HERSHEY_COMPLEX,
fontScale=1,
color=(0, 255, 0),
thickness=1)
# cv2.putText() 只能显示英文字符******************************3
# # 想要显示中文字符,用下面的方法********************************4
# # 这个是在图片上显示中文,不是在frame上面显示中文。
# frame = Image.fromarray(frame)
# draw = ImageDraw.Draw(frame)
# font = ImageFont.truetype("simhei.ttf", 20, encoding="utf-8")
# draw.text((x, y - 10), text="我的图片", fill=(0, 0, 255), font=font)
face_counter += 1
cv2.namedWindow("my_face", cv2.WINDOW_AUTOSIZE)
cv2.imshow("my_face", frame)
if face_counter > collect_face_num:
break
if cv2.waitKey(500) & 0xFF == "x":
break
def main():
Collect_img = Collect_image()
Collect_img.collect_image("Face_image", 20)
if __name__ == "__main__":
main()
**==
4. train_model.py
功能:
训练Face_img里面采集到的人脸照片,生成face.h5模型
import os
import numpy as np
from PIL import Image
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Convolution2D, Activation, MaxPool2D, Flatten, Dense, Dropout
from keras.optimizers import Adam
class Train():
def __init__(self, Raw_path, batch_size=20, nb_epoch=10):
self.raw_path = Raw_path
self.batch_size = batch_size
self.nb_epoch = nb_epoch
def pre_img(self):
img_array_list = []
label_array_list = []
nb_class = 0
for _ in os.listdir(self.raw_path):
nb_class += 1
for root, dirs, files in os.walk(self.raw_path):
for filename in files:
img = Image.open(os.path.join(root, filename))
img = img.convert("L")
img = img.resize((100, 100), Image.ANTIALIAS)
img_array = np.array(img)
img_array = img_array.reshape(100, 100, 1)
img_array = img_array / 255.
img_array_list.append(img_array)
label_array_list.append(int(filename.split("_")[0]))
img_array = np.array(img_array_list)
label_array = np.array(label_array_list)
# print(max(label_array)) # 找最大的数,这个地方不是np.argmax而是max
label_array = np_utils.to_categorical(label_array, nb_class)
print(img_array.shape)
print(label_array)
return img_array, label_array
def train_model(self):
img_array, label_array =self.pre_img()
model = Sequential()
model.add(Convolution2D(
input_shape=(100, 100, 1),
filters=32,
kernel_size=(3, 3),
padding="same",
))
model.add(Activation("relu"))
model.add(MaxPool2D(
pool_size=(2, 2),
strides=(2, 2),
padding="same"
))
model.add(Convolution2D(
filters=64,
kernel_size=(3, 3),
padding="same",
))
model.add(Activation("relu"))
model.add(MaxPool2D(
pool_size=(2, 2),
strides=(2, 2),
padding="same"
))
model.add(Flatten())
model.add(Dense(1024))
model.add(Activation("relu"))
model.add(Dropout(0.2))
model.add(Dense(256))
model.add(Activation("relu"))
model.add(Dropout(0.2))
model.add(Dense(2))
model.add(Activation("softmax"))
adam = Adam(lr=0.001)
model.compile(
loss="categorical_crossentropy",
optimizer=adam,
metrics=["accuracy"]
)
model.fit(
x=img_array,
y=label_array,
batch_size=self.batch_size,
epochs=self.nb_epoch,
verbose=1
)
model.save("./face.h5")
def main():
Train_model = Train("Face_image")
# Train_model.pre_img()
Train_model.train_model()
if __name__ == "__main__":
main()
5. predict_face.py
功能:
实时的检测人脸,并且识别出检测到的人脸是谁
注意
人脸识别仅局限于录入数据集的人脸
将第8行的级联分类器换成自己级联分类器地址
from keras.models import load_model
import cv2
import numpy as np
from PIL import Image
model = load_model("./face.h5")
# 先加载模型,避免在每次循环中再加载模型,这样会非常慢。
FACE_MODEL = cv2.CascadeClassifier("D:\\software-installation\\opencv\\opencv\\build\\etc\\haarcascades\\haarcascade_frontalface_alt.xml")
class Predict_face():
def __init__(self):
pass
def process_image(self, img):
# img = Image.open(img)
img = img.convert("L")
img = img.resize((100, 100), Image.BILINEAR)
img = np.array(img)
img = img.reshape(1, 100, 100, 1)
img = img / 255.
return img
def predict_img(self, image):
"""此处的image为摄像头获取到的图片"""
img = self.process_image(image)
prediction = model.predict(img)
final_prediction = np.argmax(prediction)
print(final_prediction)
name = ["WHD", "WLS"]
for i in range(2):
if final_prediction == i:
result_name = name[i]
return result_name
def detect_face(self):
capture = cv2.VideoCapture(0)
COUNTER = 0
while(True):
ret, frame = capture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
faces = FACE_MODEL.detectMultiScale(gray)
for (x, y, w, h) in faces:
COUNTER += 1
frame_img = Image.fromarray(frame)
frame_img = frame_img.crop((x - 40, y - 40, x + w + 40, y + h + 40)) # 这个裁剪只适用于img图片,而不是frame矩阵
predict_result = self.predict_img(frame_img)
cv2.rectangle(frame, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=1)
cv2.putText(frame, predict_result, (x, y - 40), fontFace=cv2.FONT_HERSHEY_COMPLEX, fontScale=1, color=(0, 255, 0), thickness=1)
cv2.namedWindow("人脸识别", cv2.WINDOW_AUTOSIZE)
cv2.imshow("人脸识别", frame)
if cv2.waitKey(1) & 0xFF == "x":
break
capture.release()
cv2.destroyAllWindows()
predict_face = Predict_face()
predict_face.detect_face()