人脸年龄识别

人脸识别背景

现今生活中主要采用号码、磁卡、口令等识别方法,这些都存在着易丢失、易伪造、易遗忘等诸多问题。随着技术的不断发展,传统的身份识别方法已经受到越来越多的挑战,可靠性大为降低,势必出现新的信息识别和检测技术。人们逐渐的把目光转向了生物体征,这些都是人类遗传的DNA所决定的,并且每个人都拥有自己独一无二的生物体征。生物识别技术大致可以分为两大类,一类是物体体征,例如指纹、虹膜、人脸、体味等。另一类是行为体征,例如书写、步频、惯性动作等,这些都可以通过现在的计算机图像处理技术进行识别。与其他人类的生理特征相比,人脸存在易采集、非接触、静态等优点,比较容易被大众所接受。 据调查,人与人接触时,90%的人是通过观察一个人的脸部特征来了解对方,获取对方的基本信息,这就是所谓的第一印象。虽然外部条件例如年龄、表情、光照等发生巨大变化,是一个人的面部特征发生巨大变化,但是人类仍然可以识别,这一现象说明人的脸部存有大量特征信息,通过提出人脸部的特征信息,就可以判断一个人。

人脸识别研究概况

2014年是我国人脸识别技术的转折点,使人脸识别技术从理论走向了应用,2018年则是人脸识别技术全面应用的重要节点,"刷脸"时代正式到来。
目前,从我国人脸识别技术应用来看,主要集中在三大领域:考勤门禁、安防以及金融。从具体应用来看,主要包含了公共安全领域的刑侦追逃、罪犯识别以及边防安全等;信息安全领域的政府职能领域的电子政务、户籍管理、社会福利和保险;商业企业领域的电子商务、电子货币和支付、考勤、市场营销;场所进出领域的军事机要部门、金融机构的门禁控制和进出管理等。

人脸识别算法分类

整体来看,人脸识别算法分为三类:

  1. 人脸检测(Face Detection) ,重点处理人脸定位问题,定位图像中的人脸;
  2. 人脸对齐(Face Alignment) ,重点处理人脸变换问题,得到同一角度与姿态的人脸;
  3. 人脸特征表征(Feature Representation) ,重点对人脸细节进行识别和处理,比如本文的人脸年龄检测;

人脸识别的意义

人脸识别的目标是确定一张人脸图像的身份,这是机器学习和模式识别中的分类问题。它不但可以用在身份识别和身份验证中,帮助找寻失踪人口、追踪嫌疑人、智能交互身份识别等场景;而且在证件查询、出入考勤查验、身份验证解锁、支付等场景中,也有广泛的应用,并为我们的生活带来极大的便利。

一张有趣的人脸年龄识别结果图

在这里插入图片描述
究竟是什么,让原本只有一岁之差的两个人被 AI 误会为「形同父子」?是 AI 的「良知泯灭」,还是人类的「自食其果」?

本文目的

通过训练模型推测人脸年龄

数据集

1到70岁人脸面部图像,数量不等
数据集下载地址: https://static.leiphone.com/face_age_dataset.zip.gz.
代码下载地址:https://www.leiphone.com/uploads/new/aihub/matchCode/zip/5e539045aa017.zip

dataloader.py

from PIL import Image
from torch.utils.data.dataset import Dataset
from torchvision import transforms

#定义人脸数据集类
class FADataset(Dataset):
    def __init__(self, filelist, isTrain=False):
       	self.images = [item.strip().split(' ')[0] for item in open(filelist, 'r').readlines()]
        self.labels = [int(item.strip().split(' ')[1]) for item in open(filelist, 'r').readlines()]
	#对训练集进行水平翻转及规范化操作
        if isTrain:
            self.transform = transforms.Compose([
                    transforms.RandomHorizontalFlip(),
                    transforms.ToTensor(),
                    transforms.Normalize(mean=[0.5], std=[0.5]),
                ]) 
    #对测试集不需要数据增强操作
        else:
            self.transform = transforms.Compose([
                    transforms.ToTensor(),
                    transforms.Normalize(mean=[0.5], std=[0.5]),
                ])                       
	#返回数据集中图片的个数
    def __len__(self):
        return len(self.images)
        
	#读取图片文件,返回其label
    def __getitem__(self, index):
        # image = Image.open(self.images[index])
        image = Image.open(self.images[index]).convert('L')
        img = self.transform(image)
        label = self.labels[index]
        
        return img, label

generate_train_val_file.py

import os 
#定义训练集路径并列出文件列表
root = '../../data/train/'
A = os.listdir(root)
#为训练集图片加上label
for item in A:
        if len(item) != 3:
                continue
        flag = 0
        for i in range(len(item)):
                if item[i] != '0':
                        flag = i
                        break
        label = int(item[flag:]) - 1
        B = os.listdir(root + item)

        for idx in B:
                with open('data/train.txt', 'a+') as f:
                        f.write(root + item + '/' + idx + ' ' + str(label) +'\n')


img_aug.py

# coding:utf-8
import numpy as np
import cv2
import os
import random
from tqdm import tqdm

#进行图像处理,数据增强
def gamma(img, gamma):
    image_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    image_gamma = np.uint8(np.power((np.array(img) / 255.0), gamma) * 255.0)
    cv2.normalize(image_gamma, image_gamma, 0, 255, cv2.NORM_MINMAX)
    cv2.convertScaleAbs(image_gamma, image_gamma)

    return image_gamma


def resize(img, size):
    img_resize = cv2.resize(img, size)
    img_resize = cv2.resize(img_resize, (200, 200))

    return img_resize


def img_process(img):
    if random.random() > 0.5:
        img = gamma(img, random.uniform(0.5, 1.9))
    if random.random() > 0.5:
        img = resize(img, (100, 100))
    if random.random() > 0.5:
        img = resize(img, (400, 400))
    if random.random() > 0.5:
        img = img[:, ::-1, :]

    return img


if __name__ == '__main__':
    root = 'data/train/'
    save = 'data/aug/'
    if not os.path.exists(save):
        os.makedirs(save)
    A = os.listdir(root)
    for item in tqdm(A):
        if len(item) > 3:
            continue
        B = os.listdir(root + item)
        if len(B) > 200:
            continue

        if not os.path.exists(save + item):
            os.makedirs(save + item)

        flag = 0
        for i in range(len(item)):
            if item[i] != '0':
                flag = i
                break
        label = int(item[flag:]) - 1

        for idx in range(len(B)):
            img = cv2.imread(root + item + '/' + B[idx])
            if len(B) < 100:
                img_a = img_process(img)
                cv2.imwrite(save + item + '/' + B[idx].split('.')[0] + 'a.jpg', img_a)
                with open('data/aug.txt', 'a+') as f:
                    f.write(save + item + '/' + B[idx].split('.')[0] + 'a.jpg ' + str(label) + '\n')
            img_p = img_process(img)
            cv2.imwrite(save + item + '/' + B[idx].split('.')[0] + 'p.jpg', img_p)
            with open('data/aug.txt', 'a+') as f:
                f.write(save + item + '/' + B[idx].split('.')[0] + 'p.jpg ' + str(label) + '\n')

                # cv2.imshow('1', img)
            # cv2.imshow('3', img)
            # cv2.imshow('2', cv2.imread(root + item + '/' + B[idx]))
            # cv2.waitKey(0)

net.py

import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision.models import vgg19_bn

#使用VGG19模型以及预训练
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        model = vgg19_bn(pretrained=True)
        # model = vgg19_bn(pretrained=False)
        weight = model.features[0].weight
        model.features[0] = nn.Conv2d(1, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
        model.features[0].weight = torch.nn.Parameter(weight[:, :1, :, :])
        self.features = nn.Sequential(*list(model.features.children())[:-4])
        self.fc = nn.Sequential(
            nn.ReLU(),
            nn.Dropout(0.3),
            nn.Linear(512, 70),          
        )
    
    def forward(self, input):
        x = self.features(input)
        x = nn.AdaptiveAvgPool2d(1)(x)
        x = x.view(x.size(0), -1)
        output = self.fc(x)
        return output

train.py

# -*- coding: utf-8 -*
import torch
import torch.nn as nn
from torch.optim import Adam, SGD, lr_scheduler
import torch.nn.functional as F
from net import Net
from dataloader import FADataset

#使用定义好的网络进行训练
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
net = Net()
# net.load_state_dict(torch.load("15.pkl"))
net.to(device)
loss_fn = nn.CrossEntropyLoss()

optimizer = Adam(net.parameters(), lr=1e-3, betas=(0.9, 0.999))
# optimizer = SGD(net.parameters(), lr=1e-4)
scheduler = lr_scheduler.MultiStepLR(optimizer, [8, 13], gamma=0.1, last_epoch=-1)
# scheduler = lr_scheduler.MultiStepLR(optimizer, [13, 19, 27, 33], gamma=0.1, last_epoch=-1)

best_accuracy = 0
best_loss = 10

dataset_train = FADataset('data/train.txt', True)
# dataset_train = FADataset('data/new_aug.txt', True)
train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=128, shuffle=True)

EPOCHS = 15
# EPOCHS = 39

for epoch in range(EPOCHS):
    train_loss = 0.0
    net.train()
    for i, (imgs, target) in enumerate(train_loader):
        imgs = imgs.to(device)
        target = target.to(device)
        optimizer.zero_grad()
        outputs = net(imgs)
        loss = loss_fn(outputs, target)
        loss.backward()
        optimizer.step()
        train_loss += loss.item()
    train_loss /= len(train_loader)

    for param_group in optimizer.param_groups:
        print('lr: %s' % param_group['lr'])
    print('Epoch: {}/{} - Average loss: {:.4f}'.format(epoch + 1, EPOCHS, train_loss))

    torch.save(net.state_dict(), 'checkpoints/' + str(epoch + 1) + '.pkl')
    scheduler.step(epoch + 1)

test.py

import argparse
import os
from PIL import Image
import torch
import torch.nn.functional as F
from torchvision import transforms
from net import Net
from tqdm import tqdm

# parser = argparse.ArgumentParser()
# parser.add_argument("epoch", type=str, help="test epoch")
# args = parser.parse_args()

#调用测试集进行模型测试
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
Transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.5], std=[0.5]), ])

net = Net().to(device)
epoch = 32
net.load_state_dict(torch.load('./checkpoints/' + epoch + '.pkl'))
net.eval()

root = 'data/test/'

for item in tqdm(os.listdir(root)):
    img = Image.open(root + item).convert('L')
    x_data = Transform(img).float().unsqueeze(0).to(device)
    outputs = net(x_data)
    prediction = torch.max(F.softmax(outputs, dim=1), dim=1)[1].cpu().numpy()[0]
    age = prediction + 1
    if len(str(age)) == 1:
        result = '00' + str(age)
    else:
        result = '0' + str(age)
    with open('submission.csv', 'a+') as f:
        f.write(item.split('.')[0] + ',' + result + '\n')

  • 5
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
人脸年龄识别是一种计算机视觉技术,主要利用机器学习模型对输入的人脸图像进行分析,从而预测出人脸年龄。在Python中,可以使用OpenCV、Dlib、TensorFlow等库来实现人脸年龄识别。 以下是使用OpenCV和Dlib库实现人脸年龄识别的简单示例代码: ```python import cv2 import dlib # 加载人脸检测器 detector = dlib.get_frontal_face_detector() # 加载人脸关键点检测器 predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat") # 加载年龄预测模型 age_net = cv2.dnn.readNetFromCaffe('deploy_age.prototxt', 'age_net.caffemodel') # 加载性别预测模型 gender_net = cv2.dnn.readNetFromCaffe('deploy_gender.prototxt', 'gender_net.caffemodel') # 读取图片 img = cv2.imread('test.jpg') # 缩放图片 img = cv2.resize(img, (500, 500)) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 检测人脸 faces = detector(gray) # 循环遍历每个人脸 for face in faces: # 检测人脸关键点 landmarks = predictor(gray, face) # 提取人脸区域 x1, y1, x2, y2 = face.left(), face.top(), face.right(), face.bottom() face_img = img[y1:y2, x1:x2] # 年龄预测 blob = cv2.dnn.blobFromImage(face_img, scalefactor=1.0, size=(227, 227), mean=(78.4263377603, 87.7689143744, 114.895847746), swapRB=False) age_net.setInput(blob) age_preds = age_net.forward() age = age_preds[0][0] * 100 # 性别预测 blob = cv2.dnn.blobFromImage(face_img, scalefactor=1.0, size=(227, 227), mean=(78.4263377603, 87.7689143744, 114.895847746), swapRB=False) gender_net.setInput(blob) gender_preds = gender_net.forward() gender = 'Female' if gender_preds[0][0] < 0.5 else 'Male' # 在图片上绘制年龄和性别 cv2.putText(img, "Age: {:.2f}".format(age), (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) cv2.putText(img, "Gender: {}".format(gender), (x1, y1-30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) # 显示图片 cv2.imshow('img', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 需要注意的是,上述示例代码需要预先下载年龄和性别预测模型文件(deploy_age.prototxt、age_net.caffemodel、deploy_gender.prototxt、gender_net.caffemodel)以及人脸关键点检测器模型文件(shape_predictor_68_face_landmarks.dat)。另外,需要将这些文件放在同一个目录下。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值