基于OpenCV性别识别
叙述性说明
所谓的性别识别推断检测到的面部是男性还是女性。它是一个二值分类问题。
识别算法可以用于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性别识别的更多相关文章
- 人脸和性别识别(基于OpenCV)
描写叙述 人脸识别包含四个步骤 人脸检測:定位人脸区域,仅仅关心是不是脸: 人脸预处理:对人脸检測出来的图片进行调整优化. 收集和学习人脸:收集要识别的人的预处理过的人脸,然后通过一些算法去学习怎样识 ...
- 基于深度学习的人脸性别识别系统(含UI界面,Python代码)
摘要:人脸性别识别是人脸识别领域的一个热门方向,本文详细介绍基于深度学习的人脸性别识别系统,在介绍算法原理的同时,给出Python的实现代码以及PyQt的UI界面.在界面中可以选择人脸图片.视频进行检 ...
- Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图
Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图 分类: OpenCV图像处理2013-02-21 21:35 6459人阅读 评论(8) 收藏 举报 原文链接 ht ...
- Java基于opencv实现图像数字识别(五)—投影法分割字符
Java基于opencv实现图像数字识别(五)-投影法分割字符 水平投影法 1.水平投影法就是先用一个数组统计出图像每行黑色像素点的个数(二值化的图像): 2.选出一个最优的阀值,根据比这个阀值大或小 ...
- Java基于opencv实现图像数字识别(四)—图像降噪
Java基于opencv实现图像数字识别(四)-图像降噪 我们每一步的工作都是基于前一步的,我们先把我们前面的几个函数封装成一个工具类,以后我们所有的函数都基于这个工具类 这个工具类呢,就一个成员变量 ...
- Java基于opencv实现图像数字识别(三)—灰度化和二值化
Java基于opencv实现图像数字识别(三)-灰度化和二值化 一.灰度化 灰度化:在RGB模型中,如果R=G=B时,则彩色表示灰度颜色,其中R=G=B的值叫灰度值:因此,灰度图像每个像素点只需一个字 ...
- Java基于opencv实现图像数字识别(二)—基本流程
Java基于opencv实现图像数字识别(二)-基本流程 做一个项目之前呢,我们应该有一个总体把握,或者是进度条:来一步步的督促着我们来完成这个项目,在我们正式开始前呢,我们先讨论下流程. 我做的主要 ...
- Java基于opencv实现图像数字识别(一)
Java基于opencv实现图像数字识别(一) 最近分到了一个任务,要做数字识别,我分配到的任务是把数字一个个的分开:当时一脸懵逼,直接百度java如何分割图片中的数字,然后就百度到了用Buffere ...
- 基于 OpenCV 的人脸识别
基于 OpenCV 的人脸识别 一点背景知识 OpenCV 是一个开源的计算机视觉和机器学习库.它包含成千上万优化过的算法,为各种计算机视觉应用提供了一个通用工具包.根据这个项目的关于页面,OpenC ...
随机推荐
- ASP.NET管线与应用程序生命周期
ASP.NET管线与应用程序生命周期 ASP.NET管线与应用程序生命周期 8.1节介绍了IIS的系统架构和HTTP请求处理的总体流程,从中可以知道每个ASP.NET网站都对应着一个Web应用程序,此 ...
- hdu4670(树上点分治+状态压缩)
树上路径的f(u,v)=路径上所有点的乘积. 树上每个点的权值都是由给定的k个素数组合而成的,如果f(u,v)是立方数,那么就说明f(u,v)是可行的方案. 问有多少种可行的方案. f(u,v)可是用 ...
- HTTPDNS成为移动互联网的标配–原因与原理解析(转)
DNS,作用就是将域名解析成IP.一个DNS查询,先从本地缓存查找,如果没有或者已经过期,就从DNS服务器查询,如果客户端没有主动设置DNS服务器,一般是从服务商DNS服务器上查找.这就出现了不可控. ...
- java.lang.NoClassDefFoundError: org/apache/juli/logging/LogFactory
Myeclipse 8.6使用tomcat7时间.执行javaweb如报告了以下错误项: java.lang.NoClassDefFoundError: org/apache/juli/logging ...
- 二十7天 春雨滋润着无形 —Spring依赖注入
6月11日,明确."夏条绿已密,朱萼缀明鲜.炎炎日正午,灼灼火俱燃." IT人习惯把详细的事物加工成的形状一致的类.正是这种一致,加上合适的规范.才干彰显对象筋道的牙感和bean清 ...
- 1、Cocos2dx 3.0游戏开发三找一小块前言
尊重开发人员的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27094663 前言 Cocos2d-x 是一个通用 ...
- 深度分析 Java 的枚举类型:枚举的线程安全性及序列化问题(转)
写在前面: Java SE5 提供了一种新的类型 Java的枚举类型,关键字 enum 可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用,这是一种非常有用的功能 ...
- DateTime.Compare(t1,t2)比較两个日期大小
DateTime.Compare(t1,t2)比較两个日期大小,排前面的小,排在后面的大,比方:2011-2-1就小于2012-3-2返回值小于零: t1 小于 t2. 返回值等于零 : t1 等于 ...
- SpringMVC 上下文webApplicationContext
使用listener听众载入配置,一般Struts+Spring+Hibernate是使用listener监听器的.例如以下 <listener> <listener-class&g ...
- 活动图(Activity Diagram) - 项目分解文章
案例基础上登录用户进行操作的每个模块. 1. 员 (1) 列车顺序表 (2) 货车装卸报告(数据处理) (3) 货车装卸报告(查看) 2. 管理员 (1) password管理 (2) 查看日志 (3 ...