#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
using namespace cv::dnn;
#include <fstream>
#include <iostream>
#include <cstdlib>
using namespace std;
/* Find best class for the blob (i. e. class with maximal probability) */
{
Mat probMat = probBlob.matRefConst().reshape(1, 1); //reshape the blob to 1x1000 matrix
Point classNumber;
minMaxLoc(probMat, NULL, classProb, NULL, &classNumber);
*classId = classNumber.x;
}
std::vector<String> readClassNames(const char *filename = "synset_words.txt")
{
std::vector<String> classNames;
std::ifstream fp(filename);
if (!fp.is_open())
{
std::cerr << "File with classes labels not found: " << filename << std::endl;
exit(-1);
}
std::string name;
while (!fp.eof())
{
std::getline(fp, name);
if (name.length())
classNames.push_back(name.substr(name.find(' ') + 1));
}
fp.close();
return classNames;
}
int main(int argc, char **argv)
{
String modelTxt = "bvlc_googlenet.prototxt";
String modelBin = "bvlc_googlenet.caffemodel";
String imageFile = (argc > 1) ? argv[1] : "space_shuttle.jpg";
Ptr<dnn::Importer> importer;
try //Try to import Caffe GoogleNet model
{
importer = dnn::createCaffeImporter(modelTxt, modelBin);
}
catch (const cv::Exception &err) //Importer can throw errors, we will catch them
{
std::cerr << err.msg << std::endl;
}
if (!importer)
{
std::cerr << "Can't load network by using the following files: " << std::endl;
std::cerr << "prototxt: " << modelTxt << std::endl;
std::cerr << "caffemodel: " << modelBin << std::endl;
std::cerr << "bvlc_googlenet.caffemodel can be downloaded here:" << std::endl;
std::cerr << "http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel" << std::endl;
exit(-1);
}
dnn::Net net;
importer->populateNet(net);
importer.release(); //We don't need importer anymore
Mat img = imread(imageFile);
if (img.empty())
{
std::cerr << "Can't read image from the file: " << imageFile << std::endl;
exit(-1);
}
resize(img, img, Size(224, 224)); //GoogLeNet accepts only 224x224 RGB-images
dnn::Blob inputBlob = dnn::Blob(img); //Convert Mat to dnn::Blob image batch
net.setBlob(".data", inputBlob); //set the network input
net.forward(); //compute output
dnn::Blob prob = net.getBlob("prob"); //gather output of "prob" layer
int classId;
double classProb;
getMaxClass(prob, &classId, &classProb);//find the best class
std::vector<String> classNames = readClassNames();
std::cout << "Best class: #" << classId << " '" << classNames.at(classId) << "'" << std::endl;
std::cout << "Probability: " << classProb * 100 << "%" << std::endl;
return 0;
} //main
这里给出了一个样例,如何使用Opencv的dnn模块进行人脸识别,因为在编译Opencv时似乎没有加上WITH_CUDA,所以导致forward()的传播速度巨慢,但是不影响我们进行实验。
准备工作
1、编译好Opencv的contrib库,并没有错误。
2、有用于提取特征的caffemodel文件,网络的prototxt文件。
思路
注册人脸->将人脸批量提取特征->多个同一维度的向量->保存在vector
代码
网络向前传播的速度非常“感人”,我自己写的caffe深度学习人脸识别就没这个情况。
以下的例子比较简单,可以适当修改,保留核心部分。
头文件:
#include <opencv.hpp>
#include <string>
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <cassert>
#include <cmath>
using namespace std;
using namespace cv;
Mat Facedetect(Mat frame);//一个人脸检测的函数,可以把其封装成这个样子,用Opencv的adaboost分类器也可以
float coefficient(const std::vector<float>& v1, const std::vector<float>& v2);//用于计算两个向量的相似度,下面有说明。
计算相似度
float mean(const std::vector<float>& v)
{
assert(v.size() != 0);
float ret = 0.0;
for (std::vector<float>::size_type i = 0; i != v.size(); ++i)
{
ret += v[i];
}
return ret / v.size();
}
float cov(const std::vector<float>& v1, const std::vector<float>& v2)
{
assert(v1.size() == v2.size() && v1.size() > 1);
float ret = 0.0;
float v1a = mean(v1), v2a = mean(v2);
for (std::vector<float>::size_type i = 0; i != v1.size(); ++i)
{
ret += (v1[i] - v1a) * (v2[i] - v2a);
}
return ret / (v1.size() - 1);
}
// 相关系数
float coefficient(const std::vector<float>& v1, const std::vector<float>& v2)
{
assert(v1.size() == v2.size());
return cov(v1, v2) / sqrt(cov(v1, v1) * cov(v2, v2));
}
提取训练样本特征
string modelTxt = "VGG_FACE_deploy.prototxt";//prototxt
string modelBin = "VGG_FACE.caffemodel";//model
Ptr<dnn::Importer> importer;
try
{
importer = dnn::createCaffeImporter(modelTxt, modelBin);
}
catch (const cv::Exception &err)
{
cerr << err.msg << endl;
}
if (!importer)
{
cout << "Please Check your caffemodel and prototxt";
exit(0);
}
dnn::Net net;
importer->populateNet(net);
importer.release();
//===============进行训练样本提取=======================可修改====================
//========================五个人,每人一张照片====================================
std::vector<Mat> train;
std::vector<int> train_label;
int train_man = 1, train_num = 1;//训练的人的种类、人的个数
for (train_man = 1; train_man <= 5; train_man++)
{
for (train_num = 1; train_num <= 1; train_num++)
{
string train_road = "VGG_train/" + Int_String(train_man) + " (" + Int_String(train_num) + ").jpg";
cv::Mat train_Sample = imread(train_road);
if (!train_Sample.empty())
{
train.push_back(train_Sample);
train_label.push_back(train_man);
cout << "There is train pic!!" << train_man << "" << train_num << endl;
}
else
{
cout << "There is no pic!!" << train_man << "" << train_num;
getchar();
exit(-1);
}
}
}
dnn::Blob train_blob = dnn::Blob(train);
net.setBlob(".data", train_blob);
cout << "Please wait..." << endl;
net.forward();
dnn::Blob prob = net.getBlob("fc8");//提取哪一层
vector < vector <float> > feature_vector;
int train_man_num=0;//第几个人
for (train_man_num = 0; train_man_num <= 4; train_man_num++)
{
vector<float> feature_one;//单个人的feature
int channel = 0;
while (channel < 2622)//看网络相应层的output
{
feature_one.push_back(*prob.ptrf(train_man_num, channel, 1, 1));
channel++;
string train_txt = Int_String(train_man_num) + ".txt";
ofstream myfile(train_txt, ios::app); //example.txt是你要输出的文件的名字,这里把向量都分开保存为txt,以便于后面可以直接读取
myfile << *prob.ptrf(train_man_num, channel, 1, 1) << endl;
}
feature_vector.push_back(feature_one);//把它赋给二维数组
feature_one.clear();
}
cout << "Successful extract!!!" << endl;
train_blob.offset();
测试样本特征提取
string test_fileroad = "C://wamp//www//pic//" + Int_String(x) + ".jpg";//图片的地方,改成摄像头也可以。
Mat testSample = imread(test_fileroad);
if (testSample.empty())
cout << "There is no testSample ..." << endl;
else
{
testSample = Facedetect(testSample);
vector<Mat> test;
vector<int> test_label;
test.push_back(testSample);
test_label.push_back(0);
//then
dnn::Blob test_blob = dnn::Blob(test);//如果用原来的似乎会报错。。。
net.setBlob(".data", test_blob);
cout << "extracting features..." << endl;
net.forward();
dnn::Blob prob_test = net.getBlob("fc8");
vector<float> test_feature;//第8层的特征
int channel = 0;
while (channel < 2622)
{
test_feature.push_back(*prob.ptrf(0, channel, 1, 1));
channel++;
}
cout << "we got it.." << endl;
float higher_score = 0;//相似度
int T_number = 0;
for (int test_num_vector = 0; test_num_vector <= 4; test_num_vector++)
{
float score = coefficient(feature_vector[test_num_vector], test_feature);
cout << "The coefficient" << test_num_vector << "------------to----------" << score << endl;
if (score > higher_score)
{
higher_score = score;
T_number = test_num_vector;
}
}
x++;
imshow("testSample", testSample);
imshow("trainSample", train[T_number]);//可以直接把和测试样本最相近的一张图亮出来
waitKey(1);
}
}