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

目录

1基于CNN的性别分类建模原理

1.1 人脸识别

1.2 性别预测

1.3 年龄预测

1.4 结果

2 代码

参考


本教程中,我们将讨论应用于面部的深层学习的有趣应用。我们将估计年龄,并从单个图像中找出该人的性别。模型由GilLevi和TalHassner训练(https://talhassner.github.io/home/publication/2015_CVPR)。本文介绍了如何在OpenCV中使用该模型的步骤说明。Opencv版本3.4.3以上。代码教程代码可以分为四个部分:

1基于CNN的性别分类建模原理

作者使用非常简单的卷积神经网络结构,类似于Caffenet和Alexnet。网络使用3个卷积层、2个全连接层和一个最终的输出层。下面给出了这些层的细节。COV1:第一卷积层具有96个内核大小7的节点。COV2:第二个卷积层Conv层具有256个具有内核大小5的节点。CONV3:第三个CONV层具有384个内核大小为3的节点。两个完全连接的层各自具有512个节点。

训练数据来源:https://talhassner.github.io/home/projects/Adience/Adience-data.html

检测程序主要有四块:检测人脸检测、性别检测、年龄显示和输出。

1.1 人脸识别

我们将使用人脸检测器(tensorflow模型)进行人脸检测。该模型很简单,即使在CPU上也是相当快的。详细见论文:

https://arxiv.org/pdf/1502.00046.pdf

1.2 性别预测

将性别预测设定为一个分类问题。性别预测网络(caffe模型)中的输出层类型为两类,2个节点表示“男性”和“女性”两类。以这两个输出的最大值作为最终的性别。

1.3 年龄预测

理想情况下,年龄预测应该作为一个回归问题来处理。然而通过回归准确估计年龄是很有挑战性的。即使是人类也无法通过观察一个人来准确预测年龄。但是我们能够知道他们是20多岁还是30多岁。由于这个原因,把这个问题描述为一个分类问题是明智的,因为我们试图估计这个人所处的年龄组。例如,0-2范围内的年龄是一个类,4-6是另一个类,依此类推。因此数据集分为以下8个年龄组[(0-2)、(4-6)、(8-12)、(15-20)、(25-32)、(38-43)、(48-53)、(60-100)]。因此,年龄预测网络在最后一层有8个节点,表示所述年龄范围。

应该记住,从一幅图像中预测年龄并不是一个很容易解决的问题,因为感知到的年龄取决于许多因素,而同龄的人在世界各地可能看起来很不一样。而且,人们非常努力地隐藏他们的真实年龄!

我们加载年龄网络(caffe模型)并使用前向通道获得输出。由于网络结构类似于性别网络,所以我们可以从所有输出中提取出最大值来得到预测的年龄组

1.4 结果

尽管性别预测网络表现良好,但年龄预测网络仍未达到我们的预期。所以添加人脸对齐算法或者数据样本很多时候,可以通过回归的模型来检测。但是性别人脸检测还是很准确的。

2 代码

在VS2017下运行了C++代码,其中OpenCV版本至少要3.4.5以上。不然模型读取会有问题。三个模型文件太大,见下载链接:

https://download.csdn.net/download/luohenyj/10993309

https://github.com/luohenyueji/OpenCV-Practical-Exercise

如果没有积分(系统自动设定资源分数)看看参考链接。我搬运过来的,大修改没有。

其中tensorflow和caffe模型都可以用opencv中的readnet函数读取,流程很简单。看看代码就会。

代码提供了C++和Python版本,但是python版本没有运行,原因opencv版本太低,不想升级。代码都有详细的注释。

C++版本:


#include <tuple>#include <iostream>#include <opencv2/opencv.hpp>#include <opencv2/dnn.hpp>#include <iterator>using namespace cv;using namespace cv::dnn;using namespace std;/*** @brief Get the Face Box object 人脸定位** @param net 人脸检测网络* @param frame 检测图像* @param conf_threshold 阈值* @return tuple<Mat, vector<vector<int>>> 元组容器,可返回多个值*/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;inputBlob = cv::dnn::blobFromImage(frameOpenCVDNN, 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);}int main(void){//人脸模型string faceProto = "model/opencv_face_detector.pbtxt";string faceModel = "model/opencv_face_detector_uint8.pb";//年龄模型string ageProto = "model/age_deploy.prototxt";string ageModel = "model/age_net.caffemodel";//性别模型string genderProto = "model/gender_deploy.prototxt";string genderModel = "model/gender_net.caffemodel";//均值Scalar MODEL_MEAN_VALUES = Scalar(78.4263377603, 87.7689143744, 114.895847746);//年龄段标签vector<string> ageList = { "(0-2)", "(4-6)", "(8-12)", "(15-20)", "(25-32)","(38-43)", "(48-53)", "(60-100)" };//性别标签vector<string> genderList = { "Male", "Female" };//导入网络Net ageNet = cv::dnn::readNet(ageProto, ageModel);Net genderNet = cv::dnn::readNet(genderProto, genderModel);Net faceNet = cv::dnn::readNetFromTensorflow(faceModel, faceProto);//打开摄像头VideoCapture cap;cap.open(0);if (cap.isOpened()){cout << "camera is opened!" << endl;}else{return 0;}int padding = 20;while (waitKey(1) < 0){// read frame 读图Mat frame;cap.read(frame);if (frame.empty()){waitKey();break;}frame = imread("./images/couple1.jpg");//人脸坐标vector<vector<int>> bboxes;//人脸检测结果图Mat frameFace;//人脸定位//tie()函数解包frameFace和bboxestie(frameFace, bboxes) = getFaceBox(faceNet, frame, 0.7);//人脸判断if (bboxes.size() == 0){cout << "No face detected, checking next frame." << endl;continue;}//逐个提取人脸检测for (auto it = begin(bboxes); it != end(bboxes); ++it){//框选人脸Rect rec(it->at(0) - padding, it->at(1) - padding, it->at(2) - it->at(0) + 2 * padding, it->at(3) - it->at(1) + 2 * padding);//避免人脸框选超过图像边缘rec.width = ((rec.x + rec.width) > frame.cols) ? (frame.cols - rec.x - 1) : rec.width;rec.height = ((rec.y + rec.height) > frame.rows) ? (frame.rows - rec.y - 1) : rec.height;// take the ROI of box on the frame,原图中提取人脸Mat face = frame(rec);//性别检测Mat blob;blob = blobFromImage(face, 1, Size(227, 227), MODEL_MEAN_VALUES, false);genderNet.setInput(blob);// string gender_preds; 获取前向传播softmax结果vector<float> genderPreds = genderNet.forward();// find max element index max_element用于找寻最大值// distance function does the argmax() work in C++ distance返回最大值和第一个值下标的距离int max_index_gender = std::distance(genderPreds.begin(), max_element(genderPreds.begin(), genderPreds.end()));//获得检测结果string gender = genderList[max_index_gender];cout << "Gender: " << gender << endl;//年龄识别ageNet.setInput(blob);vector<float> agePreds = ageNet.forward();// finding maximum indicd in the age_preds vector 找到年龄预测最大下表int max_indice_age = std::distance(agePreds.begin(), max_element(agePreds.begin(), agePreds.end()));string age = ageList[max_indice_age];cout << "Age: " << age << endl;// label 输出标签string label = gender + ", " + age;//在人脸定位图上显示结果cv::putText(frameFace, label, Point(it->at(0), it->at(1) - 15), cv::FONT_HERSHEY_SIMPLEX, 0.9, Scalar(0, 255, 255), 2, cv::LINE_AA);}//保存结果imshow("Frame", frameFace);imwrite("out.jpg", frameFace);}}

python版本:


# Import required modulesimport cv2 as cvimport timeimport argparsedef 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, bboxesparser = argparse.ArgumentParser(description='Use this script to run age and gender recognition using OpenCV.')parser.add_argument('--input', help='Path to input image or video file. Skip this argument to capture frames from a camera.')args = parser.parse_args()faceProto = "age_gender/model/opencv_face_detector.pbtxt"faceModel = "age_gender/model/opencv_face_detector_uint8.pb"ageProto = "age_gender/model/age_deploy.prototxt"ageModel = "age_gender/model/age_net.caffemodel"genderProto = "age_gender/model/gender_deploy.prototxt"genderModel = "age_gender/model/gender_net.caffemodel"MODEL_MEAN_VALUES = (78.4263377603, 87.7689143744, 114.895847746)ageList = ['(0-2)', '(4-6)', '(8-12)', '(15-20)', '(25-32)', '(38-43)', '(48-53)', '(60-100)']genderList = ['Male', 'Female']# Load networkageNet = cv.dnn.readNet(ageModel, ageProto)genderNet = cv.dnn.readNet(genderModel, genderProto)faceNet = cv.dnn.readNet(faceModel, faceProto)# Open a video file or an image file or a camera streamcap = cv.VideoCapture(args.input if args.input else 0)padding = 20while cv.waitKey(1) < 0:# Read framet = time.time()hasFrame, frame = cap.read()if not hasFrame:cv.waitKey()breakframeFace, bboxes = getFaceBox(faceNet, frame)if not bboxes:print("No face Detected, Checking next frame")continuefor bbox in bboxes:# print(bbox)face = frame[max(0,bbox[1]-padding):min(bbox[3]+padding,frame.shape[0]-1),max(0,bbox[0]-padding):min(bbox[2]+padding, frame.shape[1]-1)]blob = cv.dnn.blobFromImage(face, 1.0, (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 : {}, conf = {:.3f}".format(gender, genderPreds[0].max()))ageNet.setInput(blob)agePreds = ageNet.forward()age = ageList[agePreds[0].argmax()]print("Age Output : {}".format(agePreds))print("Age : {}, conf = {:.3f}".format(age, agePreds[0].max()))label = "{},{}".format(gender, age)cv.putText(frameFace, label, (bbox[0], bbox[1]-10), cv.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2, cv.LINE_AA)cv.imshow("Age Gender Demo", frameFace)# cv.imwrite("age-gender-out-{}".format(args.input),frameFace)print("time : {:.3f}".format(time.time() - t))

参考

https://www.learnopencv.com/age-gender-classification-using-opencv-deep-learning-c-python/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/547246.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Golang类型转换

类型转换 1、int转string strconv.Itoa(i)2、string转int i, err strconv.Atoi(s) 或者 i, err ParseInt(s, 10, 0) 3、string转float f, err ParseFloat(s, 32) 4、用户结构类型转换 userinfo : this.GetSession("userinfo")if userinfo nil {return}user : …

include和require区别

很多时候需要函数重用&#xff0c;引用其他文件中的函数。这时候就用到了以下几种方式。 include和require的区别&#xff1a; includerequire引用时在使用时候加载在初始时加载异常如果加载的文件不存在会报出一个警告程序继续运行加载的文件不存在会报出一个致命的错误 使用…

Ubuntu设置国内阿里云镜像源,加速apt-get下载速度

在VM虚拟机中安装了Ubuntu16.04LTS系统&#xff0c;通过apt或apt-get命令安装包&#xff0c;下载速度很慢&#xff0c;因为系统自带的下载源的服务器在国外。可以将下载源切换为国内的镜像源&#xff0c;比如说阿里云镜像&#xff0c;https://developer.aliyun.com/mirror/ubun…

结构体和联合体

结构体&#xff1a; 8个为一个内存地址 依次向下 联合体&#xff1a; 共用一块内存地址 调试可以gcc -g -o输出编译。然后gdb执行 d打断点。n下一行。p输出。查看每一个所占的内存地址 宏定义和使用 #define 宏名称 “实现什么东西” 大小端 可以自行判断自己电脑 摘自…

PowerDesigner导出Report通用报表

PowerDesigner导出Report通用报表 通用模板下载地址&#xff1a;http://pan.baidu.com/s/1c0NDphm

Log4j的应用实例

建一张表&#xff0c;如下&#xff1a; create table log4j( logId int not null auto_increment,--流水号 createDate varchar(45) default null,--日志生成时间 thread varchar(45) default null,--当前线程 level varchar(45) default null,--当前日志的级别 …

python-视频分帧多帧合成视频

1.视频分帧&#xff1a; import cv2vidcap cv2.VideoCapture(005.avi)success,image vidcap.read()count 0success Truewhile success:success,image vidcap.read()cv2.imwrite("frame%d.jpg" % count, image) # save frame as JPEG fileif cv2.waitKey(10) …

Mysql5.0没有nvarchar,national

mysql采用utf-8编码,而传统的数据库采用unicode,一个汉字要用两个unicode的char,而在mysql中由于使用了utf-8,所以无论汉字还是字母,都是一个长度的char,所以就不用分nvarhcar和varchar了,一律作varchar

搭建nginx+php后访问不到项目

记在虚拟机搭建phpnginxmysql踩到的坑 首先因为工作原因&#xff0c;离开了上家公司&#xff0c;然后入职xx后&#xff0c;由于没有开发机只能自己搭建了一个虚拟机 搭建好后使用一键安装式工具安装了lnmp环境 之后访问nginx是可以访问通的&#xff0c;但是指定了项目目录却访问…

AgileEAS.NET SOA 中间件平台.Net Socket通信框架-完整应用例子-在线聊天室系统-代码解析...

一、AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台.Net Socket通信框架-介绍一文之中我们对AgileEAS.NET SOA中间Socket/Tcp框架进行了总体的介绍&#xff0c;我们知道 AgileEAS.NET SOA中间件Socket/Tcp框架是一套Socket通信的消息中间件&…

小程序如何跳转到各大电商小程序进行CPS赚钱

小程序系统广告门槛高&#xff0c;流量主费用低&#xff0c;个人开发者难以变现。电商CPS也是一种不错的变现方式&#xff0c;在自己的小程序内添加购物优惠导航入口。自己小程序的用户通过导航跳转到电商平台&#xff0c;进行购物&#xff0c;购物完成结算后&#xff0c;作为开…

mysql default unix_timestamp(now())

按照mssql的创建方式&#xff0c;去创建mysql的默认值时间戳是不能被允许的&#xff0c;例如下面代码&#xff1a; CREATE TABLE USERINFO(CREATETIME INT NOT NULL DEFAULT UNIX_TIMESTAMP())是不能被通过的&#xff0c;因为mysql默认值只能支持常量&#xff0c;变量的不被允许…

安装composer以及laravel框架

Linux系统下安装laravel框架 在linux系统下安装laravel&#xff1a; 1.下载到windows系统下&#xff0c;使用FTP(FileZilla是一种快速、可信赖的FTP客户端以及服务器端开放源代码程式&#xff0c;具有多种特色、直接的接口。FileZilla在2002年11月获选为当月最佳推荐专案.)上传…

创业型软件公司的心得

我在两家创业公司工作过。A公司&#xff0c;由3人发展到20人&#xff1b;B公司&#xff0c;由20人发展到60人。这两家公司都不算成功&#xff0c;因此&#xff0c;要讲收获&#xff0c;更多的是经验与教训。就如同教材一样&#xff0c;反面教材更加有教育意义。我针对创业公司面…

NPM使用前设置和升级

升级版本npm3和切换模块数据源为taobao&#xff0c;大大提高下载速度。 步骤一&#xff1a;升级npm3默认npm为2.x推荐使用npm3. npm i -g npm3 步骤二&#xff1a;修改npm数据源为taobao&#xff08;默认国外数据源&#xff0c;性能非常低&#xff09; npm config set registry…

200多套微信小程序源码带后台+教程+源码

去下面论坛找更多 http://bbs.raydonet.com/forum.php 微信小程序疯狂猜成语小程序源码UI美观 知识答题类小程序源码 200多套微信小程序源码带后台教程源码 校园小情书小程序前端后端源码 微信版flappybird小游戏源码下载&#xff0c;经典像素鸟小游戏源码 [小游戏源码] …

java中关于length的真确理解~~~~有补充的请跟帖~~~

java中的length到底是个什么东西呢&#xff1f;有人说它是一个类&#xff0c;一个方法&#xff0c;如果是方法&#xff0c;它没有括号&#xff0c; 我只知道它可以得出数组的长度&#xff0c;但是今天遇到一段代码&#xff0c;怎么都解释不通&#xff0c;那就是绝对不会把循环的…

es6分享——变量的解构赋值

变量的解构赋值&#xff1a;ES6 允许按照一定模式&#xff0c;从数组和对象中提取值&#xff0c;对变量进行赋值&#xff0c;这被称为解构&#xff08;Destructuring&#xff09;。 以前的写法&#xff1a; var a 1;var b 2;es6允许的写法&#xff1a; let [a,b] [1,2];一般…

Python Windows发出警报声、蜂鸣器、声音报警

在Windows上 import winsound duration 1000 # millisecond freq 1440 # Hz winsound.Beep(freq, duration) 其中&#xff0c;FREQ是频率(以赫兹为单位)&#xff0c;而持续时间是毫秒(毫秒)。 在Linux(和Mac)上 import os duration 1 # second freq 1440 # Hz os.s…

es6新特性分享

1、字符串查找es5使用是indexOf() 返回字符第一次出现的位置int值es6新增了3个方法&#xff1a;includes()/startsWith()/endWith()返回bool值includes > 是否包含字符startsWith > 首字母是否包含字符endWith > 末尾是否包含字符 2、数值扩展Number.isInteger() >…