From 3154fc0dba597cca00d503c7a0e46200358f0f83 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Wed, 26 Aug 2015 01:43:53 +0300 Subject: [PATCH] Add googlenet tutorial --- modules/dnn/samples/caffe_googlenet.cpp | 123 +++++++++--------- .../dnn/tutorials/images/space_shuttle.jpg | Bin 0 -> 27598 bytes .../dnn/tutorials/tutorial_dnn_build.markdown | 6 +- .../tutorials/tutorial_dnn_googlenet.markdown | 64 +++++++++ 4 files changed, 129 insertions(+), 64 deletions(-) create mode 100644 modules/dnn/tutorials/images/space_shuttle.jpg create mode 100644 modules/dnn/tutorials/tutorial_dnn_googlenet.markdown diff --git a/modules/dnn/samples/caffe_googlenet.cpp b/modules/dnn/samples/caffe_googlenet.cpp index 72c1db174..66e383162 100644 --- a/modules/dnn/samples/caffe_googlenet.cpp +++ b/modules/dnn/samples/caffe_googlenet.cpp @@ -51,18 +51,14 @@ using namespace cv::dnn; #include using namespace std; -/* It contains class number and probability of this class */ -typedef std::pair ClassProb; - /* Find best class for the blob (i. e. class with maximal probability) */ -ClassProb getMaxClass(dnn::Blob &probBlob) +void getMaxClass(dnn::Blob &probBlob, int *classId, double *classProb) { - Mat probMat = probBlob.matRefConst().reshape(1, 1); - double classProb; + Mat probMat = probBlob.matRefConst().reshape(1, 1); //reshape the blob to 1x1000 matrix Point classNumber; - minMaxLoc(probMat, NULL, &classProb, NULL, &classNumber); - return std::make_pair(classNumber.x, classProb); + minMaxLoc(probMat, NULL, classProb, NULL, &classNumber); + *classId = classNumber.x; } std::vector readClassNames(const char *filename = "synset_words.txt") @@ -89,75 +85,80 @@ std::vector readClassNames(const char *filename = "synset_words.txt") return classNames; } -/* Create batch from the image */ -dnn::Blob makeInputBlob(const String &imagefile) +int main(int argc, char **argv) { - Mat img = imread(imagefile); - if (img.empty()) + String modelTxt = "bvlc_googlenet.prototxt"; + String modelBin = "bvlc_googlenet.caffemodel"; + + //! [importer_creation] + Ptr 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; + importer = Ptr(); //NULL + } + //! [importer_creation] + + if (!importer) { - std::cerr << "Can't read image from file:" << std::endl; - std::cerr << imagefile << std::endl; + 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); } - cvtColor(img, img, COLOR_BGR2RGB); - resize(img, img, Size(227, 227)); + //! [network_initialization] + dnn::Net net; + importer->populateNet(net); - return dnn::Blob(img); //construct 4-dim Blob (i. e. batch) -} + delete importer; + //! [network_initialization] -int main(int argc, char **argv) -{ - /* Initialize network */ - dnn::Net net; + + String imagefile = (argc > 1) ? argv[1] : "space_shuttle.jpg"; + + //! [input_blob_preparation] + Mat img = imread(imagefile); + if (img.empty()) { - String modelTxt = "bvlc_googlenet.prototxt"; - String modelBin = "bvlc_googlenet.caffemodel"; - - Ptr importer; //Try to import Caffe GoogleNet model - try - { - importer = dnn::createCaffeImporter(modelTxt, modelBin); - } - catch(const cv::Exception &er) //importer can throw errors, we will catch them - { - std::cerr << er.msg << std::endl; - importer = Ptr(); //NULL - } - - 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 << "Please, check them." << 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); - } - - importer->populateNet(net); + std::cerr << "Can't read image from the file: " << imagefile << std::endl; + exit(-1); } - std::vector classNames = readClassNames(); + //GoogLeNet accepts only 224x224 RGB-images + cvtColor(img, img, COLOR_BGR2RGB); + resize(img, img, Size(224, 224)); - String filename = (argc > 1) ? argv[1] : "space_shuttle.jpg"; + dnn::Blob inputBlob = dnn::Blob(img); + //! [input_blob_preparation] - Blob inputBlob = makeInputBlob(filename); //make batch - net.setBlob(".data", inputBlob); //set this blob to the network input + //! [setup_blob] + net.setBlob(".data", inputBlob); //set the network input + //! [setup_blob] + + //! [make_forward] net.forward(); //compute output + //! [make_forward] - dnn::Blob prob = net.getBlob("prob"); //gather output of prob layer - ClassProb bc = getMaxClass(prob); //find best class + //! [get_output] + dnn::Blob prob = net.getBlob("prob"); //gather output of "prob" layer - String className = classNames.at(bc.first); + int classId; + double classProb; + getMaxClass(prob, &classId, &classProb); //find the best class + //! [get_output] - std::cout << "Best class:"; - std::cout << " #" << bc.first; - std::cout << " (from " << prob.total(1) << ")"; - std::cout << " \"" + className << "\""; - std::cout << std::endl; - std::cout << "Prob: " << bc.second * 100 << "%" << std::endl; + //! [print_info] + std::vector classNames = readClassNames(); + std::cout << "Best class: #" << classId << " '" << classNames.at(classId) << "'" << std::endl; + std::cout << "Probability: " << classProb * 100 << "%" << std::endl; + //! [print_info] return 0; } diff --git a/modules/dnn/tutorials/images/space_shuttle.jpg b/modules/dnn/tutorials/images/space_shuttle.jpg new file mode 100644 index 0000000000000000000000000000000000000000..412a919694c0b0141ba0fa7003fbfc800dd1040d GIT binary patch literal 27598 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 literal 0 HcmV?d00001 diff --git a/modules/dnn/tutorials/tutorial_dnn_build.markdown b/modules/dnn/tutorials/tutorial_dnn_build.markdown index 14ba758a7..32bf3194c 100644 --- a/modules/dnn/tutorials/tutorial_dnn_build.markdown +++ b/modules/dnn/tutorials/tutorial_dnn_build.markdown @@ -32,18 +32,18 @@ git clone https://github.com/Itseez/opencv_contrib - choose the preffered project generator (Makefiles for Linux, MS Visual Studio for Windows); - also you can set many opencv build options, for more details see @ref tutorial_linux_install. --# In the appeared list of variables find variable `OPENCV_EXTRA_MODULES_PATH` and set it to the **opencv_root**/opencv_contrib. +-# In the appeared list of build parameters find parameter `OPENCV_EXTRA_MODULES_PATH` and set it to the **opencv_root**/opencv_contrib. -# *Configure* the project again, and set build options of dnn module: - - `BUILD_opencv_dnn` variable must exist and be checked. + - `BUILD_opencv_dnn` parameter must exist and be checked. - dnn module covers waste part of [Caffe](http://caffe.berkeleyvision.org) framework functionality. However, to load Caffe networks libprotobuf is required. You you can uncheck `BUILD_LIBPROTOBUF_FROM_SOURCES` flag to try use protobuf installed in your system. Elsewise libpotobuf will be built from opencv sources. - - You can additionaly check `opencv_dnn_BUILD_TORCH_IMPORTER` variable to build [Torch7](http://torch.ch) importer. + - You can additionaly check `opencv_dnn_BUILD_TORCH_IMPORTER` parameter to build [Torch7](http://torch.ch) importer. It allows you to use networks, generated by Torch7 [nn](https://github.com/torch/nn/blob/master/README.md) module. -# *Generate* the project and build it: diff --git a/modules/dnn/tutorials/tutorial_dnn_googlenet.markdown b/modules/dnn/tutorials/tutorial_dnn_googlenet.markdown new file mode 100644 index 000000000..cc03acbb1 --- /dev/null +++ b/modules/dnn/tutorials/tutorial_dnn_googlenet.markdown @@ -0,0 +1,64 @@ +Load Caffe framework models {#tutorial_dnn_googlenet} +=========================== + +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](http://caffe.berkeleyvision.org/model_zoo.html). + +We will demostrate results of this example on the following picture. +![Buran space shuttle](images/space_shuttle.jpg) + +Source Code +----------- + +We will be using snippets from the example application, that can be downloaded [here](https://github.com/ludv1x/opencv_contrib/blob/master/modules/dnn/samples/caffe_googlenet.cpp). + +Explanation +----------- + +-# Firstly, download GoogLeNet model files: + [bvlc_googlenet.prototxt ](https://raw.githubusercontent.com/ludv1x/opencv_contrib/master/modules/dnn/samples/bvlc_googlenet.prototxt) and + [bvlc_googlenet.caffemodel](http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel) + + Also you need file with names of [ILSVRC2012](http://image-net.org/challenges/LSVRC/2012/browse-synsets) classes: + [synset_words.txt](https://raw.githubusercontent.com/ludv1x/opencv_contrib/master/modules/dnn/samples/synset_words.txt). + + Put these files into working dir of this program example. + +-# Create the importer of Caffe models + @snippet dnn/samples/caffe_googlenet.cpp importer_creation + +-# Create the network and initialize its by using the created importer + @snippet dnn/samples/caffe_googlenet.cpp network_initialization + +-# Read input image and convert to the blob, acceptable by GoogleNet + @snippet dnn/samples/caffe_googlenet.cpp input_blob_preparation + 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 @ref cv::dnn::Blob constructor. + +-# Pass the blob to the network + @snippet dnn/samples/caffe_googlenet.cpp setup_blob + 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 + @snippet dnn/samples/caffe_googlenet.cpp make_forward + 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 + @snippet dnn/samples/caffe_googlenet.cpp get_output + 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 the results + @snippet dnn/samples/caffe_googlenet.cpp print_info + For our image we get: +> Best class: #812 'space shuttle' +> +> Probability: 99.6378% \ No newline at end of file