根据人脸预测年龄性别和情绪 (python + keras)(三)

阅读: 评论:0

根据人脸预测年龄性别和情绪 (python + keras)(三)

根据人脸预测年龄性别和情绪 (python + keras)(三)

人脸面部情绪识别 (一)

人脸面部情绪识别(二)

人脸面部情绪识别 age&gender(三)

根据人脸预测年龄性别和情绪代码实现 (c++ + caffe)(四)

* 背景 *

1、 目前人脸识别已经广泛运用,即使在视频流里面也能流畅识别出来,无论是对安防还是其他体验类产品都有很大的影响。研究完人脸识别后,对于年龄的预测,性别的判断以及根据面部动作识别表情也开始实现,以后可能还会学习颜值预测和是否带眼睛戴帽子什么的。面部表情识别技术主要的应用领域包括人机交互、智能控制、安全、医疗、通信等领域。颜值预测可以运用于未来的虚拟化妆,客户可以看见化妆后的自己,满意后再实际化妆出来的效果最能让客户开心。

实现

  • 在哪里实现?

第一,在视频流里实时识别,人脸识别的人脸对齐过程实现,人脸检测完之后将检测结果传参给预测模型。

第二、直接给图片先检测再预测

  • 代码实现
    demo.py

  • import os
    import cv2
    import time
    import numpy as np
    import argparse
    import dlib
    from contextlib import contextmanager
    from wide_resnet import WideResNet
    from keras.utils.data_utils import get_file
    dels import model_from_jsonpretrained_model = ".5/weights.18-4.06.hdf5"
    modhash = '89f56a39a78454e96379348bddd78c0d'emotion_labels = ['angry', 'fear', 'happy', 'sad', 'surprise', 'neutral']# load json and create model arch 
    json_file = open('model.json','r')
    loaded_model_json = ad()
    json_file.close()
    #将json重构为model结构
    model = model_from_json(loaded_model_json)# load weights into new model
    model.load_weights('model.h5')def predict_emotion(face_image_gray): # a single cropped faceresized_img = size(face_image_gray, (48,48), interpolation = cv2.INTER_AREA)image = shape(1, 1, 48, 48)im = size(resized_img,(90,100))cv2.imwrite('face.bmp', im)list_of_list = model.predict(image, batch_size=1, verbose=1)angry, fear, happy, sad, surprise, neutral = [prob for lst in list_of_list for prob in lst]return [angry, fear, happy, sad, surprise, neutral]def get_args():parser = argparse.ArgumentParser(description="This script detects faces from web cam input, ""and estimates age and gender for the detected faces.",formatter_class=argparse.ArgumentDefaultsHelpFormatter)#改成自己的地址                                 parser.add_argument("--weight_file", type=str, default="./pretrained_models/weights.18-4.06.hdf5",help="path to weight file (e.g. weights.18-4.06.hdf5)")parser.add_argument("--depth", type=int, default=16,help="depth of network")parser.add_argument("--width", type=int, default=8,help="width of network")args = parser.parse_args()return argsdef draw_label(image, point, label, font=cv2.FONT_HERSHEY_SIMPLEX,font_scale=1, thickness=2):size = TextSize(label, font, font_scale, thickness)[0]x, y = angle(image, (x, y - size[1]), (x + size[0], y), (255, 0, 0), cv2.FILLED)cv2.putText(image, label, point, font, font_scale, (255, 255, 255), thickness)@contextmanager
    def video_capture(*args, **kwargs):cap = cv2.VideoCapture(*args, **kwargs)try:yield lease()def yield_images():# capture videowith video_capture(0) as cap:cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)while True:# get video frameret, img = ad()if not ret:raise RuntimeError("Failed to capture image")yield imgdef main():biaoqing = ""args = get_args()depth = args.depthk = args.widthweight_file = args.weight_fileprint(weight_file)#第一次运行时会自动从给的网址下载weights.18-4.06.hdf5模型(190M左右)if not weight_file:weight_file = get_file("weights.18-4.06.hdf5", pretrained_model, cache_subdir="pretrained_models",file_hash=modhash, cache_dir=os.path.dirname(os.path.abspath(__file__)))# for face detectiondetector = _frontal_face_detector()# load model and weightsimg_size = 64model = WideResNet(img_size, depth=depth, k=k)()model.load_weights(weight_file)for img in yield_images():#img = cv2.imread("1.jpg")input_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)img_h, img_w, _ = np.shape(input_img)#print("h w ",img_h,img_w)emotions = []# Draw a rectangle around the faces# detect faces using dlib detectordetected = detector(img_gray, 0)faces = np.empty((len(detected), img_size, img_size, 3))#print("dector",detected)if len(detected) > 0:for i, d in enumerate(detected):#print("i,d =",i,d)x1, y1, x2, y2, w, h = d.left(), d.top(), d.right() + 1, d.bottom() + 1, d.width(), d.height()#print("w h =",w,h)xw1 = max(int(x1 - 0.4 * w), 0)yw1 = max(int(y1 - 0.4 * h), 0)xw2 = min(int(x2 + 0.4 * w), img_w - 1)yw2 = min(int(y2 + 0.4 * h), img_h - angle(img, (x1, y1), (x2, y2), (255, 0, 0), 2)#angle(img, (xw1, yw1), (xw2, yw2), (255, 0, 0), 2)faces[i, :, :, :] = size(img[yw1:yw2 + 1, xw1:xw2 + 1, :], (img_size, img_size))#print("faces  ",faces)face_image_gray = img_gray[y1:y1 + y2, x1:x1 + x2]angry, fear, happy, sad, surprise, neutral = predict_emotion(face_image_gray)emotions = [angry, fear, happy, sad, surprise, neutral]m = emotions.index(max(emotions))for index, val in enumerate(emotion_labels):if (m == index):biaoqing = val# predict ages and genders of the detected facesresults = model.predict(faces)predicted_genders = results[0]ages = np.arange(0, 101).reshape(101, 1)predicted_ages = results[1].dot(ages).flatten()# draw resultsfor i, d in enumerate(detected):#print("表情",biaoqing)label = "{}, {},{}".format(int(predicted_ages[i]),"F" if predicted_genders[i][0] > 0.5 else "M" ,biaoqing)draw_label(img, (d.left(), d.top()), label)cv2.imshow("result", img)#等待3mskey = cv2.waitKey(3)if key == 27:breakif __name__ == '__main__':main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168

    wide_resnet.py

    # This code is imported from the following project:  logging
    import sys
    import numpy as np
    dels import Model
    from keras.layers import Input, Activation, add, Dense, Flatten, Dropout
    from volutional import Conv2D, AveragePooling2D
    from alization import BatchNormalization
    ularizers import l2
    from keras import backend as Ksys.setrecursionlimit(2 ** 20)
    np.random.seed(2 ** 10)class WideResNet:def __init__(self, image_size, depth=16, k=8):self._depth = depthself._k = kself._dropout_probability = 0self._weight_decay = 0.0005self._use_bias = Falseself._weight_init = "he_normal"if K.image_dim_ordering() == "th":logging.debug("image_dim_ordering = 'th'")self._channel_axis = 1self._input_shape = (3, image_size, image_size)else:logging.debug("image_dim_ordering = 'tf'")self._channel_axis = -1self._input_shape = (image_size, image_size, 3)# Wide residual network .07146def _wide_basic(self, n_input_plane, n_output_plane, stride):def f(net):# format of conv_params:#               [ [kernel_size=("kernel width", "kernel height"),#               strides="(stride_vertical,stride_horizontal)",#               padding="same" or "valid"] ]# B(3,3): orignal <<basic>> blockconv_params = [[3, 3, stride, "same"],[3, 3, (1, 1), "same"]]n_bottleneck_plane = n_output_plane# Residual blockfor i, v in enumerate(conv_params):if i == 0:if n_input_plane != n_output_plane:net = BatchNormalization(axis=self._channel_axis)(net)net = Activation("relu")(net)convs = netelse:convs = BatchNormalization(axis=self._channel_axis)(net)convs = Activation("relu")(convs)convs = Conv2D(n_bottleneck_plane, kernel_size=(v[0], v[1]),strides=v[2],padding=v[3],kernel_initializer=self._weight_init,kernel_regularizer=l2(self._weight_decay),use_bias=self._use_bias)(convs)else:convs = BatchNormalization(axis=self._channel_axis)(convs)convs = Activation("relu")(convs)if self._dropout_probability > 0:convs = Dropout(self._dropout_probability)(convs)convs = Conv2D(n_bottleneck_plane, kernel_size=(v[0], v[1]),strides=v[2],padding=v[3],kernel_initializer=self._weight_init,kernel_regularizer=l2(self._weight_decay),use_bias=self._use_bias)(convs)# Shortcut Connection: identity function or 1x1 convolutional#  (depends on difference between input & output shape - this#   corresponds to whether we are using the first block in each#   group; see _layer() ).if n_input_plane != n_output_plane:shortcut = Conv2D(n_output_plane, kernel_size=(1, 1),strides=stride,padding="same",kernel_initializer=self._weight_init,kernel_regularizer=l2(self._weight_decay),use_bias=self._use_bias)(net)else:shortcut = netreturn add([convs, shortcut])return f# "Stacking Residual Units on the same stage"def _layer(self, block, n_input_plane, n_output_plane, count, stride):def f(net):net = block(n_input_plane, n_output_plane, stride)(net)for i in range(2, int(count + 1)):net = block(n_output_plane, n_output_plane, stride=(1, 1))(net)return netreturn f#    def create_model(self):def __call__(self):logging.debug("")assert ((self._depth - 4) % 6 == 0)n = (self._depth - 4) / 6inputs = Input(shape=self._input_shape)n_stages = [16, 16 * self._k, 32 * self._k, 64 * self._k]conv1 = Conv2D(filters=n_stages[0], kernel_size=(3, 3),strides=(1, 1),padding="same",kernel_initializer=self._weight_init,kernel_regularizer=l2(self._weight_decay),use_bias=self._use_bias)(inputs)  # "One conv at the beginning (spatial size: 32x32)"# Add wide residual blocksblock_fn = self._wide_basicconv2 = self._layer(block_fn, n_input_plane=n_stages[0], n_output_plane=n_stages[1], count=n, stride=(1, 1))(conv1)conv3 = self._layer(block_fn, n_input_plane=n_stages[1], n_output_plane=n_stages[2], count=n, stride=(2, 2))(conv2)conv4 = self._layer(block_fn, n_input_plane=n_stages[2], n_output_plane=n_stages[3], count=n, stride=(2, 2))(conv3)batch_norm = BatchNormalization(axis=self._channel_axis)(conv4)relu = Activation("relu")(batch_norm)# Classifier blockpool = AveragePooling2D(pool_size=(8, 8), strides=(1, 1), padding="same")(relu)flatten = Flatten()(pool)predictions_g = Dense(units=2, kernel_initializer=self._weight_init, use_bias=self._use_bias,kernel_regularizer=l2(self._weight_decay), activation="softmax",name="pred_gender")(flatten)predictions_a = Dense(units=101, kernel_initializer=self._weight_init, use_bias=self._use_bias,kernel_regularizer=l2(self._weight_decay), activation="softmax",name="pred_age")(flatten)model = Model(inputs=inputs, outputs=[predictions_g, predictions_a])return modeldef main():model = WideResNet(64)()model.summary()if __name__ == '__main__':main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153

    准备工作

     环境:python3  TensorFlow-gpu  numpy  keras  dlib模型:model.h5(表情预测模型)  model.json(表情预测模型的json类型)  weights.18-4.06.hdf5(性别年龄预测模型)
    [模型下载]()
    
    • 1
    • 2
    • 3

    运行

    python demo.py
    
    • 1

    效果

    处理一帧一秒以内,视频流里能流畅运行
    不足之处:模型的精度还不够,需要进行微调,如何改进还待研究

    硬件

    • GPU:
      name: GeForce GTX 960M major: 5 minor: 0 memoryClockRate(GHz): 1.176
      pciBusID: 0000:02:00.0
      totalMemory: 4.00GiB freeMemory: 3.34GiB
    • 处理器 (i7)

    学习参考
    keras官方文档
    参考代码以及model.h5下载
    年龄性别预测
    彻底理解Python中的yield
    Keras 实现的性别年龄检测 (已并入颜值服务)
    keras系列︱人脸表情分类与识别:opencv人脸检测+Keras情绪分类(四)

本文发布于:2024-01-31 23:10:01,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170671380332065.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:情绪   性别   年龄   keras   python
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23