您的位置:首页 > 理论基础 > 计算机网络

cpp-BP神经网络与特征脸实现人脸表情识别(二)-实现人脸识别

2017-02-10 20:35 399 查看
最新网络的c++实现位于 http://blog.csdn.net/mr_w1997/article/details/72353659
包含本篇所用到的神经网络  http://blog.csdn.net/mr_w1997/article/details/54973376

我使用的是 yale 大学的人脸库 解压后将文件夹放入项目文件的文件夹中 链接:http://download.csdn.net/detail/mr_w1997/9752209

以下为笑脸的训练与测试 需要 了解PCA原理,opencv简单的使用以及opencv的pca类 楼主使用 VS2015 加 opencv

基本思路就是 将图片通过PCA降维,将降维后的数据输入网络,并指定输出值进行训练 详情搜索 PCA数学原理、PCA实现人脸降维,特征脸与BP神经网络实现人脸识别

代码如下:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <cv.h>
#include "net.h"
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>

#define TEST_FACE 3

#define TESTNUM 4
#define ITEMNUM 11
#define GROUPNUM 15
#define WIDTH 100
#define HEIGHT 100
#define FEATURENUM 6

using namespace std;

string int2str(const int num)
{
char tmp[10];
sprintf(tmp, "%d", num);
string str = tmp;
return str;
}

void copyRow(cv::Mat Dest, cv::Mat Sour, int cnt)
{
for (int i = 0; i < Sour.cols; ++i)
Dest.at<float>(cnt, i) = Sour.at<float>(0, i);
}

int main()
{
string head = "Yale人脸库\\yalefaces\\";
string tail = ".bmp";

cv::Mat database(GROUPNUM, WIDTH*HEIGHT, CV_32FC1);
cv::Mat row_tmp;
for (int i = 0; i < GROUPNUM; ++i)
{
string gnum;
if (i + 1 < 10)
gnum = int2str(0) + int2str(i+1) + "\\";
else
gnum = int2str(i+1) + "\\";

string name = head + gnum;
string znum = "s" + int2str(TEST_FACE) + tail;
name += znum;

cv::Mat data = cv::imread(name.c_str(), CV_LOAD_IMAGE_GRAYSCALE);

cv::Mat tdata;
data.convertTo(tdata, CV_32FC1);

tdata.reshape(1, 1).row(0).convertTo(row_tmp, CV_32FC1);
copyRow(database, row_tmp, i);

}

cv::PCA pca(database, cv::Mat(), CV_PCA_DATA_AS_ROW, FEATURENUM);
cv::Mat eigenvectors = pca.eigenvectors.clone();

for (int i = 0; i < eigenvectors.rows; ++i)
{
cv::normalize(eigenvectors.row(i), eigenvectors.row(i), 255);
}

cv::Mat Result = pca.project(database);

int in = FEATURENUM;
int ou = 4;
double **outputs = new double*[ITEMNUM] {
new double[ou]{0,0,0,0},
new double[ou]{1,0,0,0},
new double[ou]{0,1,0,0},
new double[ou]{0,0,1,0},
new double[ou]{0,0,0,1},
new double[ou]{1,1,0,0},
new double[ou]{0,1,1,0},
new double[ou]{0,0,1,1},
new double[ou]{1,0,1,0},
new double[ou]{0,1,0,1},
new double[ou]{1,0,0,1}
};
DataSet *trainingSet = new DataSet(in, ou);
DataSet *testSet = new DataSet(in, ou);
double *tmp_data = new double[in];
for (int i = 0; i < GROUPNUM; ++i)
{
for (int j = 0; j < in; ++j)
{
tmp_data[j] = Result.at<float>(i, j);
}

if(i<TESTNUM)
testSet->AddRow(tmp_data, outputs[TEST_FACE - 1]);
else
trainingSet->AddRow(tmp_data, outputs[TEST_FACE - 1]);
}
if (tmp_data)
delete tmp_data;
trainingSet->Normaliz();
testSet->Normaliz();

//层激励函数类型 神经元个数... 学习速率
MultiLayerPerceptron *m = new MultiLayerPerceptron(FUNCTYPE_LINEAR, FEATURENUM, FUNCTYPE_SIGMOID, 2* FEATURENUM + 3, FUNCTYPE_SIGMOID, ou, 0.9);

//学习1000次
for (int i = 0; i < 1000; ++i)
m->Learn(trainingSet);

m->Test(testSet);

cv::namedWindow("Gone Girl");
cv::Mat aaa = database.row(10).reshape(1, HEIGHT);
for (int i = 0; i < aaa.rows; ++i)
for (int j = 0; j < aaa.cols; ++j)
aaa.at<float>(i, j) /= 255;
cv::imshow("Gone Girl", aaa);
cv::waitKey(0);

system("pause");
return 0;
}


1.

#define TEST_FACE 3			所测试表情的序号 1-11(数据集中每人有11张图片,即11种表情) 手动更改比较low

#define TESTNUM 4			用于测试的训练数据个数为4  用于训练的为11-4
#define ITEMNUM 11			每个人有11张图片
#define GROUPNUM 15			15个人
#define WIDTH 100			图片宽 像素
#define HEIGHT 100			图片高
#define FEATURENUM 6			pca后所保留特征向量的个数


2.

cv::Mat data = cv::imread(name.c_str(), CV_LOAD_IMAGE_GRAYSCALE);

cv::Mat tdata;
data.convertTo(tdata, CV_32FC1);

tdata.reshape(1, 1).row(0).convertTo(row_tmp, CV_32FC1);
copyRow(database, row_tmp, i);
读取图片并且转化为浮点型,将其重塑成行向量并且拷贝至 row_tmp,将行向量拷贝至database中,database每一行是一张图片的数据,

ps(若要显示浮点数据图片,应将每个元素除以255 即 a /= 255,否则为白色)

3.

cv::PCA pca(database, cv::Mat(), CV_PCA_DATA_AS_ROW, FEATURENUM);
cv::Mat eigenvectors = pca.eigenvectors.clone();

for (int i = 0; i < eigenvectors.rows; ++i)
{
cv::normalize(eigenvectors.row(i), eigenvectors.row(i), 255);
}

cv::Mat Result = pca.project(database);


通过 PCA 获取新的特征向量 eigenvectors 注意!!需要分别归一化每一行特征向量,之后方可显示特征脸,否则特征脸为黑色。

通过 project 获取新的数据 Result

int in = FEATURENUM;
int ou = 4;
double **outputs = new double*[ITEMNUM] {
new double[ou]{0,0,0,0},
new double[ou]{1,0,0,0},
new double[ou]{0,1,0,0},
new double[ou]{0,0,1,0},
new double[ou]{0,0,0,1},
new double[ou]{1,1,0,0},
new double[ou]{0,1,1,0},
new double[ou]{0,0,1,1},
new double[ou]{1,0,1,0},
new double[ou]{0,1,0,1},
new double[ou]{1,0,0,1}
};
DataSet *trainingSet = new DataSet(in, ou);
DataSet *testSet = new DataSet(in, ou);
double *tmp_data = new double[in];
for (int i = 0; i < GROUPNUM; ++i)
{
for (int j = 0; j < in; ++j)
{
tmp_data[j] = Result.at<float>(i, j);
}

if(i<TESTNUM)
testSet->AddRow(tmp_data, outputs[TEST_FACE - 1]);
else
trainingSet->AddRow(tmp_data, outputs[TEST_FACE - 1]);
}
if (tmp_data)
delete tmp_data;
trainingSet->Normaliz();
testSet->Normaliz();


建立训练集以及测试集 并且归一化

//层激励函数类型 神经元个数... 学习速率
MultiLayerPerceptron *m = new MultiLayerPerceptron(FUNCTYPE_LINEAR, FEATURENUM, FUNCTYPE_SIGMOID, 2* FEATURENUM + 3, FUNCTYPE_SIGMOID, ou, 0.9);

//学习1000次
for (int i = 0; i < 1000; ++i)
m->Learn(trainingSet);

m->Test(testSet);


训练并且测试

附上一张笑脸表情的结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息