叙述性说明

所谓的性别识别推断检测到的面部是男性还是女性。它是一个二值分类问题。

识别算法可以用于SVM,BP神经网络。LDA,PCA,PCA+LDA等等。OpenCV官网给出的文档是基于Fisherfaces检測器(LDA)方法实现的。链接:http://docs.opencv.org/modules/contrib/doc/facerec/tutorial/facerec_gender_classification.html#id5 。这篇博文(http://www.bytefish.de/blog/gender_classification/)中也是採用OpenCV官网的方法。据称有98%的正确率,我在百度图片找了一些数据測试了下,仅仅有大概50%多的识别率。原因是他的数据集是经过严格标定的。好像是眼睛的是对齐的。

实际应用中不太可能会遇到这样的情况吧。CSDN还有两篇博客也介绍到这个性格识别(http://blog.csdn.net/kklots/article/details/8247738 http://blog.csdn.net/kklots/article/details/9285505)文章写得非常好,一看就是大牛。博文中也是測试了LDA的方法,正确率也是出奇的低。採用的是PCA+LDA的方法。通过改进能达到接近90%的正确率。

博文指出PCA+LDA比单纯的LDA和PCA识别率都高,但我对博文中的PCA+LDA程序和官网的PCA程序測试了下,发现PCA的正确率会高那么一两个点。难道又是数据的问题?

数据

採集数据一方面能够採用开源的人脸库。还有一方面能够自己去百度图片下载图片。去百度或谷歌图片分别搜索“男明星头像”“女明星头像”的关键字批量下载。这里当然须要批量下载利器。

然后利用人脸检測器过滤检測出头像,然后归一化检測出来的图像,保存在本地。这样主要的数据集就有了。

当然我也会附上我採集的数据和工程文件(特此声明,全部图片均来自网络)

測试程序

创建CSV文件的python代码:

import sys
import os.path if __name__ == "__main__": if len(sys.argv) != 3:
print "usage: create_csv <base_path> <SAVE_FILE_NAME>"
sys.exit(1) BASE_PATH=sys.argv[1]
FILE_NAME = sys.argv[2]
SEPARATOR=";"
fh = open(FILE_NAME,'w') label = 0
for dirname, dirnames, filenames in os.walk(BASE_PATH):
for subdirname in dirnames:
subject_path = os.path.join(dirname, subdirname)
for filename in os.listdir(subject_path):
abs_path = "%s/%s" % (subject_path, filename)
##print "%s%s%d" % (abs_path, SEPARATOR, label)
##print "%s %s" % (dirname, subject_path) fh.write(abs_path)
fh.write(SEPARATOR)
if dirname.find("female") > 0 :
label = 1
else:
label = 0
fh.write(str(label))
fh.write("\n")
fh.close()

測试性别识别的程序

// gender.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <fstream>
#include <sstream>
#include <math.h>
int g_howManyPhotoForTraining = 260;
//每一个人取出8张作为训练
int g_photoNumberOfOnePerson = 279;
//ORL数据库每一个人10张图像
using namespace cv;
using namespace std; static Mat norm_0_255(InputArray _src) {
Mat src = _src.getMat();
// 创建和返回一个归一化后的图像矩阵:
Mat dst;
switch(src.channels()) {
case1:
cv::normalize(_src, dst, 0,255, NORM_MINMAX, CV_8UC1);
break;
case3:
cv::normalize(_src, dst, 0,255, NORM_MINMAX, CV_8UC3);
break;
default:
src.copyTo(dst);
break;
}
return dst;
}
//使用CSV文件去读图像和标签,主要使用stringstream和getline方法
static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator =';') {
std::ifstream file(filename.c_str(), ifstream::in);
if (!file) {
string error_message ="No valid input file was given, please check the given filename.";
CV_Error(CV_StsBadArg, error_message);
}
string line, path, classlabel;
while (getline(file, line)) {
stringstream liness(line);
getline(liness, path, separator);
getline(liness, classlabel);
if(!path.empty()&&!classlabel.empty()) {
images.push_back(imread(path, 0));
labels.push_back(atoi(classlabel.c_str()));
}
}
} void train_and_test_lda()
{
string fn_csv = string("at.txt");
//string fn_csv = string("feret.txt");
vector<Mat> allImages,train_images,test_images;
vector<int> allLabels,train_labels,test_labels;
try {
read_csv(fn_csv, allImages, allLabels);
} catch (cv::Exception& e) {
cerr <<"Error opening file "<< fn_csv <<". Reason: "<< e.msg << endl;
// 文件有问题,我们啥也做不了了。退出了
exit(1);
}
if(allImages.size()<=1) {
string error_message ="This demo needs at least 2 images to work. Please add more images to your data set!";
CV_Error(CV_StsError, error_message);
} for(int i=0 ; i<allImages.size() ; i++)
equalizeHist(allImages[i],allImages[i]); int photoNumber = allImages.size();
for(int i=0 ; i<photoNumber ; i++)
{
if((i%g_photoNumberOfOnePerson)<g_howManyPhotoForTraining)
{
train_images.push_back(allImages[i]);
train_labels.push_back(allLabels[i]);
}
else
{
test_images.push_back(allImages[i]);
test_labels.push_back(allLabels[i]);
}
} /*Ptr<FaceRecognizer> model = createEigenFaceRecognizer();//定义pca模型
model->train(train_images, train_labels);//训练pca模型。这里的model包括了全部特征值和特征向量。没有损失
model->save("eigenface.yml");//保存训练结果。供检測时使用 */ Ptr<FaceRecognizer> fishermodel = createFisherFaceRecognizer();
fishermodel->train(train_images,train_labels);//用保存的降维后的图片来训练fishermodel,后面的内容与原始代码就没什么变化了
fishermodel->save("fisherlda.yml");
int iCorrectPrediction = 0;
int predictedLabel;
int testPhotoNumber = test_images.size();
for(int i=0;i<testPhotoNumber;i++)
{
predictedLabel = fishermodel->predict(test_images[i]);
if(predictedLabel == test_labels[i])
iCorrectPrediction++;
}
string result_message = format("Test Number = %d / Actual Number = %d.", testPhotoNumber, iCorrectPrediction);
cout << result_message << endl;
cout<<"accuracy = "<<float(iCorrectPrediction)/testPhotoNumber<<endl;
} void train_and_test_pca()
{
string fn_csv = string("at.txt");
//string fn_csv = string("feret.txt");
vector<Mat> allImages,train_images,test_images;
vector<int> allLabels,train_labels,test_labels;
try {
read_csv(fn_csv, allImages, allLabels);
} catch (cv::Exception& e) {
cerr <<"Error opening file "<< fn_csv <<". Reason: "<< e.msg << endl;
// 文件有问题。我们啥也做不了了,退出了
exit(1);
}
if(allImages.size()<=1) {
string error_message ="This demo needs at least 2 images to work. Please add more images to your data set!";
CV_Error(CV_StsError, error_message);
} for(int i=0 ; i<allImages.size() ; i++)
equalizeHist(allImages[i],allImages[i]); int photoNumber = allImages.size();
for(int i=0 ; i<photoNumber ; i++)
{
if((i%g_photoNumberOfOnePerson)<g_howManyPhotoForTraining)
{
train_images.push_back(allImages[i]);
train_labels.push_back(allLabels[i]);
}
else
{
test_images.push_back(allImages[i]);
test_labels.push_back(allLabels[i]);
}
} Ptr<FaceRecognizer> model = createEigenFaceRecognizer();//定义pca模型
model->train(train_images, train_labels);//训练pca模型,这里的model包括了全部特征值和特征向量。没有损失
model->save("eigenfacepca.yml");//保存训练结果,供检測时使用
int iCorrectPrediction = 0;
int predictedLabel;
int testPhotoNumber = test_images.size();
for(int i=0;i<testPhotoNumber;i++)
{
predictedLabel = model->predict(test_images[i]);
if(predictedLabel == test_labels[i])
iCorrectPrediction++;
}
string result_message = format("Test Number = %d / Actual Number = %d.", testPhotoNumber, iCorrectPrediction);
cout << result_message << endl;
cout<<"accuracy = "<<float(iCorrectPrediction)/testPhotoNumber<<endl;
} void train_and_test()
{
string fn_csv = string("at.txt");
//string fn_csv = string("feret.txt");
vector<Mat> allImages,train_images,test_images;
vector<int> allLabels,train_labels,test_labels;
try {
read_csv(fn_csv, allImages, allLabels);
} catch (cv::Exception& e) {
cerr <<"Error opening file "<< fn_csv <<". Reason: "<< e.msg << endl;
// 文件有问题,我们啥也做不了了。退出了
exit(1);
}
if(allImages.size()<=1) {
string error_message ="This demo needs at least 2 images to work. Please add more images to your data set!";
CV_Error(CV_StsError, error_message);
} for(int i=0 ; i<allImages.size() ; i++)
equalizeHist(allImages[i],allImages[i]); int photoNumber = allImages.size();
for(int i=0 ; i<photoNumber ; i++)
{
if((i%g_photoNumberOfOnePerson)<g_howManyPhotoForTraining)
{
train_images.push_back(allImages[i]);
train_labels.push_back(allLabels[i]);
}
else
{
test_images.push_back(allImages[i]);
test_labels.push_back(allLabels[i]);
}
} Ptr<FaceRecognizer> model = createEigenFaceRecognizer();//定义pca模型
model->train(train_images, train_labels);//训练pca模型。这里的model包括了全部特征值和特征向量,没有损失
model->save("eigenface.yml");//保存训练结果。供检測时使用
Mat eigenvalues = model->getMat("eigenvalues");//提取model中的特征值。该特征值默认由大到小排列
Mat W = model->getMat("eigenvectors");//提取model中的特征向量,特征向量的排列方式与特征值排列顺序一一相应
int xth = 121;//打算保留前121个特征向量,代码中没有体现原因。但选择121是经过斟酌的,首先,在我的实验中。"前121个特征值之和/全部特征值总和>0.97"。其次,121=11^2,能够将结果表示成一个11*11的2维图像方阵,交给fisherface去计算。 vector<Mat> reduceDemensionimages;//降维后的图像矩阵
vector<Mat> testreduceDemensionimages;
Mat evs = Mat(W, Range::all(), Range(0, xth));//选择前xth个特征向量,其余舍弃
Mat mean = model->getMat("mean");
for(int i=0;i<train_images.size();i++)
{
Mat projection = subspaceProject(evs, mean, train_images[i].reshape(1,1));//做子空间投影
reduceDemensionimages.push_back(projection.reshape(1,sqrt(xth*1.0)));//将获得的子空间系数表示映射成2维图像,并保存起来
} for(int i=0;i<test_images.size();i++)
{
Mat projection = subspaceProject(evs, mean, test_images[i].reshape(1,1));//做子空间投影
testreduceDemensionimages.push_back(projection.reshape(1,sqrt(xth*1.0)));//将获得的子空间系数表示映射成2维图像。并保存起来
} Ptr<FaceRecognizer> fishermodel = createFisherFaceRecognizer();
fishermodel->train(reduceDemensionimages,train_labels);//用保存的降维后的图片来训练fishermodel。后面的内容与原始代码就没什么变化了
fishermodel->save("fisher.yml");
int iCorrectPrediction = 0;
int predictedLabel;
int testPhotoNumber = test_images.size();
for(int i=0;i<testPhotoNumber;i++)
{
predictedLabel = fishermodel->predict(testreduceDemensionimages[i]);
if(predictedLabel == test_labels[i])
iCorrectPrediction++;
}
string result_message = format("Test Number = %d / Actual Number = %d.", testPhotoNumber, iCorrectPrediction);
cout << result_message << endl;
cout<<"accuracy = "<<float(iCorrectPrediction)/testPhotoNumber<<endl;
} void test_pca()
{
string fn_csv = string("test.txt");
vector<Mat> allImages;
vector<int> allLabels;
try {
read_csv(fn_csv, allImages, allLabels);
} catch (cv::Exception& e) {
cerr <<"Error opening file "<< fn_csv <<". Reason: "<< e.msg << endl;
// 文件有问题,我们啥也做不了了,退出了
exit(1);
}
if(allImages.size()<=1) {
string error_message ="This demo needs at least 2 images to work. Please add more images to your data set!";
CV_Error(CV_StsError, error_message);
} Ptr<FaceRecognizer> model = createEigenFaceRecognizer();//定义pca模型
model->load("eigenfacepca.yml");//保存训练结果。供检測时使用 int iCorrectPrediction = 0;
int predictedLabel;
int testPhotoNumber = allImages.size();
for(int i=0;i<testPhotoNumber;i++)
{
predictedLabel = model->predict(allImages[i]);
if(predictedLabel == allLabels[i])
iCorrectPrediction++;
} string result_message = format("Test Number = %d / Actual Number = %d.", testPhotoNumber, iCorrectPrediction);
cout << result_message << endl;
cout<<"accuracy = "<<float(iCorrectPrediction)/testPhotoNumber<<endl;
} void test()
{
string fn_csv = string("test.txt");
vector<Mat> allImages;
vector<int> allLabels;
try {
read_csv(fn_csv, allImages, allLabels);
} catch (cv::Exception& e) {
cerr <<"Error opening file "<< fn_csv <<". Reason: "<< e.msg << endl;
// 文件有问题。我们啥也做不了了,退出了
exit(1);
}
if(allImages.size()<=1) {
string error_message ="This demo needs at least 2 images to work. Please add more images to your data set!";
CV_Error(CV_StsError, error_message);
} Ptr<FaceRecognizer> model = createEigenFaceRecognizer();//定义pca模型
model->load("eigenface.yml");//保存训练结果。供检測时使用
Mat eigenvalues = model->getMat("eigenvalues");//提取model中的特征值,该特征值默认由大到小排列
Mat W = model->getMat("eigenvectors");//提取model中的特征向量,特征向量的排列方式与特征值排列顺序一一相应
int xth = 121;//打算保留前121个特征向量,代码中没有体现原因,但选择121是经过斟酌的,首先,在我的实验中。"前121个特征值之和/全部特征值总和>0.97";其次,121=11^2,能够将结果表示成一个11*11的2维图像方阵,交给fisherface去计算。
vector<Mat> reduceDemensionimages;//降维后的图像矩阵
Mat evs = Mat(W, Range::all(), Range(0, xth));//选择前xth个特征向量。其余舍弃
Mat mean = model->getMat("mean");
for(int i=0;i<allImages.size();i++)
{
Mat projection = subspaceProject(evs, mean, allImages[i].reshape(1,1));//做子空间投影
reduceDemensionimages.push_back(projection.reshape(1,sqrt(xth*1.0)));//将获得的子空间系数表示映射成2维图像,并保存起来
} Ptr<FaceRecognizer> fishermodel = createFisherFaceRecognizer(); fishermodel->load("fisher.yml");
int iCorrectPrediction = 0;
int predictedLabel;
int testPhotoNumber = allImages.size();
for(int i=0;i<testPhotoNumber;i++)
{
predictedLabel = fishermodel->predict(reduceDemensionimages[i]);
if(predictedLabel == allLabels[i])
iCorrectPrediction++;
} string result_message = format("Test Number = %d / Actual Number = %d.", testPhotoNumber, iCorrectPrediction);
cout << result_message << endl;
cout<<"accuracy = "<<float(iCorrectPrediction)/testPhotoNumber<<endl;
} int main() { cout<<"lda = "<<endl;
train_and_test_lda();
cout<<"pca = "<<endl;
train_and_test_pca();
cout<<"pca+lda = "<<endl;
train_and_test();
/*test();
test_pca();*/
return 0 ;
}

整个工程文件和数据下载链接 http://download.csdn.net/detail/zwhlxl/8510649

版权声明:本文博主原创文章,博客,未经同意不得转载。

基于OpenCV性别识别的更多相关文章

  1. 人脸和性别识别(基于OpenCV)

    描写叙述 人脸识别包含四个步骤 人脸检測:定位人脸区域,仅仅关心是不是脸: 人脸预处理:对人脸检測出来的图片进行调整优化. 收集和学习人脸:收集要识别的人的预处理过的人脸,然后通过一些算法去学习怎样识 ...

  2. 基于深度学习的人脸性别识别系统(含UI界面,Python代码)

    摘要:人脸性别识别是人脸识别领域的一个热门方向,本文详细介绍基于深度学习的人脸性别识别系统,在介绍算法原理的同时,给出Python的实现代码以及PyQt的UI界面.在界面中可以选择人脸图片.视频进行检 ...

  3. Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图

    Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图 分类: OpenCV图像处理2013-02-21 21:35 6459人阅读 评论(8) 收藏 举报   原文链接  ht ...

  4. Java基于opencv实现图像数字识别(五)—投影法分割字符

    Java基于opencv实现图像数字识别(五)-投影法分割字符 水平投影法 1.水平投影法就是先用一个数组统计出图像每行黑色像素点的个数(二值化的图像): 2.选出一个最优的阀值,根据比这个阀值大或小 ...

  5. Java基于opencv实现图像数字识别(四)—图像降噪

    Java基于opencv实现图像数字识别(四)-图像降噪 我们每一步的工作都是基于前一步的,我们先把我们前面的几个函数封装成一个工具类,以后我们所有的函数都基于这个工具类 这个工具类呢,就一个成员变量 ...

  6. Java基于opencv实现图像数字识别(三)—灰度化和二值化

    Java基于opencv实现图像数字识别(三)-灰度化和二值化 一.灰度化 灰度化:在RGB模型中,如果R=G=B时,则彩色表示灰度颜色,其中R=G=B的值叫灰度值:因此,灰度图像每个像素点只需一个字 ...

  7. Java基于opencv实现图像数字识别(二)—基本流程

    Java基于opencv实现图像数字识别(二)-基本流程 做一个项目之前呢,我们应该有一个总体把握,或者是进度条:来一步步的督促着我们来完成这个项目,在我们正式开始前呢,我们先讨论下流程. 我做的主要 ...

  8. Java基于opencv实现图像数字识别(一)

    Java基于opencv实现图像数字识别(一) 最近分到了一个任务,要做数字识别,我分配到的任务是把数字一个个的分开:当时一脸懵逼,直接百度java如何分割图片中的数字,然后就百度到了用Buffere ...

  9. 基于 OpenCV 的人脸识别

    基于 OpenCV 的人脸识别 一点背景知识 OpenCV 是一个开源的计算机视觉和机器学习库.它包含成千上万优化过的算法,为各种计算机视觉应用提供了一个通用工具包.根据这个项目的关于页面,OpenC ...

随机推荐

  1. SPOJ 375(树链剖分)

    题目连接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28982#problem/I 题意:一棵包含N 个结点的树,每条边都有一个权值, ...

  2. C++封装SQLite实例&lt;三&gt;

    前一篇博客中介绍的是怎样依据sqlite3_get_table()函数来获取一张表的内容,就是一股脑的把表中的内容所有存储起来放在一个一维数组中,这其中的规则已经介绍过了.接下来讲的是怎样依据一个SQ ...

  3. java使用AES加密解密 AES-128-ECB加密

    java使用AES加密解密 AES-128-ECB加密 import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; impo ...

  4. 在spring MVC的controller中获取ServletConfig

    在使用SmartUpload进行文件上传时,须要用到srevletConfig: 假设是在servlet中写当然是非常easy实现的: private ServletConfig config; // ...

  5. Oracle Dataguard 介绍

    Oracle DataGuard介绍 一. DataGuard的基本原理 当某次事务处理对生产数据库中的数据作出更改时,Oracle数据库将在一个联机重做日志文件里记录此次更改.在DataGuard中 ...

  6. java环境变量设置--编写一年java,竟不会配变量了

    java环境变量设置 1.打开我的电脑--属性--高级--环境变量 2.新建系统变量JAVA_HOME 和CLASSPATH 变量名:JAVA_HOME 变量值:C:\Program Files\Ja ...

  7. testing and SQA_动态白盒測试

    一.软件測试技术: 黑盒:在不知道程序内部结构,仅仅知道程序结构的情况下採用的測试技术或策略. 白盒:在知道程序内部结构的情况下採用的測试技术或策略. 两种測试方法从不同的角度出发,反映了软件的不同側 ...

  8. VS2010关于error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏

    前段时间自己的系统一直在安装更新.今天突然打开VS2010当运行的时候一直出现error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏这种错误.然后就百度 解决的方法: 1.项目\属 ...

  9. Gitblit配置

    Gitblit的安装配置及访问-windows (2013-09-11 11:52:31) 转载▼   分类: android基础 Git 是现在很流行的分布式版本控制工具,github更是人人皆知. ...

  10. Cocos2d-x 3.2 Lua演示样例 XMLHttpRequestTest(Http网络请求)

    Cocos2d-x 3.2 Lua演示样例 XMLHttpRequestTest(Http网络请求)     本篇博客介绍Cocos2d-x 3.2Lua演示样例中的XMLHttpRequestTes ...