OpenCV dnn模块支持Caffe

#include <opencv2/dnn.hpp>
#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) */


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);
                }
            }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值