OpenCV3.3深度学习模块(DNN)应用-图像分类

OpenCV3.3深度学习模块(DNN)应用-图像分类

  2017-09-17  gloomyfish  OpenCV学堂

DNN模块介绍

在OpenCV3.3版本发布中把DNN模块从扩展模块移到了OpenCV正式发布模块中,当前DNN模块最早来自Tiny-dnn,可以加载预先训练好的Caffe模型数据,OpenCV做了近一步扩展支持所有主流的深度学习框架训练生成与导出模型数据加载,常见的有如下:

  • Caffe

  • TensorFlow

  • Torch/PyTorch 


OpenCV中DNN模块已经支持与测试过这些常见的网络模块

  • AlexNet

  • GoogLeNet v1 (also referred to as Inception-5h)

  • ResNet-34/50/...

  • SqueezeNet v1.1

  • VGG-based FCN (semantical segmentation network)

  • ENet (lightweight semantical segmentation network)

  • VGG-based SSD (object detection network)

  • MobileNet-based SSD (light-weight object detection network)

一:GoogleNet Caffe模型数据说明

OpenCV通过支持加载这些预先训练好的模型,实现图像分类、对象检测、语义分割、风格迁移等功能。支持Android/iOS等移动端平台开发。下面我们就以OpenCV3.3 使用Caffe的GoogleNet数据模型为例,实现对图像常见分类,OpenCV3.3的DNN模块使用的模型支持1000种常见图像分类、googlenet深度学习网络模型是2014图像分类比赛的冠军、首先是下载相关的数据模型文件

  • bvlc_googlenet.caffemodel

  • bvlc_googlenet.prototxt

其中prototxt是一个文本的JSON文件、一看就明白啦,另外一个文件二进制文件。文本文件只有你下载了OpenCV3.3解压缩之后就会在对应的目录发现。模型文件需要从以下地址下载即可: http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel

二:编程实现

首先我们需要加载它官方指定的一张测试图像space_shuttle.jpg 是一张航天飞机的图片、OpenCV中加载图像的代码如下:

  
  
  1.    Mat testImage = imread("D:/vcprojects/images/dnn/football.jpg");

  2.    if (testImage.empty()) {

  3.        printf("could not load image...\n");

  4.        return -1;

  5.    }

然后我们需要声明模型数据的路径与标记数据路径,加载创建网络模型,代码实现如下:

  
  
  1.    // create googlenet with caffemodel text and bin

  2.    Net net = dnn::readNetFromCaffe(modelTxt, modelBin);

  3.    if (net.empty())

  4.    {

  5.        std::cerr << "Can't load network by using the following files: " << std::endl;

  6.        std::cerr << "prototxt:   " << modelTxt << std::endl;

  7.        std::cerr << "caffemodel: " << modelBin << std::endl;

  8.        return -1;

  9.    }

  10.    // 读取分类数据

  11.    vector<String> labels = readClasslabels();

  12.    //GoogLeNet accepts only 224x224 RGB-images

  13.    Mat inputBlob = blobFromImage(testImage, 1, Size(224, 224), Scalar(104, 117, 123));

然后开始分类预测,根据prototxt中的开始的要求,我们需要输入迭代10次,输出预测分类的结果,代码实现如下:

  
  
  1. // 支持1000个图像分类检测

  2.    Mat prob;

  3.    // 循环10+

  4.    for (int i = 0; i < 10; i++)

  5.    {

  6.        // 输入

  7.        net.setInput(inputBlob, "data");        

  8.        // 分类预测

  9.        prob = net.forward("prob");

  10.    }

  11.    // 读取分类索引,最大与最小值

  12.    Mat probMat = prob.reshape(1, 1); //reshape the blob to 1x1000 matrix // 1000个分类

  13.    Point classNumber;

  14.    double classProb;

  15.    minMaxLoc(probMat, NULL, &classProb, NULL, &classNumber); // 可能性最大的一个

  16.    int classIdx = classNumber.x; // 分类索引号

  17.    printf("\n current image classification : %s, possible : %.2f \n", labels.at(classIdx).c_str(), classProb);

  18.    putText(testImage, labels.at(classIdx), Point(20, 20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0, 0, 255), 2, 8);

  19.    imshow("Image Category", testImage);

其中读取图像分类索引与文本描述的方法代码如下:

  
  
  1. vector<String> readClasslabels() {

  2.    std::vector<String> classNames;

  3.    std::ifstream fp(labelFile);

  4.    if (!fp.is_open())

  5.    {

  6.        std::cerr << "File with classes labels not found: " << labelFile << std::endl;

  7.        exit(-1);

  8.    }

  9.    std::string name;

  10.    while (!fp.eof())

  11.    {

  12.        std::getline(fp, name);

  13.        if (name.length())

  14.            classNames.push_back(name.substr(name.find(' ') + 1));

  15.    }

  16.    fp.close();

  17.    return classNames;

  18. }

 
 
  1. #include <opencv2/opencv.hpp>

  2. #include <opencv2/dnn.hpp>

  3. #include <iostream>

  4. using namespace cv;

  5. using namespace cv::dnn;

  6. using namespace std;

  7. String modelTxt = "D:/vcprojects/images/dnn/bvlc_googlenet.prototxt";

  8. String modelBin = "D:/vcprojects/images/dnn/bvlc_googlenet.caffemodel";

  9. String labelFile = "D:/vcprojects/images/dnn/synset_words.txt";

  10. vector<String> readClasslabels();

  11. int main(int argc, char** argv) {

  12.    Mat testImage = imread("D:/vcprojects/images/dnn/football.jpg");

  13.    if (testImage.empty()) {

  14.        printf("could not load image...\n");

  15.        return -1;

  16.    }

  17.    // create googlenet with caffemodel text and bin

  18.    Net net = dnn::readNetFromCaffe(modelTxt, modelBin);

  19.    if (net.empty())

  20.    {

  21.        std::cerr << "Can't load network by using the following files: " << std::endl;

  22.        std::cerr << "prototxt:   " << modelTxt << std::endl;

  23.        std::cerr << "caffemodel: " << modelBin << std::endl;

  24.        return -1;

  25.    }

  26.    // 读取分类数据

  27.    vector<String> labels = readClasslabels();

  28.    //GoogLeNet accepts only 224x224 RGB-images

  29.    Mat inputBlob = blobFromImage(testImage, 1, Size(224, 224), Scalar(104, 117, 123));

  30.    // 支持1000个图像分类检测

  31.    Mat prob;

  32.    // 循环10+

  33.    for (int i = 0; i < 10; i++)

  34.    {

  35.        // 输入

  36.        net.setInput(inputBlob, "data");        

  37.        // 分类预测

  38.        prob = net.forward("prob");

  39.    }

  40.    // 读取分类索引,最大与最小值

  41.    Mat probMat = prob.reshape(1, 1); //reshape the blob to 1x1000 matrix // 1000个分类

  42.    Point classNumber;

  43.    double classProb;

  44.    minMaxLoc(probMat, NULL, &classProb, NULL, &classNumber); // 可能性最大的一个

  45.    int classIdx = classNumber.x; // 分类索引号

  46.    printf("\n current image classification : %s, possible : %.2f \n", labels.at(classIdx).c_str(), classProb);

  47.    putText(testImage, labels.at(classIdx), Point(20, 20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0, 0, 255), 2, 8);

  48.    imshow("Image Category", testImage);

  49.    waitKey(0);

  50.    return 0;

  51. }

  52. /* 读取图像的1000个分类标记文本数据 */

  53. vector<String> readClasslabels() {

  54.    std::vector<String> classNames;

  55.    std::ifstream fp(labelFile);

  56.    if (!fp.is_open())

  57.    {

  58.        std::cerr << "File with classes labels not found: " << labelFile << std::endl;

  59.        exit(-1);

  60.    }

  61.    std::string name;

  62.    while (!fp.eof())

  63.    {

  64.        std::getline(fp, name);

  65.        if (name.length())

  66.            classNames.push_back(name.substr(name.find(' ') + 1));

  67.    }

  68.    fp.close();

  69.    return classNames;

  70. }


居不隐者,思不远也;

身不危者,志不广也!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值