最新网络的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);
训练并且测试
附上一张笑脸表情的结果