如何使用OpenCV深度学习进行性别和年龄分类
bigegpt 2024-10-12 05:41 10 浏览
我们将讨论应用于面部的深度学习的有趣应用。我们将估计年龄并从单个图像中找出该人的性别。该模型由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.代码教程
代码可以分为四个部分:
检测面孔
检测性别
检测年龄
显示输出
注意:请下载未随代码一起提供的模型权重文件(性别,年龄)。下载文件并将其与本文提供的其他代码文件一起保存。
您可以使用提供的示例图像或使用网络摄像头运行代码。
C ++用法
#Using sample image ./AgeGender sample1.jpg
Python用法
#Using sample image python AgeGender.py --input sample1.jpg
2.1 检测脸部
我们将使用DNN人脸检测器进行人脸检测。该型号仅为2.7MB,即使在CPU上也非常快。关于脸部检测装置的更多细节可以在我们的博客上找到的人脸检测。使用函数getFaceBox完成面部检测,如下所示。
tuple<Mat, vector<vector<int>>> getFaceBox(Net net, Mat &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);
python
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
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];
python
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 预测年龄
我们加载年龄网络并使用正向传递来获得输出。由于网络架构类似于性别网络,我们可以从所有输出中取出最大值来获得预测年龄组。
C++
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];
python
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功能显示它们。
c++
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);
python
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。
我们使用了本文中的图像,这些图像显示了他们的实际照片以及他们改变性别的电影中的照片。我们来看一下。
所有人都能够用异性来愚弄人工智能。而且,仅从图像中预测名人时代是非常困难的
最后,让我们看看我们的模型预测我们在帖子开头的两个例子
4.数据
尽管性别预测网络表现良好,但年龄预测网络未达到我们的预期。我们试图在论文中找到答案,并为年龄预测模型找到以下混淆矩阵。
可以从上表中进行以下观察:
预测年龄组0-2,4-6,8-13和25-32具有相对高的准确度。(见对角线元素)
输出严重偏向25-32岁年龄组(参见属于25-32岁年龄组的行)。这意味着网络很容易在15到43岁之间混淆。因此,即使实际年龄在15-20或38-43之间,预测年龄很可能是25- 32。从结果部分也可以看出这一点。
除此之外,我们观察到如果我们在检测到的面部周围使用填充,模型的准确性会提高。这可能是由于以下事实:训练时的输入是标准面部图像,而不是我们在面部检测后得到的紧密裁剪的面部。
我们还在进行预测之前分析了面部对齐的使用,并发现某些示例的预测有所改善,但与此同时,对某些人来说情况变得更糟。如果您主要使用非正面面部,那么使用对齐可能是个好主意。
相关推荐
- 当Frida来“敲”门(frida是什么)
-
0x1渗透测试瓶颈目前,碰到越来越多的大客户都会将核心资产业务集中在统一的APP上,或者对自己比较重要的APP,如自己的主业务,办公APP进行加壳,流量加密,投入了很多精力在移动端的防护上。而现在挖...
- 服务端性能测试实战3-性能测试脚本开发
-
前言在前面的两篇文章中,我们分别介绍了性能测试的理论知识以及性能测试计划制定,本篇文章将重点介绍性能测试脚本开发。脚本开发将分为两个阶段:阶段一:了解各个接口的入参、出参,使用Python代码模拟前端...
- Springboot整合Apache Ftpserver拓展功能及业务讲解(三)
-
今日分享每天分享技术实战干货,技术在于积累和收藏,希望可以帮助到您,同时也希望获得您的支持和关注。架构开源地址:https://gitee.com/msxyspringboot整合Ftpserver参...
- Linux和Windows下:Python Crypto模块安装方式区别
-
一、Linux环境下:fromCrypto.SignatureimportPKCS1_v1_5如果导包报错:ImportError:Nomodulenamed'Crypt...
- Python 3 加密简介(python des加密解密)
-
Python3的标准库中是没多少用来解决加密的,不过却有用于处理哈希的库。在这里我们会对其进行一个简单的介绍,但重点会放在两个第三方的软件包:PyCrypto和cryptography上,我...
- 怎样从零开始编译一个魔兽世界开源服务端Windows
-
第二章:编译和安装我是艾西,上期我们讲述到编译一个魔兽世界开源服务端环境准备,那么今天跟大家聊聊怎么编译和安装我们直接进入正题(上一章没有看到的小伙伴可以点我主页查看)编译服务端:在D盘新建一个文件夹...
- 附1-Conda部署安装及基本使用(conda安装教程)
-
Windows环境安装安装介质下载下载地址:https://www.anaconda.com/products/individual安装Anaconda安装时,选择自定义安装,选择自定义安装路径:配置...
- 如何配置全世界最小的 MySQL 服务器
-
配置全世界最小的MySQL服务器——如何在一块IntelEdison为控制板上安装一个MySQL服务器。介绍在我最近的一篇博文中,物联网,消息以及MySQL,我展示了如果Partic...
- 如何使用Github Action来自动化编译PolarDB-PG数据库
-
随着PolarDB在国产数据库领域荣膺桂冠并持续获得广泛认可,越来越多的学生和技术爱好者开始关注并涉足这款由阿里巴巴集团倾力打造且性能卓越的关系型云原生数据库。有很多同学想要上手尝试,却卡在了编译数据...
- 面向NDK开发者的Android 7.0变更(ndk android.mk)
-
订阅Google官方微信公众号:谷歌开发者。与谷歌一起创造未来!受Android平台其他改进的影响,为了方便加载本机代码,AndroidM和N中的动态链接器对编写整洁且跨平台兼容的本机...
- 信创改造--人大金仓(Kingbase)数据库安装、备份恢复的问题纪要
-
问题一:在安装KingbaseES时,安装用户对于安装路径需有“读”、“写”、“执行”的权限。在Linux系统中,需要以非root用户执行安装程序,且该用户要有标准的home目录,您可...
- OpenSSH 安全漏洞,修补操作一手掌握
-
1.漏洞概述近日,国家信息安全漏洞库(CNNVD)收到关于OpenSSH安全漏洞(CNNVD-202407-017、CVE-2024-6387)情况的报送。攻击者可以利用该漏洞在无需认证的情况下,通...
- Linux:lsof命令详解(linux lsof命令详解)
-
介绍欢迎来到这篇博客。在这篇博客中,我们将学习Unix/Linux系统上的lsof命令行工具。命令行工具是您使用CLI(命令行界面)而不是GUI(图形用户界面)运行的程序或工具。lsoflsof代表&...
- 幻隐说固态第一期:固态硬盘接口类别
-
前排声明所有信息来源于网络收集,如有错误请评论区指出更正。废话不多说,目前固态硬盘接口按速度由慢到快分有这几类:SATA、mSATA、SATAExpress、PCI-E、m.2、u.2。下面我们来...
- 新品轰炸 影驰SSD多款产品登Computex
-
分享泡泡网SSD固态硬盘频道6月6日台北电脑展作为全球第二、亚洲最大的3C/IT产业链专业展,吸引了众多IT厂商和全球各地媒体的热烈关注,全球存储新势力—影驰,也积极参与其中,为广大玩家朋友带来了...
- 一周热门
- 最近发表
-
- 当Frida来“敲”门(frida是什么)
- 服务端性能测试实战3-性能测试脚本开发
- Springboot整合Apache Ftpserver拓展功能及业务讲解(三)
- Linux和Windows下:Python Crypto模块安装方式区别
- Python 3 加密简介(python des加密解密)
- 怎样从零开始编译一个魔兽世界开源服务端Windows
- 附1-Conda部署安装及基本使用(conda安装教程)
- 如何配置全世界最小的 MySQL 服务器
- 如何使用Github Action来自动化编译PolarDB-PG数据库
- 面向NDK开发者的Android 7.0变更(ndk android.mk)
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- resize函数 (64)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- mybatis大于等于 (64)
- xcode-select (66)
- mysql授权 (74)
- 下载测试 (70)
- linuxlink (65)
- pythonwget (67)
- androidinclude (65)
- libcrypto.so (74)
- logstashinput (65)
- hadoop端口 (65)
- vue阻止冒泡 (67)
- jquery跨域 (68)
- php写入文件 (73)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)