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