人脸性别和年龄识别

本文是对age-gender-estimation项目的详细讲解,它给出了使用keras进行性别和年龄识别的完整流程。

数据

采用的数据集为imdb-wiki,这是一个包含 20,284名人的460,723张以及维基百科上imdb的 62,328张共计523,051 张人脸图像的数据集,是目前开源的数据集中量级最大的,它给出了图像中人物的性别和出生时间、照片的拍摄时间等信息。原始的图片很大,分成了9个部分共计100多G,而裁剪出人脸的图片比较小,只有3G多,因此大家使用的基本都是wiki.tar.gz,不需要注册,直接就可以下载,这点很良心,省去了很多下载话费的时间。

解压后的目录为100个子文件夹,每个子文件夹再存储图片文件。

不过由于是采用matlab的mat格式文件存储的,实际用起来还要做一些转化。里面还含有一些噪声,比如性别标记为NAN,年龄算出来不对等,我写了一些代码来对这些信息进行过滤和统计

import os
import numpy as np
from scipy.io import loadmat
from datetime import datetime
from tqdm import tqdm
import matplotlib.pyplot as plt

def calc_age(taken, dob):
    birth = datetime.fromordinal(max(int(dob) - 366, 1))

    # assume the photo was taken in the middle of the year
    if birth.month < 7:
        return taken - birth.year
    else:
        return taken - birth.year - 1

def get_meta(mat_path, db):
    meta = loadmat(mat_path)
    full_path = meta[db][0, 0]["full_path"][0]
    dob = meta[db][0, 0]["dob"][0]  # Matlab serial date number
    gender = meta[db][0, 0]["gender"][0]
    photo_taken = meta[db][0, 0]["photo_taken"][0]  # year
    face_score = meta[db][0, 0]["face_score"][0]
    second_face_score = meta[db][0, 0]["second_face_score"][0]
    age = [calc_age(photo_taken[i], dob[i]) for i in range(len(dob))]

    return full_path, dob, gender, photo_taken, face_score, second_face_score, age

def load_data(mat_path):
    d = loadmat(mat_path)

    return d["image"], d["gender"][0], d["age"][0], d["db"][0], d["img_size"][0, 0], d["min_score"][0, 0]

def convert2txt(mat_path="imdb.mat",db="imdb"):
    lines=[]
    min_score=1.0
    full_path, dob, gender, photo_taken, face_score, second_face_score, age = get_meta(mat_path,db)
    genders=[0,0]
    ages=[]
    for i in range(101):
        ages.append(0)
    for i in tqdm(range(len(full_path))):
        #if face_score[i] < min_score:
            #continue
        #if (~np.isnan(second_face_score[i])) and second_face_score[i] > 0.0:
            #continue
        if ~(0 <= age[i] <= 100):
            continue
        if np.isnan(gender[i]):
            continue
        g=int(gender[i])
        genders[g]+=1
        ag=int(age[i])
        ages[ag]+=1
        #print(i,gender[i],age[i])
        line=full_path[i][0]+" "+str(g)+" "+str(ag)
        lines.append(line)
    with open("gt.txt","w")as f:
        for line in lines:
            f.write(line+"\n")
    print("genders",genders[0],genders[1])
    print("age:")
    for i in range(101):
        print(i,ages[i])
    plt.plot(np.linspace(0, 101,101),ages)
    plt.savefig("plot.png")
    plt.show()

if __name__=="__main__":
    convert2txt()

结果如下:

性别比(男:女)=188746:262834

年龄分布:

0 29
1 149
2 165
3 50
4 77
5 221
6 237
7 440
8 590
9 873
10 1071
11 1705
12 1736
13 2337
14 2114
15 2727
16 2856
17 3391
18 4122
19 5563
20 7784
21 8294
22 8769
23 9813
24 11478
25 12151
26 13299
27 12937
28 13778
29 14600
30 16356
31 16255
32 15374
33 15096
34 14704
35 15056
36 15139
37 14063
38 14417
39 13729
40 11068
41 11831
42 10501
43 10160
44 8917
45 10238
46 8200
47 7151
48 6688
49 6117
50 5783
51 5485
52 4816
53 4148
54 4211
55 3482
56 3096
57 3057
58 3290
59 3267
60 2709
61 2324
62 2129
63 2318
64 1889
65 1883
66 1273
67 1395
68 1147
69 1256
70 1052
71 926
72 809
73 701
74 585
75 590
76 593
77 490
78 362
79 467
80 267
81 250
82 196
83 164
84 196
85 121
86 70
87 111
88 72
89 31
90 69
91 13
92 17
93 15
94 9
95 6
96 12
97 3
98 4
99 2
100 3

画成图如下:

不难看出30-50岁之间的图片最多 ,这也是主流的分布。

具体到age-gender-estimation项目,可以简单的通过

./download.sh

下载,然后使用

python3 create_db.py --output data/imdb_db.mat --db imdb --img_size 64

将数据集转换为需要的格式,这个格式主要是清理无效标签,省的每次都再重复做,代码和我上面给出的差不多,不再赘述。

模型

使用的模型为WiderResnet

通过Netron可视化出来是

可以看出是由6个残差模型拼起来的,不过输出部分有两个输出,一个是性别的2,另一个是年龄的101

训练

训练部分也比较简单,生成了数据文件后直接使用

python3 train.py --input data/imdb_db.mat

就可以了,如果还想使用数据增强,可以加上--aug

python3 train.py --input data/imdb_db.mat --aug

demo

想看训练好的效果可以运行

python3 demo.py

猜你喜欢

转载自blog.csdn.net/minstyrain/article/details/83212565