您的位置:首页 > Web前端

OpenCV dnn模块支持Caffe

2016-09-14 10:51 323 查看
#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);

                }

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