所有的操作是基于caffe的根目录/caffe-master/来操作的:

在caffe框架中用训练好的模型分类单张图片需要用到classification.bin,本博客主要提供其源码文件classification.cpp的注释。

1、caffe提供了一个用已经训练好的caffemodel来分类单张图片的库(./build/examples/cpp_classification/classification.bin),该库的源码为文件./examples/cpp-classification/classification.cpp。

2、利用该库的分类单张图片的具体方法::

./build/examples/cpp_classification/classification.bin \
网络结构文件:xx/xx/deploy.prototxt                      \
训练的模型文件:xx/xx/xx.caffemodel                      \
训练的图像的均值文件:xx/xx/xx.binaryproto                \
类别名称标签文件:xx/xx/synset_words.txt                 \
待测试图像:xx/xx/xx.jpg                                
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

具体可见这位大牛的博客:http://www.cnblogs.com/denny402/p/5111018.html

下面记录下我在看classification.cpp代码时一些注释,如有错误望指教:::

#include <caffe/caffe.hpp>
#ifdef USE_OPENCV
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#endif  // USE_OPENCV
#include <algorithm>
#include <iosfwd>
#include <memory>
#include <string>
#include <utility>
#include <vector>#ifdef USE_OPENCV
using namespace caffe;  // NOLINT(build/namespaces)
using std::string;/* Pair (label, confidence) representing a prediction. */
typedef std::pair<string, float> Prediction;class Classifier {public:Classifier(const string& model_file,const string& trained_file,const string& mean_file,const string& label_file);std::vector<Prediction> Classify(const cv::Mat& img, int N = 5);private:void SetMean(const string& mean_file);std::vector<float> Predict(const cv::Mat& img);void WrapInputLayer(std::vector<cv::Mat>* input_channels);void Preprocess(const cv::Mat& img,std::vector<cv::Mat>* input_channels);private:shared_ptr<Net<float> > net_;cv::Size input_geometry_;int num_channels_;cv::Mat mean_;std::vector<string> labels_;
};/*分类对象构造文件*/
Classifier::Classifier(const string& model_file,const string& trained_file,const string& mean_file,const string& label_file) {
#ifdef CPU_ONLYCaffe::set_mode(Caffe::CPU);
#elseCaffe::set_mode(Caffe::GPU);
#endif/* Load the network. */net_.reset(new Net<float>(model_file, TEST)); /*复制网络结构*/net_->CopyTrainedLayersFrom(trained_file);   /*加载caffemodel,该函数在net.cpp中实现*/CHECK_EQ(net_->num_inputs(), 1) << "Network should have exactly one input.";CHECK_EQ(net_->num_outputs(), 1) << "Network should have exactly one output.";Blob<float>* input_layer = net_->input_blobs()[0];num_channels_ = input_layer->channels();    /*该网络结构所要求的图片输入通道数*/CHECK(num_channels_ == 3 || num_channels_ == 1)<< "Input layer should have 1 or 3 channels.";input_geometry_ = cv::Size(input_layer->width(), input_layer->height());  /*输入层需要的图片宽高*//* Load the binaryproto mean file. */SetMean(mean_file);   /*加载均值文件*//* Load labels. */std::ifstream labels(label_file.c_str());  /*加载标签名称文件*/CHECK(labels) << "Unable to open labels file " << label_file;string line;while (std::getline(labels, line))labels_.push_back(string(line));Blob<float>* output_layer = net_->output_blobs()[0];   /*检查标签个数与网络的输出结点个数是否一样*/CHECK_EQ(labels_.size(), output_layer->channels())<< "Number of labels is different from the output layer dimension.";
}static bool PairCompare(const std::pair<float, int>& lhs,const std::pair<float, int>& rhs) {return lhs.first > rhs.first;
}/* Return the indices of the top N values of vector v. */
static std::vector<int> Argmax(const std::vector<float>& v, int N) {std::vector<std::pair<float, int> > pairs;for (size_t i = 0; i < v.size(); ++i)pairs.push_back(std::make_pair(v[i], i));std::partial_sort(pairs.begin(), pairs.begin() + N, pairs.end(), PairCompare);std::vector<int> result;for (int i = 0; i < N; ++i)result.push_back(pairs[i].second);return result;
}/* Return the top N predictions. */
std::vector<Prediction> Classifier::Classify(const cv::Mat& img, int N) {std::vector<float> output = Predict(img);  /*调用这个函数做分类*/N = std::min<int>(labels_.size(), N);std::vector<int> maxN = Argmax(output, N);std::vector<Prediction> predictions;for (int i = 0; i < N; ++i) {int idx = maxN[i];predictions.push_back(std::make_pair(labels_[idx], output[idx]));}return predictions;
}/* Load the mean file in binaryproto format. */
void Classifier::SetMean(const string& mean_file) {BlobProto blob_proto;ReadProtoFromBinaryFileOrDie(mean_file.c_str(), &blob_proto);  /*读入均值文件在Io.cpp中实现*//* Convert from BlobProto to Blob<float> */Blob<float> mean_blob;mean_blob.FromProto(blob_proto);  /*将读入的均值文件转成Blob对象*//*Blob类在Blob.hpp中定义*/CHECK_EQ(mean_blob.channels(), num_channels_)<< "Number of channels of mean file doesn't match input layer.";/* The format of the mean file is planar 32-bit float BGR or grayscale. */std::vector<cv::Mat> channels;float* data = mean_blob.mutable_cpu_data();for (int i = 0; i < num_channels_; ++i) {/* Extract an individual channel. */cv::Mat channel(mean_blob.height(), mean_blob.width(), CV_32FC1, data);channels.push_back(channel);data += mean_blob.height() * mean_blob.width();}  /*将均值图像的每个通道图像拷贝到channel中*//* Merge the separate channels into a single image. */cv::Mat mean;cv::merge(channels, mean);  /*合并每个通道图像*//* Compute the global mean pixel value and create a mean image* filled with this value. */cv::Scalar channel_mean = cv::mean(mean);mean_ = cv::Mat(input_geometry_, mean.type(), channel_mean);
}/*测试函数*/
std::vector<float> Classifier::Predict(const cv::Mat& img) {Blob<float>* input_layer = net_->input_blobs()[0];input_layer->Reshape(1, num_channels_,input_geometry_.height, input_geometry_.width);/*没太看懂,应该是一些缩放*//* Forward dimension change to all layers. */net_->Reshape();std::vector<cv::Mat> input_channels;WrapInputLayer(&input_channels);/*对输入层数据进行包装*/Preprocess(img, &input_channels);  /*把传入的测试图像写入到输入层*/net_->Forward();    /*网络前向传播:计算出该测试图像属于哪个每个类别的概率也就是最终的输出层*//* Copy the output layer to a std::vector */Blob<float>* output_layer = net_->output_blobs()[0];   /*将输出层拷贝到向量*/const float* begin = output_layer->cpu_data();const float* end = begin + output_layer->channels();return std::vector<float>(begin, end);
}/* Wrap the input layer of the network in separate cv::Mat objects* (one per channel). This way we save one memcpy operation and we* don't need to rely on cudaMemcpy2D. The last preprocessing* operation will write the separate channels directly to the input* layer. */
void Classifier::WrapInputLayer(std::vector<cv::Mat>* input_channels) {Blob<float>* input_layer = net_->input_blobs()[0];int width = input_layer->width();int height = input_layer->height();float* input_data = input_layer->mutable_cpu_data();for (int i = 0; i < input_layer->channels(); ++i) {cv::Mat channel(height, width, CV_32FC1, input_data);input_channels->push_back(channel);input_data += width * height;}
}void Classifier::Preprocess(const cv::Mat& img,std::vector<cv::Mat>* input_channels) {/* Convert the input image to the input image format of the network. */cv::Mat sample;if (img.channels() == 3 && num_channels_ == 1)cv::cvtColor(img, sample, cv::COLOR_BGR2GRAY);else if (img.channels() == 4 && num_channels_ == 1)cv::cvtColor(img, sample, cv::COLOR_BGRA2GRAY);else if (img.channels() == 4 && num_channels_ == 3)cv::cvtColor(img, sample, cv::COLOR_BGRA2BGR);else if (img.channels() == 1 && num_channels_ == 3)cv::cvtColor(img, sample, cv::COLOR_GRAY2BGR);elsesample = img;/*将输入的图像转换成输入层需要的图像格式*/cv::Mat sample_resized;if (sample.size() != input_geometry_)cv::resize(sample, sample_resized, input_geometry_);    /*如果大小不一致则需要缩放*/elsesample_resized = sample;cv::Mat sample_float;if (num_channels_ == 3)sample_resized.convertTo(sample_float, CV_32FC3);       /*将数据转化成浮点型*/elsesample_resized.convertTo(sample_float, CV_32FC1);cv::Mat sample_normalized;cv::subtract(sample_float, mean_, sample_normalized);     /*应该是当前图像减去均值图像*//* This operation will write the separate BGR planes directly to the* input layer of the network because it is wrapped by the cv::Mat* objects in input_channels. */cv::split(sample_normalized, *input_channels);   /*把测试的图像通过之前的定义的wraper写入到输入层*/CHECK(reinterpret_cast<float*>(input_channels->at(0).data)== net_->input_blobs()[0]->cpu_data())<< "Input channels are not wrapping the input layer of the network.";
}int main(int argc, char** argv) {if (argc != 6) {std::cerr << "Usage: " << argv[0]<< " deploy.prototxt network.caffemodel"<< " mean.binaryproto labels.txt img.jpg" << std::endl;return 1;}::google::InitGoogleLogging(argv[0]);string model_file   = argv[1];   /*标识网络结构的deploy.prototxt文件*/string trained_file = argv[2];   /*训练出来的模型文件caffemodel*/string mean_file    = argv[3];   /*均值.binaryproto文件*/string label_file   = argv[4];   /*标签文件:标识类别的名称*/Classifier classifier(model_file, trained_file, mean_file, label_file);  /*创建对象并初始化网络、模型、均值、标签各类对象*/string file = argv[5];   /*传入的待测试图片*/std::cout << "---------- Prediction for "<< file << " ----------" << std::endl;cv::Mat img = cv::imread(file, -1);CHECK(!img.empty()) << "Unable to decode image " << file;std::vector<Prediction> predictions = classifier.Classify(img);   /*具体测试传入的图片并返回测试的结果:类别ID与概率值的Prediction类型数组*//* Print the top N predictions. *//*将测试的结果打印*/for (size_t i = 0; i < predictions.size(); ++i) {Prediction p = predictions[i];std::cout << std::fixed << std::setprecision(4) << p.second << " - \""<< p.first << "\"" << std::endl;}
}
#else
int main(int argc, char** argv) {LOG(FATAL) << "This example requires OpenCV; compile with USE_OPENCV.";
}
#endif  // USE_OPENCV
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269

感谢:::::http://blog.csdn.net/csyanbin/article/details/50877359

caffe测试单张图片相关推荐

  1. GPU测试单张图片时间过长

    为什么在测试GPU和CPU的速度的时候会出现GPU反而比CPU慢的 我之前为了测试resnext101网络在CPU和GPU上的单张图片测试程序 很显然不对啊,后来我发现,GPU在刚启动测试第一张图片, ...

  2. caffe ssd 测试demo,检测单张图片

    原 SSD: Single Shot MultiBox Detector 检测单张图片 2016年10月29日 16:39:05 阅读数:19930 标签: python ssd ssd-detect ...

  3. keras笔记(3)-猫狗数据集上的训练以及单张图片多张图片的测试

    之前也写过关于使用tensorflow在猫狗数据集上的训练,想要学习的可以看一下 数据集下载 猫狗数据集:https://pan.baidu.com/s/13hw4LK8ihR6-6-8mpjLKDA ...

  4. 猫狗训练单张图片的测试

    猫狗训练的训练模型的建立,模型在整个预测集上的预测效果的测试的程序代码网上或一些书籍上都可查阅,但是对单张或某些图片的分类测试程序不多,这里通过参考博客:https://blog.csdn.net/b ...

  5. 仅输入单张图片,就能“看”出物体材质!这篇图形学论文已被SIGGRAPH 2021收录...

     OPPO 日前,计算机图形学顶级国际学术会议ACM SIGGRAPH 2021收录了Highlight-aware Two-stream Network for Single-image SVBRD ...

  6. SIGGRAPH 2021丨OPPO与南大提出双流网络:仅输入单张图片,就能“看”出物体材质...

     OPPO 为了解决双向反射分布函数 (SVBRDF)提取过程中所遇到的纹理.高光.阴影问题,南京大学计算机软件新技术国家重点实验室的过洁博士等多位专家学者和OPPO软工多媒体与智慧开发部高级算法工程 ...

  7. caffe与cv2图片格式的相互转换

    目录: caffe与cv2图片格式转换 str_to_cv2图片格式转换 caffe与cv2图片格式的转换 python中两种方式直接获得的图像是不一样的,主要表现在颜色通道,数据类型上,如下表.因此 ...

  8. yolov3 使用darknet的python接口处理单张图片和视频和摄像头视频流

    目标 使用yoloV3 darknet 自带的 python 接口(即darknet.py 文件)处理图片和视频. 具体的说有三种场景: 1 指定一张图片的位置,进行model预测+画框+另存为新图片 ...

  9. CaNet-master装载图片数据和mask(index对应单张图片序号)

    使用三个txt(15cls)训练,另外1个txt(5cls)用于val. 训练需要support set原图+mask,query set原图,使用query集计算loss更新参数. support ...

  10. Pytorch 扩展单张图片维度

    Pytorch 扩展单张图片维度@Elaine 训练数据一般都是(b,c,h,w),在测试时只输入一张图片,所以需要扩展维度,下面是扩展维度方法 import cv2 import torchimag ...

最新文章

  1. DeprecationWarning: the md5 module is deprecated; use hashlib instead import md5
  2. SQL Server 自动增长清零
  3. tensorflow 线性回归 iris
  4. 互联网分布式微服务云平台规划分析--服务监控中心
  5. Java的基础数据类型
  6. VTK:可视化算法之TensorAxes
  7. 34丨关于Linux网络,你必须知道这些(下)
  8. java的spinner_java中的spinner | 学步园
  9. SAP Cloud for Customer 标准培训课程
  10. LeetCode 1891. 割绳子(二分查找)
  11. 聊聊如何才能进大厂实习~
  12. httpf发送 json_Java发送http请求发送json对象
  13. ibatis insert mysql_iBATIS创建操作
  14. hive 如何将数组转成字符串_Hive 字符串操作[转]
  15. 软件测试中单元测试的内容有哪些?-alltesting云测试
  16. Lua 斗地主算法实现
  17. 岩板铺地好吗_铺地的石板如何用处高逼格,三个大师案例来教你!
  18. vue中使用video插件在微信浏览器中视频无法自动播放的问题
  19. python 画彩虹_python – 在matplotlib中,我如何绘制多色线,如彩虹
  20. IKBC键盘win键失效

热门文章

  1. 基于DEV控件库的webservice打印.repx模板
  2. mysql中计算日期整数差
  3. iOS UINavigationBar-导航栏、UINavigationItem-导航项
  4. SQL Server 数据类型
  5. 《肖申克的救赎》--[美]斯蒂芬·金
  6. 并行开发 5.同步机制(下)
  7. 【操作基本数据类型的流】
  8. Python Day 19 面向对象(初识面向对象)
  9. 51nod 1285山峰和分段
  10. Ubuntu搜索不到WiFi的解决办法