在本教程中,我们将讨论应用于面部的深度学习的有趣应用。我们将估计年龄并从单个图像中找出该人的性别。该模型由Gil Levi和Tal Hassner训练。我们将简要讨论本文的主要思想,并提供有关如何在OpenCV中使用该模型的分步说明。

1.使用CNN的性别和年龄分类

作者使用了一种非常简单的卷积神经网络架构,类似于CaffeNet和AlexNet。该网络使用3个卷积层,2个完全连接的层和最终的输出层。层的细节如下。

Conv1:第一个卷积层有96个内核大小为7的节点。

Conv2:第二个conv层有256个节点,内核大小为5。

Conv3:第三个转换层有384个节点,内核大小为3。

两个完全连接的层各有512个节点。

他们使用Adience数据集来训练模型。

1.1 性别预测

他们将性别预测定为分类问题。性别预测网络中的输出层是softmax类型,其中2个节点指示两个类“男性”和“女性”。

1.2 年龄预测

理想情况下,年龄预测应该作为回归问题来处理,因为我们期望将实数作为输出。但是,使用回归准确估计年龄具有挑战性。甚至人类也无法根据一个人的情况准确预测年龄。但是,我们知道他们是20岁还是30多岁。由于这个原因,将这个问题构建为一个分类问题是明智的,我们试图估计这个人所处的年龄组。例如,0-2范围内的年龄是单个类别,4-6是另一个类别上课等。

Adience数据集有8个类别,分为以下年龄组[(0 – 2),(4 – 6),(8 – 12),(15 – 20),(25 – 32),(38 – 43),( 48 – 53),(60 – 100)]。因此,年龄预测网络在最终softmax层中具有8个节点,指示所述年龄范围。

应该记住,单个图像的年龄预测不是一个很容易解决的问题,因为感知年龄取决于很多因素,同一年龄的人在世界各地可能看起来很不一样。此外,人们非常努力地隐藏自己的真实年龄!

例如,你能猜出这两位知名人士的年龄吗?

Narendra Modi是68岁,Ajit Doval是74岁!想象一下机器正确预测其年龄有多难。

2.代码教程

代码可以分为四个部分:

检测面孔

检测性别

检测年龄

显示输出

注意:请下载未随代码一起提供的模型权重文件(性别,年龄)。下载文件并将其与本文提供的其他代码文件一起保存。

下载代码后,您可以使用提供的示例图像或使用网络摄像头运行代码。

#Using sample image

./AgeGender sample1.jpg

1

2

#Using sample image

./AgeGendersample1.jpg

#Using sample image

python AgeGender.py --input sample1.jpg

1

2

#Using sample image

pythonAgeGender.py--inputsample1.jpg

最终代码在文末!

2.1检测脸部

我们将使用DNN人脸检测器进行人脸检测。该型号仅为2.7MB,即使在CPU上也非常快。关于脸部检测装置的更多细节可以在我们的博客上找到的人脸检测。使用函数getFaceBox完成面部检测,如下所示。

tuple<Mat, vector<vector<int>>> getFaceBox(Net net, Mat &amp;frame, double conf_threshold)

{

Mat frameOpenCVDNN = frame.clone();

int frameHeight = frameOpenCVDNN.rows;

int frameWidth = frameOpenCVDNN.cols;

double inScaleFactor = 1.0;

Size size = Size(300, 300);

// std::vector<int> meanVal = {104, 117, 123};

Scalar meanVal = Scalar(104, 117, 123);

cv::Mat inputBlob;

cv::dnn::blobFromImage(frameOpenCVDNN, inputBlob, inScaleFactor, size, meanVal, true, false);

net.setInput(inputBlob, "data");

cv::Mat detection = net.forward("detection_out");

cv::Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());

vector<vector<int>> bboxes;

for(int i = 0; i < detectionMat.rows; i++)

{

float confidence = detectionMat.at<float>(i, 2);

if(confidence > conf_threshold)

{

int x1 = static_cast<int>(detectionMat.at<float>(i, 3) * frameWidth);

int y1 = static_cast<int>(detectionMat.at<float>(i, 4) * frameHeight);

int x2 = static_cast<int>(detectionMat.at<float>(i, 5) * frameWidth);

int y2 = static_cast<int>(detectionMat.at<float>(i, 6) * frameHeight);

vector<int> box = {x1, y1, x2, y2};

bboxes.push_back(box);

cv::rectangle(frameOpenCVDNN, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(0, 255, 0),2, 4);

}

}

return make_tuple(frameOpenCVDNN, bboxes);

}

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

tuple<Mat,vector<vector<int>>>getFaceBox(Netnet,Mat&amp;frame,doubleconf_threshold)

{

MatframeOpenCVDNN=frame.clone();

intframeHeight=frameOpenCVDNN.rows;

intframeWidth=frameOpenCVDNN.cols;

doubleinScaleFactor=1.0;

Sizesize=Size(300,300);

// std::vector<int> meanVal = {104, 117, 123};

ScalarmeanVal=Scalar(104,117,123);

cv::MatinputBlob;

cv::dnn::blobFromImage(frameOpenCVDNN,inputBlob,inScaleFactor,size,meanVal,true,false);

net.setInput(inputBlob,"data");

cv::Matdetection=net.forward("detection_out");

cv::MatdetectionMat(detection.size[2],detection.size[3],CV_32F,detection.ptr<float>());

vector<vector<int>>bboxes;

for(inti=0;i<detectionMat.rows;i++)

{

floatconfidence=detectionMat.at<float>(i,2);

if(confidence>conf_threshold)

{

intx1=static_cast<int>(detectionMat.at<float>(i,3)*frameWidth);

inty1=static_cast<int>(detectionMat.at<float>(i,4)*frameHeight);

intx2=static_cast<int>(detectionMat.at<float>(i,5)*frameWidth);

inty2=static_cast<int>(detectionMat.at<float>(i,6)*frameHeight);

vector<int>box={x1,y1,x2,y2};

bboxes.push_back(box);

cv::rectangle(frameOpenCVDNN,cv::Point(x1,y1),cv::Point(x2,y2),cv::Scalar(0,255,0),2,4);

}

}

returnmake_tuple(frameOpenCVDNN,bboxes);

}

def getFaceBox(net, frame, conf_threshold=0.7):

frameOpencvDnn = frame.copy()

frameHeight = frameOpencvDnn.shape[0]

frameWidth = frameOpencvDnn.shape[1]

blob = cv.dnn.blobFromImage(frameOpencvDnn, 1.0, (300, 300), [104, 117, 123], True, False)

net.setInput(blob)

detections = net.forward()

bboxes = []

for i in range(detections.shape[2]):

confidence = detections[0, 0, i, 2]

if confidence > conf_threshold:

x1 = int(detections[0, 0, i, 3] * frameWidth)

y1 = int(detections[0, 0, i, 4] * frameHeight)

x2 = int(detections[0, 0, i, 5] * frameWidth)

y2 = int(detections[0, 0, i, 6] * frameHeight)

bboxes.append([x1, y1, x2, y2])

cv.rectangle(frameOpencvDnn, (x1, y1), (x2, y2), (0, 255, 0), int(round(frameHeight/150)), 8)

return frameOpencvDnn, bboxes

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

defgetFaceBox(net,frame,conf_threshold=0.7):

frameOpencvDnn=frame.copy()

frameHeight=frameOpencvDnn.shape[0]

frameWidth=frameOpencvDnn.shape[1]

blob=cv.dnn.blobFromImage(frameOpencvDnn,1.0,(300,300),[104,117,123],True,False)

net.setInput(blob)

detections=net.forward()

bboxes=[]

foriinrange(detections.shape[2]):

confidence=detections[0,0,i,2]

ifconfidence>conf_threshold:

x1=int(detections[0,0,i,3]*frameWidth)

y1=int(detections[0,0,i,4]*frameHeight)

x2=int(detections[0,0,i,5]*frameWidth)

y2=int(detections[0,0,i,6]*frameHeight)

bboxes.append([x1,y1,x2,y2])

cv.rectangle(frameOpencvDnn,(x1,y1),(x2,y2),(0,255,0),int(round(frameHeight/150)),8)

returnframeOpencvDnn,bboxes

2.2 预测性别

我们将性别网络加载到内存中,并通过网络传递检测到的面部。前向传递给出了两个类的概率或置信度。我们取两个输出的最大值并将其用作最终的性别预测。

string genderProto = "gender_deploy.prototxt";

string genderModel = "gender_net.caffemodel";

Net genderNet = readNet(genderModel, genderProto);

vector<string> genderList = {"Male", "Female"};

blob = blobFromImage(face, 1, Size(227, 227), MODEL_MEAN_VALUES, false);

genderNet.setInput(blob);

// string gender_preds;

vector<float> genderPreds = genderNet.forward();

// printing gender here

// find max element index

// distance function does the argmax() work in C++

int max_index_gender = std::distance(genderPreds.begin(), max_element(genderPreds.begin(), genderPreds.end()));

string gender = genderList[max_index_gender];

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

stringgenderProto="gender_deploy.prototxt";

stringgenderModel="gender_net.caffemodel";

NetgenderNet=readNet(genderModel,genderProto);

vector<string>genderList={"Male","Female"};

blob=blobFromImage(face,1,Size(227,227),MODEL_MEAN_VALUES,false);

genderNet.setInput(blob);

// string gender_preds;

vector<float>genderPreds=genderNet.forward();

// printing gender here

// find max element index

// distance function does the argmax() work in C++

intmax_index_gender=std::distance(genderPreds.begin(),max_element(genderPreds.begin(),genderPreds.end()));

stringgender=genderList[max_index_gender];

genderProto = "gender_deploy.prototxt"

genderModel = "gender_net.caffemodel"

ageNet = cv.dnn.readNet(ageModel, ageProto)

genderList = ['Male', 'Female']

blob = cv.dnn.blobFromImage(face, 1, (227, 227), MODEL_MEAN_VALUES, swapRB=False)

genderNet.setInput(blob)

genderPreds = genderNet.forward()

gender = genderList[genderPreds[0].argmax()]

print("Gender Output : {}".format(genderPreds))

print("Gender : {}".format(gender))

1

2

3

4

5

6

7

8

9

10

11

12

genderProto="gender_deploy.prototxt"

genderModel="gender_net.caffemodel"

ageNet=cv.dnn.readNet(ageModel,ageProto)

genderList=['Male','Female']

blob=cv.dnn.blobFromImage(face,1,(227,227),MODEL_MEAN_VALUES,swapRB=False)

genderNet.setInput(blob)

genderPreds=genderNet.forward()

gender=genderList[genderPreds[0].argmax()]

print("Gender Output : {}".format(genderPreds))

print("Gender : {}".format(gender))

2.3 预测年龄

我们加载年龄网络并使用正向传递来获得输出。由于网络架构类似于性别网络,我们可以从所有输出中获取最大值以获得预测年龄组。

string ageProto = "age_deploy.prototxt";

string ageModel = "age_net.caffemodel";

Net ageNet = readNet(ageModel, ageProto);

vector<string> ageList = {"(0-2)", "(4-6)", "(8-12)", "(15-20)", "(25-32)", "(38-43)", "(48-53)", "(60-100)"};

ageNet.setInput(blob);

vector<float> agePreds = ageNet.forward();

int max_indice_age = distance(agePreds.begin(), max_element(agePreds.begin(), agePreds.end()));

string age = ageList[max_indice_age];

1

2

3

4

5

6

7

8

9

10

stringageProto="age_deploy.prototxt";

stringageModel="age_net.caffemodel";

NetageNet=readNet(ageModel,ageProto);

vector<string>ageList={"(0-2)","(4-6)","(8-12)","(15-20)","(25-32)","(38-43)","(48-53)","(60-100)"};

ageNet.setInput(blob);

vector<float>agePreds=ageNet.forward();

intmax_indice_age=distance(agePreds.begin(),max_element(agePreds.begin(),agePreds.end()));

stringage=ageList[max_indice_age];

ageProto = "age_deploy.prototxt"

ageModel = "age_net.caffemodel"

ageNet = cv.dnn.readNet(ageModel, ageProto)

ageList = ['(0 - 2)', '(4 - 6)', '(8 - 12)', '(15 - 20)', '(25 - 32)', '(38 - 43)', '(48 - 53)', '(60 - 100)']

ageNet.setInput(blob)

agePreds = ageNet.forward()

age = ageList[agePreds[0].argmax()]

print("Gender Output : {}".format(agePreds))

print("Gender : {}".format(age))

1

2

3

4

5

6

7

8

9

10

11

ageProto="age_deploy.prototxt"

ageModel="age_net.caffemodel"

ageNet=cv.dnn.readNet(ageModel,ageProto)

ageList=['(0 - 2)','(4 - 6)','(8 - 12)','(15 - 20)','(25 - 32)','(38 - 43)','(48 - 53)','(60 - 100)']

ageNet.setInput(blob)

agePreds=ageNet.forward()

age=ageList[agePreds[0].argmax()]

print("Gender Output : {}".format(agePreds))

print("Gender : {}".format(age))

2.4 显示输出

我们将在输入图像上显示网络输出,并使用imshow功能显示它们。

string label = gender + ", " + age; // label

cv::putText(frameFace, label, Point(it->at(0), it->at(1) -20), cv::FONT_HERSHEY_SIMPLEX, 0.9, Scalar(0, 255, 255), 2, cv::LINE_AA);

imshow("Frame", frameFace);

1

2

3

stringlabel=gender+", "+age;// label

cv::putText(frameFace,label,Point(it->at(0),it->at(1)-20),cv::FONT_HERSHEY_SIMPLEX,0.9,Scalar(0,255,255),2,cv::LINE_AA);

imshow("Frame",frameFace);

label = "{}, {}".format(gender, age)

cv.putText(frameFace, label, (bbox[0], bbox[1]-20), cv.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 3, cv.LINE_AA)

cv.imshow("Age Gender Demo", frameFace)

1

2

3

label="{}, {}".format(gender,age)

cv.putText(frameFace,label,(bbox[0],bbox[1]-20),cv.FONT_HERSHEY_SIMPLEX,0.8,(255,0,0),3,cv.LINE_AA)

cv.imshow("Age Gender Demo",frameFace)

3.结果

我们在上面看到,网络能够将性别和年龄预测到高水平的准确性。接下来,我们想用这个模型做一些有趣的事情。许多演员都在电影中描绘了异性的角色。

我们想要检查一下AI在这些角色,以及他们是否能够欺骗AI。

我们使用了本文中的图像,这些图像显示了他们的实际照片以及他们改变性别的电影中的照片。我们来看一下。

除了Elle Fanning之外,其他所有人都能够用异性来愚弄人工智能。而且,仅从图像中预测名人年龄是非常困难的。

最后,让我们看看我们的模型预测我们在帖子开头的两个例子。

4. 观察

尽管性别预测网络表现良好,但年龄预测网络未达到我们的预期。我们试图在论文中找到答案,并为年龄预测模型找到以下混淆矩阵。

可以从上表中进行以下观察:

预测年龄组0-2,4-6,8-13和25-32具有相对高的准确度。(见对角线元素)

输出严重偏向25-32岁年龄组(参见属于25-32岁年龄组的行)。这意味着网络很容易在15到43岁之间混淆。因此,即使实际年龄在15-20或38-43之间,预测年龄很可能是25- 32。从结果部分也可以看出这一点。

除此之外,我们观察到如果我们在检测到的面部周围使用填充,模型的准确性会提高。这可能是由于以下事实:训练时的输入是标准面部图像,而不是我们在面部检测后得到的紧密裁剪的面部。

我们还在进行预测之前分析了面部对齐的使用,并发现某些示例的预测得到了改善,但与此同时,对某些人来说情况变得更糟。如果您主要使用非正面面部,那么使用对齐可能是个好主意。

5. 结论

总的来说,我认为模型的准确性是不错的,但可以通过使用更多数据,数据增强和更好的网络架构进一步改进。

如果有足够的数据可用,也可以尝试使用回归模型而不是年龄预测分类。

6. 参考文献

下载链接:

温馨提示: 此处内容需要 评论本文 后 刷新本页 才能查看!

本文最后更新于2019年11月11日,已超过 1 年没有更新,如果文章内容或图片资源失效,请留言反馈,我们会及时处理,谢谢!

python 数据结构转换层_[mcj]使用OpenCV深度学习进行性别和年龄分类(C++/Python)...相关推荐

  1. bert使用做文本分类_使用BERT进行深度学习的多类文本分类

    bert使用做文本分类 Most of the researchers submit their research papers to academic conference because its ...

  2. python机器人库_机器人之实战深度学习(上)OpenCV库

    本文主要向大家介绍了机器人之实战深度学习(上)OpenCV库,通过具体的内容向大家展现,希望对大家学习机器人有所帮助. 在如今人工智能的浪潮下,无数模拟机器学习和深度学习的开发者工具倍出,其中在计算机 ...

  3. Opencv 深度学习识别性别和检测年龄

    目录 1基于CNN的性别分类建模原理 1.1 人脸识别 1.2 性别预测 1.3 年龄预测 1.4 结果 2 代码 参考 本教程中,我们将讨论应用于面部的深层学习的有趣应用.我们将估计年龄,并从单个图 ...

  4. opencv 计数后不动了 训练模型时_用OpenCV,深度学习和Python进行年龄识别

    (给Python编程开发加星标,提升编程技能.) 在本教程中,您将学习如何使用OpenCV,深度学习和Python执行年龄的自动识别/预测. 学完本教程后,您将能够以相当高的精确度去自动预测静态图像文 ...

  5. opencv opencl加速_回放 | OpenCV Webinar 3:OpenCV深度学习应用与原理分析

    OpenCV DNN模块提供了深度学习的推理,支持Caffe.Tensoflow.Torch.Darknet.ONNX等格式的模型,无需用户安装对应的深度学习框架,也无需进行模型格式转换,直接调用DN ...

  6. Python深度学习:基于PyTorch [Deep Learning with Python and PyTorch]

    作者:吴茂贵,郁明敏,杨本法,李涛,张粤磊 著 出版社:机械工业出版社 品牌:机工出版 出版时间:2019-11-01 Python深度学习:基于PyTorch [Deep Learning with ...

  7. 超详细!使用OpenCV深度学习模块在图像分类下的应用实践

    专注计算机视觉前沿资讯和技术干货 微信公众号:极市平台 官网:https://www.cvmart.net/ 极市导读:本文来自6月份出版的新书<OpenCV深度学习应用与性能优化实践>, ...

  8. 回归素材(part9)--PYTHON机器学习手册-从数据预处理到深度学习

    学习笔记,仅供参考,有错必纠 PYTHON机器学习手册-从数据预处理到深度学习 通过正则化减少方差 我们可以使用岭回归或者Lasso回归,介绍回归模型的方差.

  9. 基于深度学习的手写数字识别、python实现

    基于深度学习的手写数字识别.python实现 一.what is 深度学习 二.加深层可以减少网络的参数数量 三.深度学习的手写数字识别 一.what is 深度学习 深度学习是加深了层的深度神经网络 ...

最新文章

  1. 【洛谷搜索专题Python和C++解】DFS和BFS经典题目(陆续补充)
  2. 使用Arduino模块实施无线信号的重放攻击
  3. Java 程序优化:字符串操作、基本运算方法等优化策略
  4. C# 编写Web API
  5. nw.js FrameLess Window下的窗口拖拽与窗口大小控制
  6. 蓝桥杯数字三角形java,蓝桥杯数字三角形(java)
  7. Ros基本概念及小乌龟程序学习
  8. mysql 求平方_如何用MySQL求一个范围内的完全平方数
  9. 搜狗关键词挖掘工具,搜狗权重关键词挖掘工具
  10. iOS面试开发-这样的简历才是面试官想看的
  11. 毕业设计3-BME280温湿度大气压传感器调试记录(STM32F103C8T6 + STM32CubeMX + BME280)
  12. 计算机桌面怎么改为d盘,WinXP桌面路径修改成D盘的步骤
  13. CSDN-markdown(文字加色加字号、背景色等)
  14. 安装Centos系统时选择安装的包
  15. 全网最全JAVA面试八股文,终于整理完了
  16. Android 自定义锁屏 监听系统消息推送
  17. 华为数字化转型之道第四讲
  18. Android连接网络打印机进行打印
  19. 前端可视化项目全国疫情地图
  20. Java length() 方法、length 属性和 size() 方法有什么区别?

热门文章

  1. 利用 Python 实现 K-means 算法
  2. JMX远程监视Java进程
  3. 麻省理工数学与计算机科学,美国留学MIT学子M专访
  4. 教你使用 Reflector中的Reflexil插件反编译.NET,修复Help Viewer v2.0 - Error: .cab未经Microsoft签名
  5. 基于STM32的BMP图片解码灰度化以及缩放
  6. PHP 7面向对象的全部文章(OOP)
  7. 程序员幸福感拉满:一键为代码自动生成注释的工具,拿走不谢!
  8. springMVC nodes
  9. python 爬取财经新闻股票_python 抓取新浪财经股票数据
  10. 各大排序算法实现及总结