Commit 3677bc6d by 20200318111

人脸关键点检测

parents
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="renderExternalDocumentation" value="true" />
</component>
<component name="TestRunnerService">
<option name="projectConfiguration" value="pytest" />
<option name="PROJECT_TEST_RUNNER" value="pytest" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7" project-jdk-type="Python SDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/cnn人脸关键点检测.iml" filepath="$PROJECT_DIR$/.idea/cnn人脸关键点检测.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PySciProjectComponent">
<option name="PY_SCI_VIEW" value="true" />
<option name="PY_SCI_VIEW_SUGGESTED" value="true" />
</component>
</project>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
import numpy as np
import numpy as np
import time
import os
import cv2
import kmodel as kmodel
from utils import transparentOverlay # 贴片的覆盖层
os.environ['KMP_DUPLICATE_LIB_OK']='True'
# 加载预先训练好的模型
# my_model = kmodel.load_trained_model('yuan_model_mac')
# 加载自己训练好的模型(测试时取消下面行的注释)
my_model = kmodel.load_trained_model('Bai_model')
# 创建人脸检测器
face_cascade = cv2.CascadeClassifier('cascades/haarcascade_frontalface_default.xml')
# 加载摄像头
camera = cv2.VideoCapture(0)
# 加载一个太阳眼镜图像
sunglasses = cv2.imread('sunglass.png', cv2.IMREAD_UNCHANGED)
# 死循环
while True:
time.sleep(0.01)
# 从摄像头获取一张图像
(_, frame) = camera.read()
frame = cv2.flip(frame, 1) # 翻转一下图像
frame2 = np.copy(frame) # 复制一帧图像
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 转为灰度图像
# 检测所有的人脸
faces = face_cascade.detectMultiScale(gray, 1.25, 6) # 1.25
# 对每一个检测到的人脸。faces得到的是矩形框,多张人脸就是多个矩形框,然后遍历每一张人脸。x,y为起始坐标,w,h为宽度和高度
for (x, y, w, h) in faces:
# 只包含人脸的图像
gray_face = gray[y:y+h, x:x+w]
color_face = frame[y:y+h, x:x+w]
# 将人脸图像的值 normalize 在 [0, 1] 之间。训练数据也做了归一化,所有次人脸也需要。
gray_normalized = gray_face / 255
# 缩放灰度图人脸到 96x96 匹配网络的输入
original_shape = gray_face.shape # A Copy for future reference
face_resized = cv2.resize(gray_normalized, (96, 96), interpolation = cv2.INTER_AREA) #
face_resized = face_resized.reshape(1, 96, 96, 1)
# 预测关键点坐标
keypoints = my_model.predict(face_resized) # (1,30)15个关键点的坐标
# 将关键点坐标的值从 [-1, 1] 之间转换为 [0, 96] 之间
keypoints = keypoints * 48 + 48
# 缩放彩色图人脸到 96x96 匹配关键点
face_resized_color = cv2.resize(color_face, (96, 96), interpolation = cv2.INTER_AREA) # 将要展示的彩色图像
face_resized_color2 = np.copy(face_resized_color)
# 将网络输出的30个值配对为15个tuple对
points = []
for i, co in enumerate(keypoints[0][0::2]): # x坐标
points.append((co, keypoints[0][1::2][i])) # y坐标
# 按照关键点的 left_eyebrow_outer_end_x[7], right_eyebrow_outer_end_x[9]确定眼镜的宽度
sunglass_width = int((points[7][0]-points[9][0])*1.1) # 左眉毛外侧减去右眉毛外侧
# 按照关键点的 nose_tip_y[10], right_eyebrow_inner_end_y[8]确定眼镜的高度
sunglass_height = int((points[10][1]-points[8][1])/1.1)
sunglass_resized = cv2.resize(sunglasses, (sunglass_width, sunglass_height), interpolation = cv2.INTER_CUBIC)
# 戴眼镜
face_resized_color = transparentOverlay(face_resized_color, sunglass_resized , pos=(int(points[9][0]),int(points[9][1])), scale = 1)
# 将覆盖了眼镜的 face_resized_color 图像转为摄像头捕捉到的原始图像中的大小
frame[y:y+h, x:x+w] = cv2.resize(face_resized_color, original_shape, interpolation = cv2.INTER_CUBIC)
# 在人脸图像中显示关键点坐标
for keypoint in points:
cv2.circle(face_resized_color2, keypoint, 1, (0,255,0), 1)
frame2[y:y+h, x:x+w] = cv2.resize(face_resized_color2, original_shape, interpolation = cv2.INTER_CUBIC)
# 显示加了眼镜的图像
cv2.imshow("With Glass", frame)
# 显示添加了关键点的图像
cv2.imshow("With Keypoints", frame2)
# 当 'q' 键被点击, 退出循环
if cv2.waitKey(1) & 0xFF == ord("q"):
break
# 释放摄像头, 关闭窗口
camera.release()
cv2.destroyAllWindows()
from keras.models import Sequential
from keras.models import Sequential
from keras.models import load_model
from keras.layers import Convolution2D, MaxPooling2D, Dropout
from keras.layers import Flatten, Dense
from keras.optimizers import SGD, RMSprop, Adagrad, Adadelta, Adam, Adamax, Nadam
def create_model():
"""
网络的输入为96x96的单通道灰阶图像, 输出30个值, 代表的15个关键点的横坐标和纵坐标
"""
model = Sequential()
model.add(Convolution2D(32, (5, 5), input_shape=(96, 96, 1), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.1))
model.add(Convolution2D(128, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.2))
model.add(Convolution2D(30, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.3))
model.add(Flatten())
model.add(Dense(64, activation='relu'))
model.add(Dense(128, activation='relu'))
model.add(Dense(256, activation='relu'))
model.add(Dense(64, activation='relu'))
model.add(Dense(30))
return model
def compile_model(model):
optimizer = 'adam' # 优化器的选择
loss = 'mean_squared_error' # 回归问题
metrics = ['mean_squared_error']
model.compile(optimizer=optimizer, loss=loss, metrics=metrics)
def train_model(model, X_train, y_train):
return model.fit(X_train, y_train, epochs=100, batch_size=200, verbose=1, validation_split=0.2)
def save_model(model, fileName):
model.save(fileName + '.h5')
def load_trained_model(fileName):
return load_model(fileName + '.h5')
from utils import load_data
from utils import load_data
import kmodel as kmodel
# 加载训练数据
X_train, y_train = load_data()
# 创建网络结构
my_model = kmodel.create_model()
# 编译网络模型
kmodel.compile_model(my_model)
# 训练网络模型
kmodel.train_model(my_model, X_train, y_train)
# 保存网络模型
kmodel.save_model(my_model, 'Bai_model')
import numpy as np
import numpy as np
from pandas.io.parsers import read_csv
from sklearn.utils import shuffle
import cv2
def load_data(test=False):
"""
当 test 为真, 加载测试数据, 否则加载训练数据
"""
FTRAIN = './data/training.csv'
FTEST = './data/test.csv'
fname = FTEST if test else FTRAIN
df = read_csv(fname)
# 将'Image' 列中 '空白键' 分割的数字们转换为一个 numpy array
df['Image'] = df['Image'].apply(lambda im: np.fromstring(im, sep=' '))
# 丢弃有缺失值的数据
df = df.dropna()
# 将图像的数字从 0 到 255 的整数转换为 0 到 1 的实数
X = np.vstack(df['Image'].values) / 255.
X = X.astype(np.float32)
# 将 X 的每一行转换为一个 96 * 96 * 1 的三维数组
X = X.reshape(-1, 96, 96, 1)
# 只有 FTRAIN 包含关键点的数据 (target value)
if not test:
y = df[df.columns[:-1]].values
# 将关键点的值 normalize 到 [-1, 1] 之间
y = (y - 48) / 48
# 置乱训练数据
X, y = shuffle(X, y, random_state=42)
y = y.astype(np.float32)
else:
y = None
return X, y
def transparentOverlay(src , overlay , pos=(0,0), scale = 1):
"""
将带透明通道(png图像)的图像 overlay 叠放在src图像上方
:param src: 背景图像
:param overlay: 带透明通道的图像 (BGRA)
:param pos: 叠放的起始位置
:param scale : overlay图像的缩放因子
:return: Resultant Image
"""
if scale != 1:
overlay = cv2.resize(overlay,(0,0),fx=scale,fy=scale)
# overlay图像的高和宽
h,w,_ = overlay.shape
# 叠放的起始坐标
y,x = pos[0],pos[1]
# 以下被注释的代码是没有优化的版本, 便于理解, 与如下没有注释的版本的功能一样
"""
# src图像的高和款
rows,cols,_ = src.shape
for i in range(h):
for j in range(w):
if x+i >= rows or y+j >= cols:
continue
alpha = float(overlay[i][j][3]/255.0) # 读取alpha通道的值
src[x+i][y+j] = alpha*overlay[i][j][:3]+(1-alpha)*src[x+i][y+j]
return src """
alpha = overlay[:,:,3]/255.0
alpha = alpha[..., np.newaxis]
src[x:x+h,y:y+w,:] = alpha * overlay[:,:,:3] + (1-alpha)*src[x:x+h,y:y+w,:] # 贴眼睛
return src
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment