keras入门系列(五)——使用opencv实现人脸实时检测与识别

【参考视频网址:】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()

6. 测试结果

在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值