人臉識別--(opencv、dlib、keras-TensorFlow)

1.創(chuàng)建工程結(jié)構(gòu)目錄如下

image.png
data目錄

包含train目錄與validation目錄,將需要訓(xùn)練的圖片放入到對應(yīng)的文件夾中,名稱可以自命名

saved_models目錄

儲存訓(xùn)練完成后的模型

4.mp4

視屏文件,訓(xùn)練完成之后可通過這個視屏文件進(jìn)行預(yù)測

model_cnn_train.py

模型訓(xùn)練文件
詳細(xì)代碼如下

#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = 'ding'
from __future__ import print_function
import keras
import matplotlib.pyplot as plt
from keras.datasets import cifar10
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Conv2D, MaxPooling2D
import os

batch_size = 32  # 訓(xùn)練時每個批次的樣本數(shù)    訓(xùn)練樣本數(shù)/批次樣本數(shù) = 批次數(shù)(每個周期)
# num_classes = 10
num_classes = 2  # 2類別  可增加或減少需要識別的類別,對應(yīng)train、validation目錄下的目錄個數(shù),例如我這里只有兩個類別 這里的classes就是2
# epochs = 100
epochs = 50  # 訓(xùn)練50周期,訓(xùn)練集所有樣本(數(shù)據(jù)、記錄)參與訓(xùn)練一次為一個周期
# data_augmentation = True
# num_predictions = 20
save_dir = os.path.join(os.getcwd(), 'saved_models')
model_name = 'keras_face_trained_model.h5'

img_w = 150
img_h = 150


# LossHistory類,保存loss和acc
class LossHistory(keras.callbacks.Callback):
    def on_train_begin(self, logs={}):
        self.losses = {'batch': [], 'epoch': []}
        self.accuracy = {'batch': [], 'epoch': []}
        self.val_loss = {'batch': [], 'epoch': []}
        self.val_acc = {'batch': [], 'epoch': []}

    def on_batch_end(self, batch, logs={}):
        self.losses['batch'].append(logs.get('loss'))
        self.accuracy['batch'].append(logs.get('acc'))
        self.val_loss['batch'].append(logs.get('val_loss'))
        self.val_acc['batch'].append(logs.get('val_acc'))

    def on_epoch_end(self, batch, logs={}):
        self.losses['epoch'].append(logs.get('loss'))
        self.accuracy['epoch'].append(logs.get('acc'))
        self.val_loss['epoch'].append(logs.get('val_loss'))
        self.val_acc['epoch'].append(logs.get('val_acc'))

    def loss_plot(self, loss_type):
        iters = range(len(self.losses[loss_type]))
        plt.figure()
        # acc
        plt.plot(iters, self.accuracy[loss_type], 'r', label='train acc')
        # loss
        plt.plot(iters, self.losses[loss_type], 'g', label='train loss')
        if loss_type == 'epoch':
            # val_acc
            plt.plot(iters, self.val_acc[loss_type], 'b', label='val acc')
            # val_loss
            plt.plot(iters, self.val_loss[loss_type], 'k', label='val loss')
        plt.grid(True)
        plt.xlabel(loss_type)
        plt.ylabel('acc-loss')
        plt.legend(loc="upper right")
        plt.show()


''''' 
# The data, shuffled and split between train and test sets: 
(x_train, y_train), (x_test, y_test) = cifar10.load_data() 
print('x_train shape:', x_train.shape) 
print(x_train.shape[0], 'train samples') 
print(x_test.shape[0], 'test samples') 
 
# Convert class vectors to binary class matrices. 
y_train = keras.utils.to_categorical(y_train, num_classes) 
y_test = keras.utils.to_categorical(y_test, num_classes) 
'''

model = Sequential()
model.add(Conv2D(32, (3, 3), padding='same',
                 # input_shape=x_train.shape[1:]))
                 input_shape=(150, 150, 3)))  # 輸入數(shù)據(jù)是圖片轉(zhuǎn)換的矩陣格式,150(行)x 150(列) x 3 (通道)(每個像素點(diǎn)3個單位,分別表示RGB(紅綠藍(lán)))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Conv2D(64, (3, 3), padding='same'))
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes))
model.add(Activation('softmax'))

# initiate RMSprop optimizer
opt = keras.optimizers.rmsprop(lr=0.0001, decay=1e-6)

# Let's train the model using RMSprop
model.compile(loss='categorical_crossentropy',
              optimizer=opt,
              metrics=['accuracy'])

# x_train = x_train.astype('float32')
# x_test = x_test.astype('float32')
# x_train /= 255
# x_test /= 255

# 創(chuàng)建history實(shí)例
history = LossHistory()
''''' 
if not data_augmentation: 
    print('Not using data augmentation.') 
    model.fit(x_train, y_train, 
              batch_size=batch_size, 
              epochs=epochs, 
              validation_data=(x_test, y_test), 
              shuffle=True) 
else: 
    print('Using real-time data augmentation.') 
    # This will do preprocessing and realtime data augmentation: 
    datagen = ImageDataGenerator( 
        featurewise_center=False,  # set input mean to 0 over the dataset 
        samplewise_center=False,  # set each sample mean to 0 
        featurewise_std_normalization=False,  # divide inputs by std of the dataset 
        samplewise_std_normalization=False,  # divide each input by its std 
        zca_whitening=False,  # apply ZCA whitening 
        rotation_range=0,  # randomly rotate images in the range (degrees, 0 to 180) 
        width_shift_range=0.1,  # randomly shift images horizontally (fraction of total width) 
        height_shift_range=0.1,  # randomly shift images vertically (fraction of total height) 
        horizontal_flip=True,  # randomly flip images 
        vertical_flip=False)  # randomly flip images 
 
    # Compute quantities required for feature-wise normalization 
    # (std, mean, and principal components if ZCA whitening is applied). 
    datagen.fit(x_train) 
 
    # Fit the model on the batches generated by datagen.flow(). 
    model.fit_generator(datagen.flow(x_train, y_train, 
                                     batch_size=batch_size), 
                        epochs=epochs, 
                        validation_data=(x_test, y_test), 
                        workers=4) 
'''
train_datagen = ImageDataGenerator(
    rescale=1. / 255,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True)

test_datagen = ImageDataGenerator(rescale=1. / 255)

# 訓(xùn)練樣本初始化處理:長寬調(diào)整,批次大小調(diào)整,數(shù)據(jù)打亂排序(shuffle=True),分類區(qū)分(binary:2分類、categorical:多分類)
train_generator = train_datagen.flow_from_directory(
    './data/train',  # 訓(xùn)練樣本
    target_size=(img_w, img_h),  # 圖片格式調(diào)整為 150x150
    batch_size=batch_size,
    shuffle=True,
    class_mode='categorical')  # matt,多分類

validation_generator = test_datagen.flow_from_directory(
    './data/validation',  # 驗(yàn)證樣本
    target_size=(img_w, img_h),
    batch_size=batch_size,
    shuffle=True,
    class_mode='categorical')  # matt,多分類

# 模型適配生成
model.fit_generator(
    train_generator,  # 訓(xùn)練集
    samples_per_epoch=2400,  # 訓(xùn)練集總樣本數(shù),如果提供樣本數(shù)量不夠,則調(diào)整圖片(翻轉(zhuǎn)、平移等)補(bǔ)足數(shù)量(本例,該函數(shù)補(bǔ)充2400-240個樣本)
    nb_epoch=epochs,
    validation_data=validation_generator,  # 驗(yàn)證集
    nb_val_samples=800,  # 驗(yàn)證集總樣本數(shù),如果提供樣本數(shù)量不夠,則調(diào)整圖片(翻轉(zhuǎn)、平移等)補(bǔ)足數(shù)量(本例,該函數(shù)補(bǔ)充800-60個樣本)
    callbacks=[history])  # 回調(diào)函數(shù),繪制批次(epoch)和精確度(acc)關(guān)系圖表函數(shù)

# Save model and weights
if not os.path.isdir(save_dir):  # 沒有save_dir對應(yīng)目錄則建立
    os.makedirs(save_dir)
model_path = os.path.join(save_dir, model_name)
model.save(model_path)
print('Saved trained model at %s ' % model_path)

# 顯示批次(epoch)和精確度(acc)關(guān)系圖表
history.loss_plot('epoch')

# 模型結(jié)構(gòu)圖
from keras.utils import plot_model

plot_model(model, to_file='model.png', show_shapes=True)

# Score trained model.
# scores = model.evaluate(x_test, y_test, verbose=1)
# print('Test loss:', scores[0])
# print('Test accuracy:', scores[1])

video_face_sign.py

模型預(yù)測

#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = 'ding'
import os
import numpy as np
import sys
import time
import cv2
import dlib

from keras.preprocessing import image as imagekeras
from keras.models import load_model
from PIL import Image, ImageDraw, ImageFont

size = 150
save_dir = os.path.join(os.getcwd(), 'saved_models')
model_name = 'keras_face_trained_model.h5'


# 類別編碼轉(zhuǎn)換為中文名稱返回
def return_name(codelist):
    #
    names = ['XXX', 'XXX'] #這里的XXX為中文名字,識別出來的以此處的名字作為標(biāo)記出現(xiàn),順序應(yīng)該與train目錄下的順序一致
    for it in range(0, len(codelist), 1):
        if int(codelist[it]) == 1.0:
            return names[it]


# 類別編碼轉(zhuǎn)換為英文名稱返回
def return_name_en(codelist):
    names = ['ding', 'tss']#train目錄下的名稱與這里的名稱需要保持一致
    for it in range(0, len(codelist), 1):
        if int(codelist[it]) == 1.0:
            return names[it]


# 區(qū)分和標(biāo)記視頻中截圖的人臉
def face_rec():
    global image_ouput
    model = load_model(os.path.join(save_dir, model_name))
    camera = cv2.VideoCapture("4.mp4")  # 視頻
    # camera_img = cv2.imread()
    # camera = cv2.VideoCapture(0) # 攝像頭

    while (True):
        read, img = camera.read()
        try:
            # 未截取視頻圖片結(jié)束本次循環(huán)
            if not (type(img) is np.ndarray):
                continue
            gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 圖片轉(zhuǎn)為灰度圖
        except:
            print("Unexpected error:", sys.exc_info()[0])
            break

        # 使用detector進(jìn)行人臉檢測
        # 使用dlib自帶的frontal_face_detector作為我們的特征提取器
        detector = dlib.get_frontal_face_detector()
        dets = detector(gray_img, 1)  # 提取截圖中所有人臉

        facelist = []
        for i, d in enumerate(dets):  # 依次區(qū)分截圖中的人臉
            x1 = d.top() if d.top() > 0 else 0
            y1 = d.bottom() if d.bottom() > 0 else 0
            x2 = d.left() if d.left() > 0 else 0
            y2 = d.right() if d.right() > 0 else 0

            img = cv2.rectangle(img, (x2, x1), (y2, y1), (255, 0, 0), 2)  # 人臉畫框

            face = img[x1:y1, x2:y2]
            face = cv2.resize(face, (size, size))

            x_input = np.expand_dims(face, axis=0)
            prey = model.predict(x_input)
            print(prey, 'prey')

            facelist.append([d, return_name(prey[0])])  # 存儲一張圖中多張人臉坐標(biāo)和標(biāo)記(姓名)

        cv2_im = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # cv2和PIL中顏色的hex碼的儲存順序不同
        pil_im = Image.fromarray(cv2_im)

        draw = ImageDraw.Draw(pil_im)  # 括號中為需要打印的cqanvas,這里就是在圖片上直接打印
        font = ImageFont.truetype("simhei.ttf", 20, encoding="utf-8")  # 第一個參數(shù)為字體文件路徑,第二個為字體大小

        try:
            for i in facelist:
                # 人臉標(biāo)記寫入圖片,第一個參數(shù)為打印的坐標(biāo),第二個為打印的文本,第三個為字體顏色,第四個為字體
                draw.text((i[0].left() + int((i[0].right() - i[0].left()) / 2 - len(i[1]) * 10), i[0].top() - 20), i[1],
                          (255, 0, 0), font=font)
        except:
            print("Unexpected error:", sys.exc_info()[0])
            continue

        # PIL圖片轉(zhuǎn)換為cv2圖片
        cv2_char_img = cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGB2BGR)
        # 顯示圖片
        cv2.imshow("camera", cv2_char_img)
        if cv2.waitKey(1) & 0xff == ord("q"):
            break
    cv2.destroyAllWindows()


if __name__ == "__main__":
    face_rec()

關(guān)鍵庫版本
keras==2.1.0
tensorflow==1.4.0
dlib==19.7.0

dlib在win7環(huán)境下的安裝可直接用whl文件安裝
dlib 工具
https://download.csdn.net/download/u014258362/10473197

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容