叙述性说明

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

识别算法可以用于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. Java UML描述

      开发Java应用程序时,开发者要想有效地利用统一建模语言(UML),必须全面理解UML元素以及这些元素如何映射到Java.本文重点讨论UML类图中的元素. 类图是最常用的UML图,它用于描述系统的 ...

  2. (017)将一棵二叉查找树重构成链表(keep it up)

    给定一棵二叉查找树,设计算法,将每一层的全部结点构建为一个 链表(也就是说, 假设树有D层,那么你将构建出D个链表). 这个题实质是个BFS,可是实现起来有点麻烦,又不像常见的BFS, 所以编写代码时 ...

  3. ipconfig /flushdns 清除系统DNS缓存

    1.ipconfig /flushdns的作用 ipconfig /flushdns 这是清除DNS缓存用的. 当訪问一个站点时系统将从DNS缓存中读取该域名所相应的IP地址,当查找不到时就会到系统中 ...

  4. VMware workstation 安装错误提示1021解决方法

    Failed to create the requested registry key Key: Installer Error: 1021 解决方法:删除注册表--HKEY_LOCAL_MACHIN ...

  5. cocos2dx移植android平台

    本人这几天一直都没有跟新自己的网站内容,问我干什么去了,当然是做这篇文章做的事了,说起这个移植来真是麻烦啊,网上试验了各种方法,都不知道谁对谁错啊.不过经过本人这三天的研究最后终于成功了,为了让大家少 ...

  6. pygame系列_mouse鼠标事件

    pygame.mouse提供了一些方法获取鼠标设备当前的状态 ''' pygame.mouse.get_pressed - get the state of the mouse buttons get ...

  7. OCP读书笔记(19) - 数据库空间管理

    传输表空间:将linux下的数据库中的test表空间传输到windows平台下的数据库 在传输表空间前,先确定一下源库与目标数据库字符集一致: select * from nls_database_p ...

  8. Linux中块设备驱动程序分析

    基于<Linux设备驱动程序>书中的sbull程序以对Linux块设备驱动总结分析. 開始之前先来了解这个块设备中的核心数据结构: struct sbull_dev {         i ...

  9. 部署 Redis 群集

    Windows 部署 Redis 群集   1,下载Redis for windows 的最新版本,解压到 c:\Redis 目录下备用https://github.com/MSOpenTech/re ...

  10. Android 动态显示和隐藏软键盘

    ** * 动态设置软盘的显示和隐藏 * @author JPH */ public class MainActivity extends Activity implements OnClickList ...