/* Find best class for the blob (i. e. class with maximal probability) */
void getMaxClass(dnn::Blob &probBlob, int *classId, double *classProb) { 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 <opencv2/dnn.hpp> #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); } }