前言

前面的博文中,我试了如何使用caffe训练得到想要的模型与其如何使用别人成熟的模型微调优化自己训练的模型,那么得到训练好的模型之后如何在自己的项目中呢,我这里使用opencv的DNN模块调用caffe训练好的模型,DNN是opencv3.0之后开始添加的功能,实现的语言是C++。

一、环境准备

1.windows 7 64位,Visual Studio 2015,opencv3.3加opencv_contrib,boost, win7、opencv3.3、opencv_contrib、vs2015相关配置我前面也有介绍过。
2.训练好的caffe模型,deploy.prototxt,标签文件labels.txt的文件建议按前面的博文生成相应的文件。

二、代码实现

代码用到opencv3的dnn模块和boost库,而boost是用来处理文件操作的,如果不用测试整个文件夹的图像,就不用引入boost库,可以把void categoryTestDir(string src_dir,string dst_dir)、void createDir(string path, vector dir_name)、vector getFileNameFromDir(string root_path)这三个成员函数的声明和代码部分注释掉。
类的头文件:ImageClassification.h

#pragma once
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core/utils/trace.hpp>
#include <fstream>
#include <iostream>
#include <cstdlib>
//boost 库
#include <boost/filesystem.hpp>
#include<boost/thread/thread.hpp>using namespace std;
using namespace cv;
using namespace cv::dnn;
//定义一个boost库的命名空间
namespace fs = boost::filesystem;class ImageClassification
{
public:ImageClassification();//构造函数,传入三个路径ImageClassification(string _model_txt_path, string _model_bin_path, string _labels_path);//得到置信值最大的类void getMaxClass(const Mat &probBlob);//读取标签文件vector<string> readClassNames(string labels_path);//对单张图像进行分类void classification(string image_path);//对整个文件夹的图像进行分类void categoryTestDir(string src_dir,string dst_dir);//创建文件夹void createDir(string path, vector<string> dir_name);//得到文件夹下第一层文件夹名vector<string> getFileNameFromDir(string root_path);~ImageClassification();
private:int class_id;double max_val;string model_txt_path, model_bin_path, labels_path;
};

类的实现文件:ImageClassification.cpp

#include "ImageClassification.h"ImageClassification::ImageClassification()
{
}ImageClassification::ImageClassification(string _model_txt_path, string _model_bin_path, string _labels_path)
{model_bin_path = _model_bin_path;model_txt_path = _model_txt_path;labels_path = _labels_path;
}void ImageClassification::getMaxClass(const Mat &prob_mat)
{//改变矩阵的通道数或对矩阵元素进行序列化Mat probMat = prob_mat.reshape(1, 1);Point max_loc;//查找全局最小和最大数组元素并返回它们的值和它们的位置minMaxLoc(prob_mat, NULL, &max_val, NULL, &max_loc);class_id = max_loc.x;
}vector<string> ImageClassification::readClassNames(string labels_path){vector<string> class_names;ifstream fp(labels_path);if (!fp.is_open()){cerr << "无法打开标签文件:" << labels_path << endl;exit(-1);}string name;while (!fp.eof()){getline(fp, name);if (name.length()){class_names.push_back(name.substr(name.find(' ') + 1));}}fp.close();return class_names;}void ImageClassification::classification(string image_path){//合成网络Net net = dnn::readNetFromCaffe(model_txt_path, model_bin_path);//判断网络是否生成成功if (net.empty()){cerr << "无法打开DNN网络文件!" << endl;exit(-1);}cerr << "打开DNN文件成功!" << endl;//读取图片Mat img = imread(image_path);if (img.empty()){cerr << "无法打开图像:" << image_path << endl;exit(-1);}//转换成GoogleNet能接受的数据格式(blob)文件//Mat inputBlob = blobFromImage(img, 1, Size(227, 227));//缩放图像,改变图像的通道顺序,现在图像是一个224x224x3的3维阵列;//使用blobFromImages把这个图像转换成一个1x3x224x224形状的4维对象(blob)。Mat inputBlob = blobFromImage(img, 1.0f, Size(224, 224), Scalar(104, 117, 123));Mat prob;//将构建的blob传入网络data层net.setInput(inputBlob, "data");//前向预测//在前向传输过程中,每一个网络层的输出都被计算,但在本例程中仅从“prob”层输出prob = net.forward("prob");//找出最高的概率ID存储在classId,对应的标签值在classProb中getMaxClass(prob);//打印出结果vector<string> class_names = readClassNames(labels_path);string out = "Best class:" + class_names.at(class_id);putText(img, out, Point(5, 30), FONT_HERSHEY_SIMPLEX, 0.8, Scalar(0, 255, 0), 2, 6);string probability = "Probability:" + to_string(max_val * 100) + "%";putText(img, probability, Point(5, 60), FONT_HERSHEY_SIMPLEX, 0.8, Scalar(0, 255, 0), 2, 6);imshow("image", img);waitKey(0);}void ImageClassification::categoryTestDir(string src_dir,string dst_dir){//合成网络Net net = dnn::readNetFromCaffe(model_txt_path, model_bin_path);//判断网络是否生成成功if (net.empty()){cerr << "无法打开DNN网络文件!" << endl;exit(-1);}cerr << "打开DNN文件成功!" << endl;fs::directory_iterator begin_train(src_dir);fs::directory_iterator end_train;//得到标签种类vector<string> class_names = readClassNames(labels_path);//按标签种类创建文件夹createDir(dst_dir, class_names);//得到目标文件夹第一层文件夹名vector<string> dir_name = getFileNameFromDir(dst_dir);//遍历路径下面的所有测试图像for (; begin_train != end_train; ++begin_train){string file_name = begin_train->path().string();fs::path file(file_name);Mat img;if (file.extension().string() != ".jpg"){continue;}//读取图片img = imread(file_name);if (img.empty()){cerr << "无法打开图像:" << file_name << endl;exit(-1);}//转换成GoogleNet能接受的数据格式(blob)文件//Mat inputBlob = blobFromImage(img, 1, Size(227, 227));//缩放图像,改变图像的通道顺序,现在图像是一个224x224x3的3维阵列;//使用blobFromImages把这个图像转换成一个1x3x224x224形状的4维对象(blob)。Mat inputBlob = blobFromImage(img, 1.0f, Size(224, 224), Scalar(104, 117, 123));Mat prob;//将构建的blob传入网络data层net.setInput(inputBlob, "data");//前向预测//在前向传输过程中,每一个网络层的输出都被计算,但在本例程中仅从“prob”层输出prob = net.forward("prob");//找出最高的概率ID存储在classId,对应的标签值在classProb中getMaxClass(prob);//移动图像到相关类的文件夹for (int j = 0; j < dir_name.size(); j++){if (class_names.at(class_id) == dir_name.at(j)){string str_file = file.stem().string();imwrite(dst_dir + class_names.at(class_id) + "/" + str_file + ".jpg", img);}}//在图像上打印输出string out = "Best class:" + class_names.at(class_id);putText(img, out, Point(5, 30), FONT_HERSHEY_SIMPLEX, 0.8, Scalar(0, 255, 0), 2, 6);string probability = "Probability:" + to_string(max_val * 100) + "%";putText(img, probability, Point(5, 60), FONT_HERSHEY_SIMPLEX, 0.8, Scalar(0, 255, 0), 2, 6);imshow("image", img);waitKey(10);}}//创建文件夹void ImageClassification::createDir(string path, vector<string> dir_name){fs::path dir(path);// 判断路径是否存在if (fs::exists(dir)){for (int i = 0; i < dir_name.size(); i++){string temp = path + dir_name.at(i);fs::path new_dir(temp);if (!fs::exists(new_dir)){fs::create_directory(temp);}}}}//得到路径下第一层的文件夹vector<string> ImageClassification::getFileNameFromDir(string root_path){vector<string> dir_name;boost::filesystem::path dir(root_path);//vector<string> class_name = readClassNames("E:/LIB/caffe-windows/data/fine_tuning/CPP/labels.txt");// 判断路径是否存在if (boost::filesystem::exists(dir)){boost::filesystem::directory_iterator itEnd;boost::filesystem::directory_iterator itDir(dir);string file_name;// 遍历路径下所有文件for (; itDir != itEnd; itDir++){file_name = itDir->path().string();// 判断文件是否是文件夹if (boost::filesystem::is_directory(file_name.c_str())){int last_index = file_name.find_last_of("\\");string name = file_name.substr(last_index + 1);dir_name.push_back(name);}}}return dir_name;}ImageClassification::~ImageClassification()
{
}

主文件:main.cpp

#include "ImageClassification.h"int main()
{//读取模型参数路径String model_txt_path = "E:/LIB/caffe-windows/data/fine_tuning/CPP/deploy.prototxt";//模型结构文件路径String model_bin_path = "E:/LIB/caffe-windows/data/fine_tuning/CPP/train_iter_800.caffemodel";//标签文件路径string labels_name = "E:/LIB/caffe-windows/data/fine_tuning/CPP/labels.txt";//单张读取图片string image_file_path = "E:/LIB/caffe-windows/data/fine_tuning/test/4126.jpg";//测试图像路径string test_path = "E:/LIB/caffe-windows/data/fine_tuning/test/";//保存测试图像路径string dst_path = "E:/LIB/caffe-windows/data/fine_tuning/";//实例化对象ImageClassification classificaton(model_txt_path, model_bin_path, labels_name);//测试单张图像classificaton.classification(image_file_path);//测试整个文件夹//classificaton.categoryTestDir(test_path, dst_path);system("pause");return 0;
}

三、测试代码

1.测试结果

2.把测试图像转换的时候,有一个要注意的地方,转换的参数会影响准确率,如下面两张图:


3.再对整个文件夹进行测试的时候,可以看到还是有一些判断不准确的图像,这个要继续优化。

后记

以上是从caffe训练开始到使用opencv调用训练好的模型的全部步骤,代码和训练时的参数都有很需要改进的地方,如果有兴趣的可以加群:487350510互相讨论学习。

Windows下Caffe的学习与应用(三)——使用OpenCV3调用自己训练好的Caffe模型进行图像分类相关推荐

  1. Windows进程与线程学习笔记(三)—— KPCR

    Windows进程与线程学习笔记(三)-- KPCR KPCR +0x000 NtTib : _NT_TIB +0x120 PrcbData : _KPRCB KPCR 描述:CPU控制区(Proce ...

  2. RCNN学习笔记——第三篇: 实现FRCNN网络训练、评价与预测(附全部源码)

    RCNN学习笔记--第三篇: 实现FRCNN网络训练.评价与预测(附全部源码) 本文是个人根据B站大佬Bubbliiiing的FRCNN系列视频同步完成FRCNN训练,记录心得和遇见的问题. 关于RC ...

  3. Windows下动态链接库和静态链接库的生成以及调用

    Windows下静态库和动态库的生成和调用 一.简介 二.生成静态链接库(.lib)和动态链接库(.dll) 三.静态链接库的调用 四.动态链接库的调用 动态链接库的两种调用方式 仅使用.dll文件 ...

  4. python caffe 训练自己的模型_python接口调用已训练好的caffe模型测试分类方法

    训练好了model后,可以通过python调用caffe的模型,然后进行模型测试的输出. 本次测试主要依靠的模型是在caffe模型里面自带训练好的结构参数:~/caffe/models/bvlc_re ...

  5. Windows下Libvirt Java API使用教程(三)- TLS认证访问和动态链接文件依赖

    之前已经介绍过了libvirt api的上手使用方式: <Windows下Libvirt Java API使用教程(二)- 接口使用说明> <Windows下Libvirt Java ...

  6. windows下vue-cli及webpack 构建网站(三)使用组件

    1.本文章是建立在<windows下vue-cli及webpack 构建网站(一)环境安装>和<windows下vue-cli及webpack 构建网站(一)导入bootstrap样 ...

  7. 在ubuntu下使用cmake进行opencv的配置和Windows下进行使用cmake编译源代码比较,opencv3进行g++例子程序编译、动态库的制作

    1.首先安装的是cmake软件,使用指令: apt-get install cmake 接着查看版本,测试是否安装成功: root@emouse:/home# cmake --version cmak ...

  8. 【深度学习】ToMe:我的方法无需训练即可加速 ViT 模型|搞懂Transformer系列

    作者丨科技猛兽 编辑丨极市平台 导读 这篇文章提出了一种无需训练即可加速 ViT 模型,提高吞吐量的方法 Token Merging (ToMe).ToMe 通过一种轻量化的匹配算法,逐步合并 ViT ...

  9. Windows下Caffe的学习与应用(二)——优化自己训练的模型(fine-tuning)

    前言 在前面的博文中,我们也看到,在进行训练的样本比较少,每个种类的样本只有120张,迭代次数为100代,训练得到的模型在测试那些特征不那么明显图像时,准确率达不到我们想要的效果.如果下图: 测试的结 ...

最新文章

  1. ubuntu——python
  2. 【ESP8266】NONOS SDK开发,串口发送、接收与中断
  3. 美国不要求计算机背景的学校,美国哪些院校计算机专业不需要CS背景
  4. 仔细研究Java Identity API
  5. Vue(二十八)el-cascader 动态加载 - 省市区组件
  6. Visual Studio 2010旗舰版在安装Windows Phone 7 SDK后项目模版里没有Windows Phone 项目解决办法...
  7. 前端学习(2262)vue造轮子框架搭建
  8. php null截断 漏洞,CVE-2015-3412,CNNVD-201507-164|PHP NULL Character 安全漏洞 - 信息安全漏洞门户 VULHUB...
  9. ubuntu高版本环境变量问题
  10. 服务器 自检 修改,检查多台服务器初始密码是否修改的shell脚本
  11. ARM太贵,80多家科技巨头悄然站队开源芯片架构RISC-V
  12. [转]网络编程学习指南
  13. 1709意思_期货m1709是什么意思
  14. ZendFramework-2.4 源代码 - 整体架构(类图)
  15. 计算机A级学科排名,“计算机科学与技术”学科排名出炉,上交大无缘A+吉大表现亮眼...
  16. 有截图功能的android播放器,Android视频播放器VPlayer发新版本 增加截图功能
  17. 【HDU4622】Reincarnation
  18. [附源码]计算机毕业设计springboot基于Vue的社区拼购商城
  19. php 如何实现心跳包,Socket心跳机制-JS+PHP实现
  20. keil创建无启动文件及自定义.sct文件的工程

热门文章

  1. 安装python3.8.0步骤_python3.8.0安装教程_后端开发
  2. 如何解决没有文件扩展“.js”的脚本引擎
  3. java 常用十种设计模式示例归纳 | 已打包请带走
  4. notepad++的好用快捷键整理
  5. Java 单例模式探讨
  6. 写给准爸爸的专业指导
  7. Matlab矩阵函数
  8. 用C语言实现三子棋游戏
  9. Spring Cloud的全局封装实践
  10. 校园交易平台后台系统git操作全过程