Introduction
In this tutorial you will learn how to use opencv_dnn module for image classification by using GoogLeNet trained network from Caffe model zoo.
We will demonstrate results of this example on the following picture.
Buran space shuttle
Source Code
We will be using snippets from the example application, that can be downloaded here.
#include <fstream>
#include <iostream>
#include <cstdlib>
void getMaxClass(
dnn::Blob &probBlob,
int *classId,
double *classProb)
{
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";
try
{
}
{
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);
}
{
std::cerr << "Can't read image from the file: " << imageFile << std::endl;
exit(-1);
}
int classId;
double classProb;
getMaxClass(prob, &classId, &classProb);
std::vector<String> classNames = readClassNames();
std::cout << "Best class: #" << classId << " '" << classNames.at(classId) << "'" << std::endl;
std::cout << "Probability: " << classProb * 100 << "%" << std::endl;
return 0;
}
Explanation
Firstly, download GoogLeNet model files: bvlc_googlenet.prototxt and bvlc_googlenet.caffemodel
Also you need file with names of ILSVRC2012 classes: synset_words.txt.
Put these files into working dir of this program example.
- Create the importer of Caffe models
Ptr<dnn::Importer> importer;
try
{
}
{
std::cerr << err.
msg << std::endl;
}
- Create the network and initialize its by using the created importer
dnn::Net net;
importer->populateNet(net);
importer.release();
Read input image and convert to the blob, acceptable by GoogleNet
if (img.empty())
{
std::cerr << "Can't read image from the file: " << imageFile << std::endl;
exit(-1);
}
dnn::Blob inputBlob = dnn::Blob::fromImages(img);
Firstly, we resize the image and change its channel sequence order.
Now image is actually a 3-dimensional array with 224x224x3 shape.
Next, we convert the image to 4-dimensional blob (so-called batch) with 1x2x224x224 shape by using special cv::dnn::Blob constructor.
Pass the blob to the network
net.setBlob(".data", inputBlob);
In bvlc_googlenet.prototxt the network input blob named as "data", therefore this blob labeled as ".data" in opencv_dnn API.
Other blobs labeled as "name_of_layer.name_of_layer_output".
- Make forward pass During the forward pass output of each network layer is computed, but in this example we need output from "prob" layer only.
- Determine the best class
dnn::Blob prob = net.getBlob("prob");
int classId;
double classProb;
getMaxClass(prob, &classId, &classProb);
We put the output of "prob" layer, which contain probabilities for each of 1000 ILSVRC2012 image classes, to the prob
blob. And find the index of element with maximal value in this one. This index correspond to the class of the image.
- Print results
std::vector<String> classNames = readClassNames();
std::cout << "Best class: #" << classId << " '" << classNames.at(classId) << "'" << std::endl;
std::cout << "Probability: " << classProb * 100 << "%" << std::endl;
For our image we get:
Best class: #812 'space shuttle'
Probability: 99.6378%