C++ opencv-3.4.1 调用caffe训练好的模型

opencv在3.0之后就支持调用深度学习模型。OpenCV dnn模块目前支持Caffe、TensorFlow、Torch、PyTorch等深度学习框架。另外,新版本中使用预训练深度学习模型的API同时兼容C++和Python。

参照官方教程进行一个分类模型的调用caffe模型进行分类,Load Caffe framework models。注意版本,我的版本是3.4.1,选择对应版本。

image.png

  1. 在opencv的解压文件下面有sample/dnn/所有的例子。这个例子来自sample/dnn//caffe_googlenet.cpp

  2. 下载两个文件bvlc_googlenet.prototxt and bvlc_googlenet.caffemodel

3.也要下载 synset_words.txt.

  1. 把上面三个文件放在与caffe_googlenet.cpp同级目录。

  2. 新建工程把caffe_googlenet.cpp添加进去。

caffe_googlenet.cpp 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core/utils/trace.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) */
static void getMaxClass(const Mat &probBlob, int *classId, double *classProb)
{
    Mat probMat = probBlob.reshape(1, 1); //reshape the blob to 1x1000 matrix
    Point classNumber;

    minMaxLoc(probMat, NULL, classProb, NULL, &classNumber);
    *classId = classNumber.x;
}

static std::vector<String> readClassNames(const char *filename)
{
    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;
}

const char* params
= "{ help         | false | Sample app for loading googlenet model }"
"{ proto          | bvlc_googlenet.prototxt | model configuration }"
"{ model          | bvlc_googlenet.caffemodel | model weights }"
"{ label          | classification_classes_ILSVRC2012.txt | names of ILSVRC2012 classes }"
"{ image          | space_shuttle.jpg | path to image file }"
"{ opencl         | false | enable OpenCL }"
;

int main(int argc, char **argv)
{
    CV_TRACE_FUNCTION();

    CommandLineParser parser(argc, argv, params);

    if (parser.get<bool>("help"))
    {
        parser.printMessage();
        return 0;
    }

    String modelTxt = parser.get<string>("proto");
    String modelBin = parser.get<string>("model");
    String imageFile = parser.get<String>("image");
    String classNameFile = parser.get<String>("label");

    Net net;
    try {
        //! [Read and initialize network]
        net = dnn::readNetFromCaffe(modelTxt, modelBin);
        //! [Read and initialize network]
    }
    catch (const cv::Exception& e) {
        std::cerr << "Exception: " << e.what() << std::endl;
        //! [Check that network was read successfully]
        if (net.empty())
        {
            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);
        }
        //! [Check that network was read successfully]
    }

    if (parser.get<bool>("opencl"))
    {
        net.setPreferableTarget(DNN_TARGET_OPENCL);
    }

    //! [Prepare blob]
    Mat img = imread(imageFile);
    if (img.empty())
    {
        std::cerr << "Can't read image from the file: " << imageFile << std::endl;
        exit(-1);
    }

    //GoogLeNet accepts only 224x224 BGR-images
    Mat inputBlob = blobFromImage(img, 1.0f, Size(224, 224),
        Scalar(104, 117, 123), false);   //Convert Mat to batch of images
    //! [Prepare blob]
    net.setInput(inputBlob, "data");        //set the network input
    Mat prob = net.forward("prob");         //compute output

    cv::TickMeter t;
    for (int i = 0; i < 10; i++)
    {
        CV_TRACE_REGION("forward");
        //! [Set input blob]
        net.setInput(inputBlob, "data");        //set the network input
        //! [Set input blob]
        t.start();
        //! [Make forward pass]
        prob = net.forward("prob");                          //compute output
        //! [Make forward pass]
        t.stop();
    }

    //! [Gather output]
    int classId;
    double classProb;
    getMaxClass(prob, &classId, &classProb);//find the best class
    //! [Gather output]

    //! [Print results]
    std::vector<String> classNames = readClassNames(classNameFile.c_str());
    std::cout << "Best class: #" << classId << " '" << classNames.at(classId) << "'" << std::endl;
    std::cout << "Probability: " << classProb * 100 << "%" << std::endl;
    //! [Print results]
    std::cout << "Time: " << (double)t.getTimeMilli() / t.getCounter() << " ms (average from " << t.getCounter() << " iterations)" << std::endl;
    // input samething
    int a;
    std::cin >> a;

    return 0;
} //main

按照对应的版本使用例子,一般不会出错。

这里有几个比较重要的参数,需改对应的参数就可进行不同图片的分类了。

1
2
3
4
5
6
7
const char* params
= "{ help         | false | Sample app for loading googlenet model }"
"{ proto          | bvlc_googlenet.prototxt | model configuration }"
"{ model          | bvlc_googlenet.caffemodel | model weights }"
"{ label          | synset_words.txt | names of ILSVRC2012 classes }"
"{ image          | space_shuttle.jpg | path to image file }"
"{ opencl         | false | enable OpenCL }"

proto: caffe的配置文件
model:caffe的参数文件
image:图片
opencl:是否使用opencl进行加速

result

1
2
3
4
5
6
7
8
9
Attempting to upgrade input file specified using deprecated V1LayerParameter: bvlc_googlenet.caffemodel
Successfully upgraded file specified using deprecated V1LayerParameter
[ INFO:0] Initialize OpenCL runtime...

Net Outputs(1):
prob
Best class: #812 'shuttle'
Probability: 99.993%
Time: 1492.05 ms (average from 10 iterations)

使用c++ opencv调用tensorflow训练好的卷积神经网络
opencv官方教程caffe model调用
OpenCV调用TensorFlow预训练模型
基于opencv dnn模块 的caffe模型的调用