C++开发人脸性别识别教程(5)——通过FaceRecognizer类实现性别识别

2024-08-28 18:18

本文主要是介绍C++开发人脸性别识别教程(5)——通过FaceRecognizer类实现性别识别,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  在之前的博客中已经解决了人脸检测的问题,我们计划在这篇博客中介绍人脸识别、性别识别方面的相关实现方法。

  其实性别识别和人脸识别本质上是相似的,因为这里只是一个简单的MFC开发,主要工作并不在算法研究上,因此我们直接将性别识别视为一种特殊的人脸识别模式。人脸识别可能需要分为几十甚至上百个类(因为有几十甚至上百个人),而性别识别则是一种特殊的人脸识别——只有两个类。

  一、基本工具

  通过OpenCv进行性别识别的基本工具是FaceRecognizer。这是OpenCv2.x版本中的一个基本的人脸识别类,它封装了三种基本但也是经典的人脸识别算法:基于PCA变换的人脸识别(EigenFaceRecognizer)、基于Fisher变换的人脸识别(FisherFaceRecognizer)、基于局部二值模式的人脸识别(LBPHFaceRecognizer)。这些算法差不多都是十年以前的人脸识别方法了,因此在今天看来正确率应该不会太让人满意,不过我们这里重在实践,而非算法研究(虽然本人就是搞图像识别算法研究的),因此我们不会在算法创新方面下太多功夫,所以选择了这三个基本的识别算法。

  关于FaceRecognizer类人脸识别的详细操作,这里为大家推荐两篇博客:FaceRecognizer帮助文档以及FaceRecognizer。

  这里我们直接使用FaceRecognizer类的相关操作方法,对于其基本用法就不再赘述。

  二、数据集准备

  进行性别识别理所应当需要先准备一些性别识别方面的训练样本,需要强调的一点是,数据集的准备过程中也需要一些小的技巧,在之后我会专门写一篇博文来解释如何制作一个简易的性别识别训练集,这里我们直接用我已经做好的训练集,下载地址:性别识别数据集

  1、概况

  我这里整理的性别识别训练集是取自中科院的人脸数据库CAS-PEAL的光照子集,包含400张男性人脸图片和400张女性人脸图片,剩余人脸图片作为测试样本

  2、训练集基本结构

  训练集包含三部分:男性样本、女性样本、测试样本:

  这里我们通过CSV文件方法来批量读取训练样本,因此这里提前制作了一个txt文件来存储每一个训练样本图片的路径:

  注意这里at.txt文件中的路径实际上是由两部分内容组成,即“路径;性别标号”。性别标号“1”代表男性,“2”代表女性。至于如何通过csv文件方法来批量读取文件,参见:一种批量读取文件的方法—CSV文件。

  同理,在测试样本中同样需要用txt文件来记录样本路径和标签:

  三、识别算法的训练与测试

  1、新建一个控制台工程,配置OpenCv

  这里不再赘述,建议加上预编译头即可,这里工程名暂定为GenderRecognition

  2、编写批量读取文件函数read_csv()

  首先,批量txt文件是典型的io操作,需要包含以下头文件:

#include <iostream>
#include <sstream>
#include <fstream>

  然后开始编写read_csv函数,函数相对比较简单,这里直接给出代码:

void read_csv(string& fileName,vector<Mat>& images,vector<int>& labels,char separator = ';')
{ifstream file(fileName.c_str(),ifstream::in);    //以读入的方式打开文件String line,path,label;while (getline(file,line))                       //从文本文件中读取一行字符,未指定限定符默认限定符为“/n”{stringstream lines(line);getline(lines,path,separator);               //根据指定分割符进行分割,分为“路径+标号”getline(lines,label);if (!path.empty()&&!label.empty())           //如果读取成功,则将图片和对应标签压入对应容器中 {images.push_back(imread(path,1));        //读取训练样本labels.push_back(atoi(label.c_str()));   //读取训练样本标号}}
}

  read_csv()函数的主要功能就是读取指定目录下的路径文件(例如这里的at.txt),然后根据路径文件中的记录,逐行读入对应路径的训练样本路径及其标号,并放入对应容器(vector)中。至于为什么采用vector数据结构来存储训练样本,一是因为这样做简单直观,二是因为OpenCv的训练函数提供的是vector接口。当然这样做也存在一定弊端,就是必须一次性将训练样本全部读入到内存中,当训练样本数量庞大时这种方法不但会消耗掉巨额内存,而且效率低下。

  更多关于read_csv()批量读取的知识参见一种批量读取文件的方法—CSV文件。

  3、读入训练样本

  接下来在主函数中调用read_csv()函数,读取训练样本及标签,并放入对应容器中:

int _tmain(int argc, _TCHAR* argv[])
{String csvPath = "E:\\性别识别数据库—CAS-PEAL\\at.txt";vector<Mat> images;vector<int> labels;read_csv(csvPath,images,labels);return 0;
}

  读取成功,images和labels两个容器都包含800个样本:

  4、训练分类器

  OpenCv中的FaceRecognizer类提供的分类器训练API函数非常简单,只需三句话,以EigenFaceRecognizer为例:

    Ptr<FaceRecognizer> modelPCA = createEigenFaceRecognizer();modelPCA->train(images,labels);modelPCA->save("E:\\性别识别数据库—CAS-PEAL\\PCA_Model.xml");

  训练完成后(大约五分钟左右),训练好的分类器已经以XML文件的形式保存在了指定路径下:

   同理,训练FisherFaceRecognizer、LBPHFaceRecognizer两个分类器并保存:

    Ptr<FaceRecognizer> modelFisher = createFisherFaceRecognizer();modelFisher->train(images,labels);modelFisher->save("E:\\性别识别数据库—CAS-PEAL\\Fisher_Model.xml");Ptr<FaceRecognizer> modelLBP = createLBPHFaceRecognizer();modelLBP->train(images,labels);modelLBP->save("E:\\性别识别数据库—CAS-PEAL\\LBP_Model.xml");

  得到另外两个分类器:

  4、测试分类器

  训练完分类器后,接下来我们介绍如何使用这些训练好的分类器对测试样本进行分类。首先加载三个分类器

    Ptr<FaceRecognizer> modelPCA = createEigenFaceRecognizer();Ptr<FaceRecognizer> modelFisher = createFisherFaceRecognizer();Ptr<FaceRecognizer> modelLBP = createLBPHFaceRecognizer();modelPCA->load("E:\\性别识别数据库—CAS-PEAL\\PCA_Model.xml");modelFisher->load("E:\\性别识别数据库—CAS-PEAL\\Fisher_Model.xml");modelLBP->load("E:\\性别识别数据库—CAS-PEAL\\LBP_Model.xml");

  然后读入一张测试样本,通过三个分类器对其进行预测:

    Mat testImage = imread("E:\\性别识别数据库—CAS-PEAL\\测试样本\\男性测试样本\\face_480.bmp",0);int predictPCA = modelPCA->predict(testImage);int predictLBP = modelLBP->predict(testImage);int predictFisher = modelFisher->predict(testImage);

  预测结果如图:

  可见对于这张测试图片,三个分类器均给出了正确预测(数字“1”代表男性),正确率可以接受。

  四、代码

  这部分博客所涉及的代码同样较为简洁,因此在这里给出整体代码:

// GenderRecognition.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <opencv2\opencv.hpp>
#include <iostream>
#include <sstream>
#include <fstream>using namespace std;
using namespace cv;void read_csv(string& fileName,vector<Mat>& images,vector<int>& labels,char separator = ';')
{ifstream file(fileName.c_str(),ifstream::in);    //以读入的方式打开文件String line,path,label;while (getline(file,line))                       //从文本文件中读取一行字符,未指定限定符默认限定符为“/n”{stringstream lines(line);getline(lines,path,separator);               //根据指定分割符进行分割,分为“路径+标号”getline(lines,label);if (!path.empty()&&!label.empty())           //如果读取成功,则将图片和对应标签压入对应容器中 {images.push_back(imread(path,0));        //读取训练样本labels.push_back(atoi(label.c_str()));   //读取训练样本标号}}
}int _tmain(int argc, _TCHAR* argv[])
{String csvPath = "E:\\性别识别数据库—CAS-PEAL\\at.txt";vector<Mat> images;vector<int> labels;read_csv(csvPath,images,labels);Ptr<FaceRecognizer> modelPCA = createEigenFaceRecognizer();modelPCA->train(images,labels);modelPCA->save("E:\\性别识别数据库—CAS-PEAL\\PCA_Model.xml");Ptr<FaceRecognizer> modelFisher = createFisherFaceRecognizer();modelFisher->train(images,labels);modelFisher->save("E:\\性别识别数据库—CAS-PEAL\\Fisher_Model.xml");Ptr<FaceRecognizer> modelLBP = createLBPHFaceRecognizer();modelLBP->train(images,labels);modelLBP->save("E:\\性别识别数据库—CAS-PEAL\\LBP_Model.xml");//Ptr<FaceRecognizer> modelPCA = createEigenFaceRecognizer();//Ptr<FaceRecognizer> modelFisher = createFisherFaceRecognizer();//Ptr<FaceRecognizer> modelLBP = createLBPHFaceRecognizer();modelPCA->load("E:\\性别识别数据库—CAS-PEAL\\PCA_Model.xml");modelFisher->load("E:\\性别识别数据库—CAS-PEAL\\Fisher_Model.xml");modelLBP->load("E:\\性别识别数据库—CAS-PEAL\\LBP_Model.xml");Mat testImage = imread("E:\\性别识别数据库—CAS-PEAL\\测试样本\\男性测试样本\\face_480.bmp",0);int predictPCA = modelPCA->predict(testImage);int predictLBP = modelLBP->predict(testImage);int predictFisher = modelFisher->predict(testImage);return 0;
}

  四、总结

  这篇博客主要介绍了如何使用OpenCv提供的人脸识别类FaceRecognizer来进行性别识别,并提供了一段win32控制台工程下的简洁代码,同时,有以下几个方面需要特别注意一下。

  1、人脸识别和性别识别的关系

  在这篇博客的开始部分曾提到过性别识别和人脸识别的关系,在这里需要再次强调一下。性别识别本质上属于人脸识别,但是和人脸识别还是有很多方面的区别。性别识别是二分类问题,人脸识别是多分类问题,二者在算法上也有很大差异。我们这里之所以简单的将性别识别看做简化的人脸识别,是因为在这套教程中我们主要注重实践,注重OpenCv的使用以及MFC框架编程方法,因此在算法方面会显得不够严谨。因此希望大家不要被这些简化的观点所误导,真正的性别识别算法也远比这些复杂,也和人脸识别方法大不相同,作为图像处理的行内人,我觉得很有必要把这点说清楚。

  2、read_csv函数

  这里对read_csv()批量读取函数介绍得相对简洁,大家可以参照我提供的博客来进行详细学习,同时考虑到这个函数相对简洁,可以凡在main()函数之前,从而避免提前声明。

  3、数据集原始路径问题

  这篇博文中并没有详细介绍如何制作性别识别训练数据集,因此大家在使用网上下载的数据集时一定要注意路径的问题。下载后数据集必须放在E盘根目录下,否则的话则需要重新制作路径文件(at.txt),不过这一步也并不复杂,参见一种批量读取文件的方法—CSV文件。

  同时,这里在向路径文件后边添加类别标号时,当初我采用的是手动添加的方式,不过我相信大家能够找到更为简便的添加方式。

  这里之所以没有介绍数据集的制作,是因为我计划将这部分内容作为程序的一个附加功能来单独进行介绍(也就是所谓的“人脸批量分割”),在之后进入到MFC编程部分时会进行专门的介绍。

  4、关于性别识别的其他方法

  在接下来的博文中我会介绍性别识别中的另外一种基础方法——SVM方法。

 

这篇关于C++开发人脸性别识别教程(5)——通过FaceRecognizer类实现性别识别的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1115523

相关文章

Redis客户端连接机制的实现方案

《Redis客户端连接机制的实现方案》本文主要介绍了Redis客户端连接机制的实现方案,包括事件驱动模型、非阻塞I/O处理、连接池应用及配置优化,具有一定的参考价值,感兴趣的可以了解一下... 目录1. Redis连接模型概述2. 连接建立过程详解2.1 连php接初始化流程2.2 关键配置参数3. 最大连

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

python设置环境变量路径实现过程

《python设置环境变量路径实现过程》本文介绍设置Python路径的多种方法:临时设置(Windows用`set`,Linux/macOS用`export`)、永久设置(系统属性或shell配置文件... 目录设置python路径的方法临时设置环境变量(适用于当前会话)永久设置环境变量(Windows系统

C++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

PyQt5 GUI 开发的基础知识

《PyQt5GUI开发的基础知识》Qt是一个跨平台的C++图形用户界面开发框架,支持GUI和非GUI程序开发,本文介绍了使用PyQt5进行界面开发的基础知识,包括创建简单窗口、常用控件、窗口属性设... 目录简介第一个PyQt程序最常用的三个功能模块控件QPushButton(按钮)控件QLable(纯文本

PyCharm中配置PyQt的实现步骤

《PyCharm中配置PyQt的实现步骤》PyCharm是JetBrains推出的一款强大的PythonIDE,结合PyQt可以进行pythion高效开发桌面GUI应用程序,本文就来介绍一下PyCha... 目录1. 安装China编程PyQt1.PyQt 核心组件2. 基础 PyQt 应用程序结构3. 使用 Q

2025版mysql8.0.41 winx64 手动安装详细教程

《2025版mysql8.0.41winx64手动安装详细教程》本文指导Windows系统下MySQL安装配置,包含解压、设置环境变量、my.ini配置、初始化密码获取、服务安装与手动启动等步骤,... 目录一、下载安装包二、配置环境变量三、安装配置四、启动 mysql 服务,修改密码一、下载安装包安装地