如何在iOS上使用caffemodel和OpenCV?

时间:2016-08-22 15:27:28

标签: c++ ios opencv caffe

我正在尝试在iOS设备上使用.caffemodel和OpenCV。我找到了这个github repository,但它只能用Xcode 6构建。我正在使用Xcode 7,但我也下载了Xcode 6,但仍然没有成功构建它。

如何在iOS 9上使用带有OpenCV的caffemodel?

PS:另一种选择是this,但是用swift&金属,我需要能够与OpenCV一起使用。

2 个答案:

答案 0 :(得分:2)

您可以使用OpenCV DNN contrib module

首先需要使用contrib模块构建OpenCV,您可以找到步骤here

然后,您可以导入并使用this tutorial之后的.caffemodel

以下是本教程的更新版本,因为它不能正常工作:

#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)
{
    cv::dnn::initModule();        

    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 batch of images
    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

答案 1 :(得分:1)

我将发布另一个答案,因为与最新版本有所不同。

首先dnn已经在标准OpenCV库中,因此您不必从contrib_modules进行构建。

加载网络的功能是readNetFromCaffe

例如,以下代码加载NN:

  std::string modelName = "path/to/mymodel.caffemodel";

  std::string protoName = "path/to/deploy.prototxt";
  cv::dnn::Net net;
  try
  {
    net = cv::dnn::readNetFromCaffe(protoName, modelName);
  }
  catch (cv::Exception& e)
  {
    std::cerr << "Exception: " << e.what() << std::endl;
    if (net.empty())
    {
      std::cerr << "Can't load network by using the following files: " << std::endl;
      std::cerr << "prototxt:   " << protoName << std::endl;
      std::cerr << "caffemodel: " << modelName << 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);
    }
  }

然后您可以运行NN:

  cv::Mat res_mat;
  float res;
  cv::Mat inputBlob = cv::dnn::blobFromImage(roi, 1.0f, cv::Size(227, 227),
                                  cv::Scalar(0, 0, 0), false);
  net.setInput(inputBlob);
  //During the forward pass output of each network layer is computed,
  //but in this example we need output from "prob" layer only.
  res_mat = net.forward("score");
  std::cout<<res_mat<<std::endl;
  res_mat = res_mat.reshape(1, 1); //reshape the blob to 1x2 matrix
  return res_mat.at<float>(0); 

函数cv::dnn::blobFromImage将图像调整为第三个参数(在我的情况下为cv::Size(227, 227))中指定的输入网络大小。参数cv::Scalar(0, 0, 0)是从三个BGR通道中减去均值。

score是我使用的NN中输出层的名称。您可以在prototxt文件中看到此信息。