2016.12.14:

代码已知bug:

由于类中有全局变量,声明多个对象时,全局变量指向会改变,造成结果错误并且有内存泄漏。因此该份代码只能声明一个Classifier对象。

新的代码已经重新封装,并且做成多标签输出,下载地址:http://download.csdn.net/detail/sinat_30071459/9715053

主要修改:http://blog.csdn.net/sinat_30071459/article/details/53611678

因为caffe-windows-master的代码比较多,看着很乱,所以想到把它封装成一个类来调用做图像分类,这里以GPU版本为例,记录一下自己封装成DLL和如何使用封装后的DLL的过程。

1.打开解决方案

首先,需要修改解决方案配置(默认是Release),我们新建一个叫ReleaseGPU,平台修改为x64(因为用到的其他DLL是64位,配置成win32会出错),如下:

这里我将caffelib的项目名改成了type_recognition_ver2_api_gpu,配置好ReleaseGPU后,右键项目type_recognition_ver2_api_gpu——>属性,配置属性页:

(1)配置属性——常规

(2)C/C++——常规——附加包含目录:

../../3rdparty/include

../../src

../../include

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5\include

预处理器——预处理器定义添加:

TYPE_RECOGNITION_LINK_SHARED
TYPE_RECOGNITION_API_EXPORTS

(3)链接器——常规——附加库目录:

../../3rdparty/lib

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5\lib\x64

(4)链接器——输入——附加依赖项:

kernel32.lib
user32.lib
gdi32.lib
winspool.lib
shell32.lib
ole32.lib
oleaut32.lib
uuid.lib
comdlg32.lib
advapi32.lib
cudart.lib
cublas.lib
curand.lib
libprotobuf.lib
hdf5_tools.lib
hdf5_hl_fortran.lib
hdf5_fortran.lib
hdf5_hl_f90cstub.lib
hdf5_f90cstub.lib
hdf5_cpp.lib
hdf5_hl_cpp.lib
hdf5_hl.lib
hdf5.lib
zlib.lib
szip.lib
opencv_world300.lib
shlwapi.lib
leveldb.lib
cublas_device.lib
cuda.lib
libglog.lib
lmdb.lib
cudnn.lib
libopenblas.dll.a
libgflags.lib

这样就配置好了。

2.添加文件

(1)添加classfy.h和classify.cpp

[plain] view plaincopy
  1. //classify.h
  2. #pragma once
  3. #include <caffe/caffe.hpp>
  4. #include <opencv2/core/core.hpp>
  5. #include <opencv2/highgui/highgui.hpp>
  6. #include <opencv2/imgproc/imgproc.hpp>
  7. #include <iosfwd>
  8. #include <memory>
  9. #include <utility>
  10. #include <vector>
  11. #include <iostream>
  12. #include <string>
  13. #include <fstream>
  14. #include <sstream>
  15. using namespace caffe;  // NOLINT(build/namespaces)
  16. //using namespace boost::property_tree;
  17. using std::string;
  18. /* Pair (number, confidence) representing a prediction. */
  19. typedef std::pair<int, float> Prediction;
  20. class ClassifierImpl {
  21. public:
  22. ClassifierImpl::ClassifierImpl(){};
  23. ClassifierImpl(const string& model_file,
  24. const string& trained_file,
  25. const string& mean_file,
  26. const string& label_file);
  27. std::vector<Prediction> Classify(const cv::Mat& img, int N = 2);
  28. private:
  29. void SetMean(const string& mean_file);
  30. std::vector<float> Predict(const cv::Mat& img);
  31. void WrapInputLayer(std::vector<cv::Mat>* input_channels);
  32. void Preprocess(const cv::Mat& img,
  33. std::vector<cv::Mat>* input_channels);
  34. private:
  35. shared_ptr<Net<float> > net_;
  36. cv::Size input_geometry_;
  37. int num_channels_;
  38. cv::Mat mean_;
  39. };
[plain] view plaincopy
  1. //classify.cpp
  2. #include "classify.h"
  3. ClassifierImpl::ClassifierImpl(const string& model_file,
  4. const string& trained_file,
  5. const string& mean_file,
  6. const string& label_file)
  7. {
  8. #ifdef CPU_ONLY
  9. Caffe::set_mode(Caffe::CPU);
  10. #else
  11. Caffe::set_mode(Caffe::GPU);
  12. #endif
  13. /* Load the network. */
  14. net_.reset(new Net<float>(model_file, TEST));
  15. net_->CopyTrainedLayersFrom(trained_file);
  16. CHECK_EQ(net_->num_inputs(), 1) << "Network should have exactly one input.";
  17. CHECK_EQ(net_->num_outputs(), 1) << "Network should have exactly one output.";
  18. Blob<float>* input_layer = net_->input_blobs()[0];
  19. num_channels_ = input_layer->channels();
  20. CHECK(num_channels_ == 3 || num_channels_ == 1)
  21. << "Input layer should have 1 or 3 channels.";
  22. input_geometry_ = cv::Size(input_layer->width(), input_layer->height());
  23. /* Load the binaryproto mean file. */
  24. SetMean(mean_file);
  25. Blob<float>* output_layer = net_->output_blobs()[0];
  26. }
  27. static bool PairCompare(const std::pair<float, int>& lhs,
  28. const std::pair<float, int>& rhs) {
  29. return lhs.first > rhs.first;
  30. }
  31. /* Return the indices of the top N values of vector v. */
  32. static std::vector<int> Argmax(const std::vector<float>& v, int N) {
  33. std::vector<std::pair<float, int> > pairs;
  34. for (size_t i = 0; i < v.size(); ++i)
  35. pairs.push_back(std::make_pair(v[i], i));
  36. std::partial_sort(pairs.begin(), pairs.begin() + N, pairs.end(), PairCompare);
  37. std::vector<int> result;
  38. for (int i = 0; i < N; ++i)
  39. result.push_back(pairs[i].second);
  40. return result;
  41. }
  42. /* Return the top N predictions. */
  43. std::vector<Prediction> ClassifierImpl::Classify(const cv::Mat& img, int N) {
  44. std::vector<float> output = Predict(img);
  45. std::vector<int> maxN = Argmax(output, N);
  46. std::vector<Prediction> predictions;
  47. for (int i = 0; i < N; ++i) {
  48. int idx = maxN[i];
  49. predictions.push_back(std::make_pair(idx, output[idx]));
  50. }
  51. return predictions;
  52. }
  53. /* Load the mean file in binaryproto format. */
  54. void ClassifierImpl::SetMean(const string& mean_file) {
  55. BlobProto blob_proto;
  56. ReadProtoFromBinaryFileOrDie(mean_file.c_str(), &blob_proto);
  57. /* Convert from BlobProto to Blob<float> */
  58. Blob<float> mean_blob;
  59. mean_blob.FromProto(blob_proto);
  60. CHECK_EQ(mean_blob.channels(), num_channels_)
  61. << "Number of channels of mean file doesn't match input layer.";
  62. /* The format of the mean file is planar 32-bit float BGR or grayscale. */
  63. std::vector<cv::Mat> channels;
  64. float* data = mean_blob.mutable_cpu_data();
  65. for (int i = 0; i < num_channels_; ++i) {
  66. /* Extract an individual channel. */
  67. cv::Mat channel(mean_blob.height(), mean_blob.width(), CV_32FC1, data);
  68. channels.push_back(channel);
  69. data += mean_blob.height() * mean_blob.width();
  70. }
  71. /* Merge the separate channels into a single image. */
  72. cv::Mat mean;
  73. cv::merge(channels, mean);
  74. /* Compute the global mean pixel value and create a mean image
  75. * filled with this value. */
  76. cv::Scalar channel_mean = cv::mean(mean);
  77. mean_ = cv::Mat(input_geometry_, mean.type(), channel_mean);
  78. }
  79. std::vector<float> ClassifierImpl::Predict(const cv::Mat& img) {
  80. Blob<float>* input_layer = net_->input_blobs()[0];
  81. input_layer->Reshape(1, num_channels_,
  82. input_geometry_.height, input_geometry_.width);
  83. /* Forward dimension change to all layers. */
  84. net_->Reshape();
  85. std::vector<cv::Mat> input_channels;
  86. WrapInputLayer(&input_channels);
  87. Preprocess(img, &input_channels);
  88. net_->ForwardPrefilled();
  89. /* Copy the output layer to a std::vector */
  90. Blob<float>* output_layer = net_->output_blobs()[0];
  91. const float* begin = output_layer->cpu_data();
  92. const float* end = begin + output_layer->channels();
  93. return std::vector<float>(begin, end);
  94. }
  95. /* Wrap the input layer of the network in separate cv::Mat objects
  96. * (one per channel). This way we save one memcpy operation and we
  97. * don't need to rely on cudaMemcpy2D. The last preprocessing
  98. * operation will write the separate channels directly to the input
  99. * layer. */
  100. void ClassifierImpl::WrapInputLayer(std::vector<cv::Mat>* input_channels) {
  101. Blob<float>* input_layer = net_->input_blobs()[0];
  102. int width = input_layer->width();
  103. int height = input_layer->height();
  104. float* input_data = input_layer->mutable_cpu_data();
  105. for (int i = 0; i < input_layer->channels(); ++i) {
  106. cv::Mat channel(height, width, CV_32FC1, input_data);
  107. input_channels->push_back(channel);
  108. input_data += width * height;
  109. }
  110. }
  111. void ClassifierImpl::Preprocess(const cv::Mat& img,
  112. std::vector<cv::Mat>* input_channels) {
  113. /* Convert the input image to the input image format of the network. */
  114. cv::Mat sample;
  115. if (img.channels() == 3 && num_channels_ == 1)
  116. cv::cvtColor(img, sample, CV_BGR2GRAY);
  117. else if (img.channels() == 4 && num_channels_ == 1)
  118. cv::cvtColor(img, sample, CV_BGRA2GRAY);
  119. else if (img.channels() == 4 && num_channels_ == 3)
  120. cv::cvtColor(img, sample, CV_BGRA2BGR);
  121. else if (img.channels() == 1 && num_channels_ == 3)
  122. cv::cvtColor(img, sample, CV_GRAY2BGR);
  123. else
  124. sample = img;
  125. cv::Mat sample_resized;
  126. if (sample.size() != input_geometry_)
  127. cv::resize(sample, sample_resized, input_geometry_);
  128. else
  129. sample_resized = sample;
  130. cv::Mat sample_float;
  131. if (num_channels_ == 3)
  132. sample_resized.convertTo(sample_float, CV_32FC3);
  133. else
  134. sample_resized.convertTo(sample_float, CV_32FC1);
  135. cv::Mat sample_normalized;
  136. cv::subtract(sample_float, mean_, sample_normalized);
  137. /* This operation will write the separate BGR planes directly to the
  138. * input layer of the network because it is wrapped by the cv::Mat
  139. * objects in input_channels. */
  140. cv::split(sample_normalized, *input_channels);
  141. CHECK(reinterpret_cast<float*>(input_channels->at(0).data)
  142. == net_->input_blobs()[0]->cpu_data())
  143. << "Input channels are not wrapping the input layer of the network.";
  144. }

然后,我们再写一个导出类即可(如下(2))。

(2)添加type_recognition_ver2_api_gpu.h和type_recognition_ver2_api_gpu.cpp

[plain] view plaincopy
  1. //type_recognition_ver2_api_gpu.h
  2. #ifndef TYPE_RECOGNITION_API_H_  //保证头文件包含一次
  3. #define TYPE_RECOGNITION_API_H_
  4. #ifdef TYPE_RECOGNITION_LINK_SHARED
  5. #if defined(__GNUC__) && __GNUC__ >= 4
  6. #define TYPE_RECOGNITION_API __attribute__ ((visibility("default")))
  7. #elif defined(__GNUC__)
  8. #define TYPE_RECOGNITION_API
  9. #elif defined(_MSC_VER)
  10. #if defined (TYPE_RECOGNITION_API_EXPORTS)
  11. #define TYPE_RECOGNITION_API __declspec(dllexport)
  12. #else
  13. #define TYPE_RECOGNITION_API __declspec(dllimport)
  14. #endif
  15. #else
  16. #define TYPE_RECOGNITION_API
  17. #endif
  18. #else
  19. #define TYPE_RECOGNITION_API
  20. #endif
  21. #include <opencv2/core/core.hpp>
  22. #include <string>
  23. #include <vector>
  24. /* Pair (label, confidence) representing a prediction. */
  25. typedef std::pair<int, float> Prediction;
  26. class TYPE_RECOGNITION_API Classifier //导出类
  27. {
  28. public:
  29. Classifier(){};
  30. ~Classifier();
  31. Classifier(const std::string& model_file,
  32. const std::string& trained_file,
  33. const std::string& mean_file,
  34. const std::string& label_file);
  35. std::vector<Prediction> Classify(const cv::Mat& img, int N = 2);
  36. };
  37. #endif
[plain] view plaincopy
  1. //type_recognition_ver2_api_gpu.cpp
  2. #include "type_recognition_ver2_api_gpu.h"
  3. #include "classify.h"
  4. ClassifierImpl *impl = NULL;
  5. Classifier::Classifier(const std::string& model_file,
  6. const std::string& trained_file,
  7. const std::string& mean_file,
  8. const std::string& label_file)
  9. {
  10. #ifdef _MSC_VER
  11. #pragma comment( linker, "/subsystem:windows")
  12. #endif
  13. impl = new ClassifierImpl(model_file, trained_file, mean_file, label_file);
  14. }
  15. Classifier::~Classifier()
  16. {
  17. //impl->~ClassifierImpl();
  18. if (impl)
  19. delete impl;
  20. }
  21. std::vector<Prediction> Classifier::Classify(const cv::Mat& img, int N)
  22. {
  23. return impl->Classify(img, N);
  24. }

这时,右键type_recognition_ver2_api_gpu项目,生成即可,在ReleaseGPU文件夹内即可得到如下文件:


用到的文件是dll和lib文件,使用这些文件方法如下。

3.使用DLL

将type_recognition_ver2_api_gpu.dll复制到caffe-windows-master\3rdparty\bin;

将type_recognition_ver2_api_gpu.lib复制到caffe-windows-master\3rdparty\lib;

将type_recognition_ver2_api_gpu.h复制到caffe-windows-master\3rdparty\include;

然后,新建一个控制台项目,配置成x64,

右键项目配置如下:

C/C++——常规——附加包含目录:(这里路径自己修改)

********\3rdparty\include

链接器——常规——附加库目录:

********\3rdparty\lib

链接器——输入——附加依赖项:

将type_recognition_ver2_api_gpu.lib和opencv_world300.lib加进去,

然后,为项目添加一个cpp文件:

[plain] view plaincopy
  1. #include <iostream>
  2. #include <string>
  3. #include <opencv2/core/core.hpp>
  4. #include <opencv2/highgui/highgui.hpp>
  5. #include "type_recognition_ver2_api_gpu.h"
  6. int main(int argc, char** argv)
  7. {
  8. std::string model_file("./model/deploy.prototxt");
  9. std::string trained_file("./model/net.caffemodel");
  10. std::string mean_file("./model/type_mean.binaryproto");
  11. std::string label_file("./model/typelabels.txt");
  12. Classifier myclassifier(model_file, trained_file, mean_file, label_file);
  13. cv::Mat img = cv::imread("../image/automobile/000001.jpg", -1);
  14. std::vector<Prediction> result = myclassifier.Classify(img);
  15. Prediction p = result[0];
  16. std::cout <<"类别:"<< p.first << "确信度:" << p.second << "\n";
  17. getchar();
  18. return 0;
  19. }

结果:

下面链接的代码有bug,声明多个对象会出问题,新的代码:http://blog.csdn.net/sinat_30071459/article/details/53735600)

封装好的代码加入了OpenCV显示图像,可通过链接下载:http://download.csdn.net/detail/sinat_30071459/9568131  是一个txt文件,因为csdn上传限制,上传到了百度云,txt里面有百度云链接。

将Classification\CLassificationDLL\bin加入环境变量后即可。

效果如下:(把Freetype库也加了进去,标签可以显示中文)

封装caffe-windows-master为动态链接库相关推荐

  1. jenkins使用Git为源码管理(windows master linux slave)

    作为一个不太经常总结的人,工作以来碰到过太多问题!往往解决之后没有有效记录,导致再次碰到需要重新查资料解决.现在改变下习惯,努力搞的了技术. 公司最近提倡开源(以前啥都机密,即使开源也没改变多少),代 ...

  2. Caffe Windows版本的编译

    2019独角兽企业重金招聘Python工程师标准>>> 1:Caffe的主版本只支持Linux,所以要下载专门的Caffe Windows版本,网址为 https://github. ...

  3. caffe windows学习:第一个测试程序

    caffe windows编译成功后,就可以开始进行测试了.如果还没有编译成功的,请参考:caffe windows 学习第一步:编译和安装(vs2012+win 64) 一般第一个测试都是建议对手写 ...

  4. caffe windows 学习第一步:编译和安装(vs2012+win 64)

    转载自:http://www.cnblogs.com/denny402/p/5041060.html 没有GPU,没有linux, 只好装caffe的windows版本了. 我的系统是win10(64 ...

  5. Jmeter分布式压测-windows(master控制机)多个linux(slaves负载机)监测服务器资源(cpu、内存等)

    为什么进行jmeter分布式压测? 一.干货解释原因: **原因一:**一台压力机的 Jmeter 默认最大支持 1000 左右的并发用户数(线程数),再大的话,容易造成卡顿.无响应等情况,这是受限于 ...

  6. caffe windows 训练自己的图片数据

    caffe训练自己的数据分为四步: 1.图片数据集准备 2.网络训练所需数据格式 lmdb / leveldb 转换 3.图像均值文件计算 4.网络训练 具体过程如下: 一.图片数据集准备 图片数据收 ...

  7. Windows平台下动态链接库的总结

    1. 动态链接库与静态连接库 静态连接库与动态链接库都是经过编译器编译之后的,在计算机上可以直接运行的二进制目标文件,就像exe文件一样,但不同于exe文件的是静态链接库和动态链接库不可以独立运行,一 ...

  8. QT Windows下生成动态链接库

    目标:需要将一个QT程序生成动态链接库 Windows环境下Qt生成的共享库文件其后缀为dll,可以在程序运行过程中动态加载 新建项目,选择库 选择共享库 建立好项目后生成三个文件,两个.h一个.cp ...

  9. caffe/ windows 10 /Can't parse message of type caffe.NetParameter because it is missing required

    背景 将linux下训练的caffemodel移植到windows上使用但是出现以下错误提示:Can't parse message of type "caffe.NetParameter& ...

  10. 基于SphereFace深度学习的人脸考勤系统(Caffe+windows+OpenCV)

    界面展示 这是主界面.打开摄像头,能进行人脸捕捉并显示在屏幕上,自动连接数据库,显示出对应人脸的信息,并进行上下班打卡. 相关开发工具 数据库:Microsoft SQL Server Managem ...

最新文章

  1. vb 搜索指定目录下的指定类型文件
  2. char和vchar
  3. 【沟通交流】弱关系向强关系的转变
  4. linux ftp 工作过程,linux中ftp的安装过程记录[运维篇]
  5. html一段文字弹窗提示代码,css3提示文字弹窗代码
  6. 洛谷——P1024 [NOIP2001 提高组] 一元三次方程求解
  7. python自动处理多个txt文件_怎么用python去实现几个文件中内容的并行处理
  8. andriod连接mysql测试工具,Android数据库调试工具
  9. vscode有趣插件
  10. 各代iphone尺寸_iPhone所有机型对比尺寸
  11. ACCESS使用技巧三则
  12. 怎么把服务器上的文件备份到nas,如何将文件备份到NAS
  13. auto.js B0013 查找父控件子控件进入阅读文章视频学习每日答题2021-10-03
  14. 普通2d视频转3d视频
  15. MATLAB实现在不同Es/N0情况下,QPSK、16QAM、64QAM误码率结果仿真图(包含软硬判决)
  16. 关于el-dialog弹出层右上角叉号绑定取消按钮功能
  17. Android音视频开发详解
  18. Drop Shipment PO以及Replenishment PO有何异同?
  19. OverTheWire——Bandit
  20. 如何将英文文献转中文?

热门文章

  1. boost::geometry::num_interior_rings用法的测试程序
  2. boost::fusion::fused用法的测试程序
  3. 遍历boost::fibers::unbuffered_channel< unsigned int >的测试程序
  4. Boost:BOOST_VERIFY_MSG扩展的用法测试程序
  5. Boost:双图和boost assign的测试程序
  6. ITK:多路输出相同类型的
  7. VTK:相互作用之CallBack
  8. OpenCV HDF读写属性
  9. OpenGL 深度测试depth test 的实例
  10. C语言实现线索二叉树Threaded Binary Tree (附完整源码)