caffe.proto中TransformationParameter部分

  1. // Message that stores parameters used to apply transformation
  2. // to the data layer's data
  3. message TransformationParameter {
  4. // For data pre-processing, we can do simple scaling and subtracting the
  5. // data mean, if provided. Note that the mean subtraction is always carried
  6. // out before scaling.
  7. //像素幅度缩放参数,默认不缩放
  8. optional float scale = [default = ];
  9. // Specify if we want to randomly mirror data.
  10. //图像随机镜像开关。默认false,不进行随机镜像操作
  11. optional bool mirror = [default = false];
  12. // Specify if we would like to randomly crop an image.
  13. //图像随机切块的大小。默认不切块。
  14. optional uint32 crop_size = [default = ];
  15. // mean_file and mean_value cannot be specified at the same time
  16. //存储图像均值的文件
  17. optional string mean_file = ;
  18. // if specified can be repeated once (would subtract it from all the channels)
  19. // or can be repeated the same number of times as channels
  20. // (would subtract them from the corresponding channel)
  21. //均值数值。无需读取文件。
  22. //如果均值数目和通道数一致,则每个通道分别减去对应均值;
  23. //如果没有均值只有一个,则每个通道减去相同的均值。
  24. repeated float mean_value = ;
  25. // Force the decoded image to have 3 color channels.
  26. //强制为三通道三色图像输入 默认false
  27. optional bool force_color = [default = false];
  28. // Force the decoded image to have 1 color channels.
  29. //强制为单通道灰度图像输入 默认false
  30. optional bool force_gray = [default = false];
  31. }

caffe.proto中Datum部分

  1. //Datum用来从LMDB/LEVELDB 中读取数据,或将数据写入其中。和BlobProto有相似功能,只是
  2. //BlobProto用于模型权值序列化反序列化,而Datum用于数据或特征图(feature map)提供序列化反序列化
  3. message Datum {
  4. //数据维度信息:channels*height*width
  5. optional int32 channels = ;
  6. optional int32 height = ;
  7. optional int32 width = ;
  8. // the actual image data, in bytes
  9. //图像数据,以字节类型存储
  10. optional bytes data = ;
  11. //标签数据,统一用int32类型存储
  12. optional int32 label = ;
  13. // Optionally, the datum could also hold float data.
  14. repeated float float_data = ;
  15. // If true data contains an encoded image that need to be decoded
  16. optional bool encoded = [default = false];//是否为编码数据,默认false
  17. }

include/caffe/data_transformer.hpp

  1. #ifndef CAFFE_DATA_TRANSFORMER_HPP
  2. #define CAFFE_DATA_TRANSFORMER_HPP
  3.  
  4. #include <vector>
  5.  
  6. #include "caffe/blob.hpp"
  7. #include "caffe/common.hpp"
  8. #include "caffe/proto/caffe.pb.h"
  9.  
  10. namespace caffe {
  11.  
  12. /**
  13. * @brief Applies common transformations to the input data, such as
  14. * scaling, mirroring, substracting the image mean...
  15. */
  16. template <typename Dtype>
  17. class DataTransformer {
  18. public:
  19. explicit DataTransformer(const TransformationParameter& param, Phase phase);
  20. virtual ~DataTransformer() {}
  21.  
  22. /**
  23. * @brief Initialize the Random number generations if needed by the
  24. * transformation.
  25. */
  26. //初始化随机数种子函数
  27. void InitRand();
  28.  
  29. /**
  30. * @brief Applies the transformation defined in the data layer's
  31. * transform_param block to the data.
  32. *
  33. * @param datum
  34. * Datum containing the data to be transformed.
  35. * @param transformed_blob
  36. * This is destination blob. It can be part of top blob's data if
  37. * set_cpu_data() is used. See data_layer.cpp for an example.
  38. */
  39. //数据读取层中transform_param块所声明的变换应用到输入数据中。
  40. //以下为多个重载函数
  41. void Transform(const Datum& datum, Blob<Dtype>* transformed_blob);
  42.  
  43. /**
  44. * @brief Applies the transformation defined in the data layer's
  45. * transform_param block to a vector of Datum.
  46. *
  47. * @param datum_vector
  48. * A vector of Datum containing the data to be transformed.
  49. * @param transformed_blob
  50. * This is destination blob. It can be part of top blob's data if
  51. * set_cpu_data() is used. See memory_layer.cpp for an example.
  52. */
  53. void Transform(const vector<Datum> & datum_vector,
  54. Blob<Dtype>* transformed_blob);
  55. //使用OPENCV
  56. #ifdef USE_OPENCV
  57. /**
  58. * @brief Applies the transformation defined in the data layer's
  59. * transform_param block to a vector of Mat.
  60. *
  61. * @param mat_vector
  62. * A vector of Mat containing the data to be transformed.
  63. * @param transformed_blob
  64. * This is destination blob. It can be part of top blob's data if
  65. * set_cpu_data() is used. See memory_layer.cpp for an example.
  66. */
  67. void Transform(const vector<cv::Mat> & mat_vector,
  68. Blob<Dtype>* transformed_blob);
  69.  
  70. /**
  71. * @brief Applies the transformation defined in the data layer's
  72. * transform_param block to a cv::Mat
  73. *
  74. * @param cv_img
  75. * cv::Mat containing the data to be transformed.
  76. * @param transformed_blob
  77. * This is destination blob. It can be part of top blob's data if
  78. * set_cpu_data() is used. See image_data_layer.cpp for an example.
  79. */
  80. void Transform(const cv::Mat& cv_img, Blob<Dtype>* transformed_blob);
  81. #endif // USE_OPENCV
  82.  
  83. /**
  84. * @brief Applies the same transformation defined in the data layer's
  85. * transform_param block to all the num images in a input_blob.
  86. *
  87. * @param input_blob
  88. * A Blob containing the data to be transformed. It applies the same
  89. * transformation to all the num images in the blob.
  90. * @param transformed_blob
  91. * This is destination blob, it will contain as many images as the
  92. * input blob. It can be part of top blob's data.
  93. */
  94. void Transform(Blob<Dtype>* input_blob, Blob<Dtype>* transformed_blob);
  95.  
  96. /**
  97. * @brief Infers the shape of transformed_blob will have when
  98. * the transformation is applied to the data.
  99. *
  100. * @param datum
  101. * Datum containing the data to be transformed.
  102. */
  103. //获取执行变换后输出Blob的形状
  104. vector<int> InferBlobShape(const Datum& datum);
  105. /**
  106. * @brief Infers the shape of transformed_blob will have when
  107. * the transformation is applied to the data.
  108. * It uses the first element to infer the shape of the blob.
  109. *
  110. * @param datum_vector
  111. * A vector of Datum containing the data to be transformed.
  112. */
  113. vector<int> InferBlobShape(const vector<Datum> & datum_vector);
  114. /**
  115. * @brief Infers the shape of transformed_blob will have when
  116. * the transformation is applied to the data.
  117. * It uses the first element to infer the shape of the blob.
  118. *
  119. * @param mat_vector
  120. * A vector of Mat containing the data to be transformed.
  121. */
  122. #ifdef USE_OPENCV
  123. vector<int> InferBlobShape(const vector<cv::Mat> & mat_vector);
  124. /**
  125. * @brief Infers the shape of transformed_blob will have when
  126. * the transformation is applied to the data.
  127. *
  128. * @param cv_img
  129. * cv::Mat containing the data to be transformed.
  130. */
  131. vector<int> InferBlobShape(const cv::Mat& cv_img);
  132. #endif // USE_OPENCV
  133.  
  134. protected:
  135. /**
  136. * @brief Generates a random integer from Uniform({0, 1, ..., n-1}).
  137. *
  138. * @param n
  139. * The upperbound (exclusive) value of the random number.
  140. * @return
  141. * A uniformly random integer value from ({0, 1, ..., n-1}).
  142. */
  143. //产生取值0到n-1的随机整数,服从均匀分布
  144. virtual int Rand(int n);
  145.  
  146. void Transform(const Datum& datum, Dtype* transformed_data);
  147. // Tranformation parameters
  148. //变换参数,该数据结构由ProtoBuffer工具自动生成
  149. TransformationParameter param_;
  150.  
  151. //随机数生成器。声明在include/caffe/common.hpp中
  152. shared_ptr<Caffe::RNG> rng_;
  153. Phase phase_;//当前运行阶段。TRAIN或TEST。阶段不同,变换会有差异
  154. Blob<Dtype> data_mean_;//均值图像,从均值文件中读取
  155. vector<Dtype> mean_values_;//均值数值,从param_中提取
  156. };
  157.  
  158. } // namespace caffe
  159.  
  160. #endif // CAFFE_DATA_TRANSFORMER_HPP_

src/caffe/data_transformer.cpp

  1. #ifdef USE_OPENCV
  2. #include <opencv2/core/core.hpp>
  3. #endif // USE_OPENCV
  4.  
  5. #include <string>
  6. #include <vector>
  7.  
  8. #include "caffe/data_transformer.hpp"
  9. #include "caffe/util/io.hpp"
  10. #include "caffe/util/math_functions.hpp"
  11. #include "caffe/util/rng.hpp"
  12.  
  13. namespace caffe {
  14.  
  15. template<typename Dtype>
  16. DataTransformer<Dtype>::DataTransformer(const TransformationParameter& param,
  17. Phase phase)
  18. : param_(param), phase_(phase) {//初始化
  19. // check if we want to use mean_file
  20. //查看是否使用均值文件
  21. if (param_.has_mean_file()) {
  22. //如果param_中指定了均值文件又指定了均值数值则报错,二选一
  23. CHECK_EQ(param_.mean_value_size(), ) <<
  24. "Cannot specify mean_file and mean_value at the same time";
  25. const string& mean_file = param.mean_file();//获取均值文件名
  26. if (Caffe::root_solver()) {
  27. LOG(INFO) << "Loading mean file from: " << mean_file;
  28. }
  29. BlobProto blob_proto;//从均值文件中读取数据到blob_proto对象中
  30. ReadProtoFromBinaryFileOrDie(mean_file.c_str(), &blob_proto);
  31. data_mean_.FromProto(blob_proto);//从blob_proto将均值反序列化到data_mean_内存中
  32. }
  33. // check if we want to use mean_value
  34. //查看是否使用均值数值
  35. if (param_.mean_value_size() > ) {
  36. CHECK(param_.has_mean_file() == false) <<
  37. "Cannot specify mean_file and mean_value at the same time";
  38. for (int c = ; c < param_.mean_value_size(); ++c) {
  39. //读取均值数值,不再读取均值文件
  40. mean_values_.push_back(param_.mean_value(c));
  41. }
  42. }
  43. }
  44. //若干重载变换函数
  45. //该函数以Datum作为输入,结构体在caffe.proto中可见。输出为数据指针
  46. template<typename Dtype>
  47. void DataTransformer<Dtype>::Transform(const Datum& datum,
  48. Dtype* transformed_data) {
  49. //获得datum数据字串、维度信息
  50. const string& data = datum.data();
  51. const int datum_channels = datum.channels();
  52. const int datum_height = datum.height();
  53. const int datum_width = datum.width();
  54.  
  55. //从param_获得处理参数。如切块大小、幅度缩放、随机镜像、图像均值等
  56. const int crop_size = param_.crop_size();
  57. const Dtype scale = param_.scale();
  58. const bool do_mirror = param_.mirror() && Rand();
  59. const bool has_mean_file = param_.has_mean_file();
  60. const bool has_uint8 = data.size() > ;
  61. const bool has_mean_values = mean_values_.size() > ;
  62.  
  63. CHECK_GT(datum_channels, );//保证输入通道数大于零
  64. CHECK_GE(datum_height, crop_size);//保证输入数据的宽和高大于切块尺寸
  65. CHECK_GE(datum_width, crop_size);
  66.  
  67. //获得图像均值
  68. Dtype* mean = NULL;
  69. if (has_mean_file) {//若指定了图像均值文件
  70. //保证图像的均值文件的维度和输入图像数据的维度完全相同
  71. CHECK_EQ(datum_channels, data_mean_.channels());
  72. CHECK_EQ(datum_height, data_mean_.height());
  73. CHECK_EQ(datum_width, data_mean_.width());
  74. mean = data_mean_.mutable_cpu_data();//获得图像均值数据控制权
  75. }
  76. if (has_mean_values) {//未指定图像均值文件,直接给出均值数值
  77. //保证均值数据维数是1,或与输入图像数据的通道数相同
  78. CHECK(mean_values_.size() == || mean_values_.size() == datum_channels) <<
  79. "Specify either 1 mean_value or as many as channels: " << datum_channels;
  80. if (datum_channels > && mean_values_.size() == ) {
  81. // Replicate the mean_value for simplicity
  82. //如果均值数据维度为1,且输入数据通道数大于1,则重复channels次
  83. for (int c = ; c < datum_channels; ++c) {
  84. mean_values_.push_back(mean_values_[]);
  85. }
  86. }
  87. }
  88.  
  89. //输入图像的宽和高
  90. int height = datum_height;
  91. int width = datum_width;
  92.  
  93. //开始图像切块
  94. int h_off = ;
  95. int w_off = ;
  96. if (crop_size) {//若不为0则进行切块,为0不切块
  97. height = crop_size;
  98. width = crop_size;
  99. // We only do random crop when we do training.
  100. // 在训练的时候随机crop图像块,这里需要自己实现Rand这个函数来确定是如何随机的
  101. if (phase_ == TRAIN) {
  102. h_off = Rand(datum_height - crop_size + );// 产生从0到datum_height - crop_size的随机数
  103. w_off = Rand(datum_width - crop_size + );//切块的width偏移量
  104. } else {//测试阶段只切取图像中心位置
  105. h_off = (datum_height - crop_size) / ;
  106. w_off = (datum_width - crop_size) / ;
  107. }
  108. }
  109.  
  110. // 对数据进行变换,主要是将原来的像素值减去均值,然后乘以scale这么一个操作
  111. // 如果需要crop则最终转换的Blob的大小即为crop*crop
  112. // 如果不是,则最终的Blob大小即为datum_height*datum_width
  113. Dtype datum_element;//存放输入图像的像素值
  114. int top_index, data_index;//分别存放输出index和输入index
  115. for (int c = ; c < datum_channels; ++c) {
  116. for (int h = ; h < height; ++h) {
  117. for (int w = ; w < width; ++w) {
  118. data_index = (c * datum_height + h_off + h) * datum_width + w_off + w;
  119. if (do_mirror) {//若需要镜像操作,则输出index时设置width反向
  120. top_index = (c * height + h) * width + (width - - w);
  121. } else {
  122. top_index = (c * height + h) * width + w;
  123. }
  124. if (has_uint8) {// Datum中如果是uint8存储图像数据则转换为float
  125. datum_element =
  126. static_cast<Dtype>(static_cast<uint8_t>(data[data_index]));
  127. } else {//否则为float
  128. datum_element = datum.float_data(data_index);
  129. }
  130. if (has_mean_file) {//若指定了均值文件
  131. transformed_data[top_index] =
  132. (datum_element - mean[data_index]) * scale;//去均值,幅度缩放
  133. } else {
  134. if (has_mean_values) {//若指定了均值数值
  135. transformed_data[top_index] =
  136. (datum_element - mean_values_[c]) * scale;//去均值,幅度缩放
  137. } else {
  138. transformed_data[top_index] = datum_element * scale;//不去均值,只幅度缩放
  139. }
  140. }
  141. }
  142. }
  143. }
  144. }
  145.  
  146. //与上一个函数类似,只是输出变成blob
  147. template<typename Dtype>
  148. void DataTransformer<Dtype>::Transform(const Datum& datum,
  149. Blob<Dtype>* transformed_blob) {
  150. // If datum is encoded, decode and transform the cv::image.
  151. if (datum.encoded()) {// 检查datum是否经过编码的图像,如果是则解码
  152. #ifdef USE_OPENCV
  153. // 先检查是不是两个属性都设置, 如果是则说明参数设置有误
  154. CHECK(!(param_.force_color() && param_.force_gray()))
  155. << "cannot set both force_color and force_gray";
  156. cv::Mat cv_img;
  157. if (param_.force_color() || param_.force_gray()) {
  158. // If force_color then decode in color otherwise decode in gray.
  159. // 如果强制彩色或者强制灰度图像一个成立则使用DecodeDatumToCVMat解码
  160. cv_img = DecodeDatumToCVMat(datum, param_.force_color());
  161. } else {// 否则使用DecodeDatumToCVMatNative解码
  162. cv_img = DecodeDatumToCVMatNative(datum);
  163. }
  164. // Transform the cv::image into blob.将cv::image 变换为 blob
  165. return Transform(cv_img, transformed_blob);
  166. #else
  167. LOG(FATAL) << "Encoded datum requires OpenCV; compile with USE_OPENCV.";
  168. #endif // USE_OPENCV
  169. } else {// 如果没有编码则检查force_color和force_gray是否设置,如果设置则不合法,因为该选项只适合于编码后的数据
  170. if (param_.force_color() || param_.force_gray()) {
  171. LOG(ERROR) << "force_color and force_gray only for encoded datum";
  172. }
  173. }
  174.  
  175. const int crop_size = param_.crop_size();
  176. const int datum_channels = datum.channels();
  177. const int datum_height = datum.height();
  178. const int datum_width = datum.width();
  179.  
  180. // Check dimensions.检查维度
  181. const int channels = transformed_blob->channels();
  182. const int height = transformed_blob->height();
  183. const int width = transformed_blob->width();
  184. const int num = transformed_blob->num();
  185.  
  186. CHECK_EQ(channels, datum_channels);
  187. CHECK_LE(height, datum_height);
  188. CHECK_LE(width, datum_width);
  189. CHECK_GE(num, );
  190.  
  191. if (crop_size) {
  192. CHECK_EQ(crop_size, height);
  193. CHECK_EQ(crop_size, width);
  194. } else {
  195. CHECK_EQ(datum_height, height);
  196. CHECK_EQ(datum_width, width);
  197. }
  198. // 参数变换完毕,调用现有函数
  199. Dtype* transformed_data = transformed_blob->mutable_cpu_data();
  200. Transform(datum, transformed_data);
  201. }
  202.  
  203. //对一组datum数据进行变换
  204. template<typename Dtype>
  205. void DataTransformer<Dtype>::Transform(const vector<Datum> & datum_vector,
  206. Blob<Dtype>* transformed_blob) {
  207. const int datum_num = datum_vector.size();
  208. const int num = transformed_blob->num();// 变换到的目标blob的形状
  209. const int channels = transformed_blob->channels();
  210. const int height = transformed_blob->height();
  211. const int width = transformed_blob->width();
  212.  
  213. CHECK_GT(datum_num, ) << "There is no datum to add";
  214. CHECK_LE(datum_num, num) <<
  215. "The size of datum_vector must be no greater than transformed_blob->num()";
  216. Blob<Dtype> uni_blob(, channels, height, width);// 新建一个uni_blob,里面只有一个batch。临时Blob
  217. //依次对每一个datum进行变换,放入对应的Blob之中
  218. for (int item_id = ; item_id < datum_num; ++item_id) {
  219. int offset = transformed_blob->offset(item_id);
  220. uni_blob.set_cpu_data(transformed_blob->mutable_cpu_data() + offset);
  221. Transform(datum_vector[item_id], &uni_blob);
  222. }
  223. }
  224.  
  225. #ifdef USE_OPENCV
  226. //对一组cv::Mat对象进行变换,放入Blob中
  227. template<typename Dtype>
  228. void DataTransformer<Dtype>::Transform(const vector<cv::Mat> & mat_vector,
  229. Blob<Dtype>* transformed_blob) {
  230. // 获取mat的参数
  231. const int mat_num = mat_vector.size();
  232. const int num = transformed_blob->num();
  233. const int channels = transformed_blob->channels();
  234. const int height = transformed_blob->height();
  235. const int width = transformed_blob->width();
  236.  
  237. CHECK_GT(mat_num, ) << "There is no MAT to add";
  238. CHECK_EQ(mat_num, num) <<
  239. "The size of mat_vector must be equals to transformed_blob->num()";
  240. Blob<Dtype> uni_blob(, channels, height, width);
  241. for (int item_id = ; item_id < mat_num; ++item_id) {
  242. int offset = transformed_blob->offset(item_id);
  243. uni_blob.set_cpu_data(transformed_blob->mutable_cpu_data() + offset);
  244. Transform(mat_vector[item_id], &uni_blob);
  245. }
  246. }
  247. // 对一个cv::Mat对象进行变换,放入Blob中。
  248. // 如果是图像的话,需要减去均值乘以scale,判断是不是需要做镜像处理
  249. // 逻辑与前面类似
  250. template<typename Dtype>
  251. void DataTransformer<Dtype>::Transform(const cv::Mat& cv_img,
  252. Blob<Dtype>* transformed_blob) {
  253. const int crop_size = param_.crop_size();
  254. const int img_channels = cv_img.channels();
  255. const int img_height = cv_img.rows;
  256. const int img_width = cv_img.cols;
  257.  
  258. // Check dimensions.检查维度
  259. const int channels = transformed_blob->channels();
  260. const int height = transformed_blob->height();
  261. const int width = transformed_blob->width();
  262. const int num = transformed_blob->num();
  263.  
  264. CHECK_EQ(channels, img_channels);
  265. CHECK_LE(height, img_height);
  266. CHECK_LE(width, img_width);
  267. CHECK_GE(num, );
  268.  
  269. CHECK(cv_img.depth() == CV_8U) << "Image data type must be unsigned byte";
  270.  
  271. const Dtype scale = param_.scale();
  272. const bool do_mirror = param_.mirror() && Rand();
  273. const bool has_mean_file = param_.has_mean_file();
  274. const bool has_mean_values = mean_values_.size() > ;
  275.  
  276. CHECK_GT(img_channels, );
  277. CHECK_GE(img_height, crop_size);
  278. CHECK_GE(img_width, crop_size);
  279.  
  280. Dtype* mean = NULL;
  281. if (has_mean_file) {
  282. CHECK_EQ(img_channels, data_mean_.channels());
  283. CHECK_EQ(img_height, data_mean_.height());
  284. CHECK_EQ(img_width, data_mean_.width());
  285. mean = data_mean_.mutable_cpu_data();
  286. }
  287. if (has_mean_values) {
  288. CHECK(mean_values_.size() == || mean_values_.size() == img_channels) <<
  289. "Specify either 1 mean_value or as many as channels: " << img_channels;
  290. if (img_channels > && mean_values_.size() == ) {
  291. // Replicate the mean_value for simplicity 复制均值便于操作
  292. for (int c = ; c < img_channels; ++c) {
  293. mean_values_.push_back(mean_values_[]);
  294. }
  295. }
  296. }
  297.  
  298. int h_off = ;
  299. int w_off = ;
  300. cv::Mat cv_cropped_img = cv_img;
  301. if (crop_size) {
  302. CHECK_EQ(crop_size, height);
  303. CHECK_EQ(crop_size, width);
  304. // We only do random crop when we do training.只有训练阶段才随机切块
  305. if (phase_ == TRAIN) {
  306. h_off = Rand(img_height - crop_size + );
  307. w_off = Rand(img_width - crop_size + );
  308. } else {
  309. h_off = (img_height - crop_size) / ;
  310. w_off = (img_width - crop_size) / ;
  311. }
  312. cv::Rect roi(w_off, h_off, crop_size, crop_size);
  313. cv_cropped_img = cv_img(roi);
  314. } else {
  315. CHECK_EQ(img_height, height);
  316. CHECK_EQ(img_width, width);
  317. }
  318.  
  319. CHECK(cv_cropped_img.data);
  320.  
  321. Dtype* transformed_data = transformed_blob->mutable_cpu_data();
  322. int top_index;
  323. for (int h = ; h < height; ++h) {
  324. const uchar* ptr = cv_cropped_img.ptr<uchar>(h);
  325. int img_index = ;
  326. for (int w = ; w < width; ++w) {
  327. for (int c = ; c < img_channels; ++c) {
  328. if (do_mirror) {
  329. top_index = (c * height + h) * width + (width - - w);
  330. } else {
  331. top_index = (c * height + h) * width + w;
  332. }
  333. // int top_index = (c * height + h) * width + w;
  334. Dtype pixel = static_cast<Dtype>(ptr[img_index++]);
  335. if (has_mean_file) {
  336. int mean_index = (c * img_height + h_off + h) * img_width + w_off + w;
  337. transformed_data[top_index] =
  338. (pixel - mean[mean_index]) * scale;
  339. } else {
  340. if (has_mean_values) {
  341. transformed_data[top_index] =
  342. (pixel - mean_values_[c]) * scale;
  343. } else {
  344. transformed_data[top_index] = pixel * scale;
  345. }
  346. }
  347. }
  348. }
  349. }
  350. }
  351. #endif // USE_OPENCV
  352.  
  353. //输入输出都是Blob
  354. template<typename Dtype>
  355. void DataTransformer<Dtype>::Transform(Blob<Dtype>* input_blob,
  356. Blob<Dtype>* transformed_blob) {
  357. const int crop_size = param_.crop_size();
  358. const int input_num = input_blob->num();
  359. const int input_channels = input_blob->channels();
  360. const int input_height = input_blob->height();
  361. const int input_width = input_blob->width();
  362.  
  363. if (transformed_blob->count() == ) {
  364. // Initialize transformed_blob with the right shape.初始化变换后的Blob形状
  365. if (crop_size) {
  366. transformed_blob->Reshape(input_num, input_channels,
  367. crop_size, crop_size);
  368. } else {
  369. transformed_blob->Reshape(input_num, input_channels,
  370. input_height, input_width);
  371. }
  372. }
  373.  
  374. const int num = transformed_blob->num();
  375. const int channels = transformed_blob->channels();
  376. const int height = transformed_blob->height();
  377. const int width = transformed_blob->width();
  378. const int size = transformed_blob->count();
  379.  
  380. CHECK_LE(input_num, num);
  381. CHECK_EQ(input_channels, channels);
  382. CHECK_GE(input_height, height);
  383. CHECK_GE(input_width, width);
  384.  
  385. const Dtype scale = param_.scale();
  386. const bool do_mirror = param_.mirror() && Rand();
  387. const bool has_mean_file = param_.has_mean_file();
  388. const bool has_mean_values = mean_values_.size() > ;
  389.  
  390. int h_off = ;
  391. int w_off = ;
  392. if (crop_size) {
  393. CHECK_EQ(crop_size, height);
  394. CHECK_EQ(crop_size, width);
  395. // We only do random crop when we do training.只有训练阶段随机切块
  396. if (phase_ == TRAIN) {
  397. h_off = Rand(input_height - crop_size + );
  398. w_off = Rand(input_width - crop_size + );
  399. } else {
  400. h_off = (input_height - crop_size) / ;
  401. w_off = (input_width - crop_size) / ;
  402. }
  403. } else {
  404. CHECK_EQ(input_height, height);
  405. CHECK_EQ(input_width, width);
  406. }
  407.  
  408. Dtype* input_data = input_blob->mutable_cpu_data();
  409. if (has_mean_file) {
  410. CHECK_EQ(input_channels, data_mean_.channels());
  411. CHECK_EQ(input_height, data_mean_.height());
  412. CHECK_EQ(input_width, data_mean_.width());
  413. for (int n = ; n < input_num; ++n) {
  414. int offset = input_blob->offset(n);
  415. /*
  416. template <typename Dtype>
  417. void caffe_sub(const int N, const Dtype* a, const Dtype* b, Dtype* y);
  418. math_function中定义的caffe_sub目的是矩阵相减input_data(以offset开始的矩阵) = input_data(以offset开始的矩阵) - data_mean_
  419. */
  420. caffe_sub(data_mean_.count(), input_data + offset,
  421. data_mean_.cpu_data(), input_data + offset);
  422. }
  423. }
  424.  
  425. if (has_mean_values) {
  426. CHECK(mean_values_.size() == || mean_values_.size() == input_channels) <<
  427. "Specify either 1 mean_value or as many as channels: " << input_channels;
  428. if (mean_values_.size() == ) {
  429. caffe_add_scalar(input_blob->count(), -(mean_values_[]), input_data);
  430. } else {
  431. for (int n = ; n < input_num; ++n) {
  432. for (int c = ; c < input_channels; ++c) {
  433. int offset = input_blob->offset(n, c);
  434. // 给input_data[offset]地址开始的每一个元素加上一个-mean_values_[c]
  435. caffe_add_scalar(input_height * input_width, -(mean_values_[c]),
  436. input_data + offset);
  437. }
  438. }
  439. }
  440. }
  441. // 如果什么均值都没有则直接复制
  442. Dtype* transformed_data = transformed_blob->mutable_cpu_data();
  443.  
  444. for (int n = ; n < input_num; ++n) {
  445. int top_index_n = n * channels;
  446. int data_index_n = n * channels;
  447. for (int c = ; c < channels; ++c) {
  448. int top_index_c = (top_index_n + c) * height;
  449. int data_index_c = (data_index_n + c) * input_height + h_off;
  450. for (int h = ; h < height; ++h) {
  451. int top_index_h = (top_index_c + h) * width;
  452. int data_index_h = (data_index_c + h) * input_width + w_off;
  453. if (do_mirror) {
  454. int top_index_w = top_index_h + width - ;
  455. for (int w = ; w < width; ++w) {
  456. transformed_data[top_index_w-w] = input_data[data_index_h + w];
  457. }
  458. } else {
  459. for (int w = ; w < width; ++w) {
  460. transformed_data[top_index_h + w] = input_data[data_index_h + w];
  461. }
  462. }
  463. }
  464. }
  465. }
  466. if (scale != Dtype()) {
  467. DLOG(INFO) << "Scale: " << scale;
  468. caffe_scal(size, scale, transformed_data);
  469. }
  470. }
  471.  
  472. //获得数据变换输出尺寸
  473. template<typename Dtype>
  474. vector<int> DataTransformer<Dtype>::InferBlobShape(const Datum& datum) {
  475. if (datum.encoded()) {
  476. #ifdef USE_OPENCV
  477. // 如果使用OpenCV则可以用先转换为CVMat,然后推断blob的形状
  478. CHECK(!(param_.force_color() && param_.force_gray()))
  479. << "cannot set both force_color and force_gray";
  480. cv::Mat cv_img;
  481. if (param_.force_color() || param_.force_gray()) {
  482. // If force_color then decode in color otherwise decode in gray.
  483. cv_img = DecodeDatumToCVMat(datum, param_.force_color());
  484. } else {
  485. cv_img = DecodeDatumToCVMatNative(datum);
  486. }
  487. // InferBlobShape using the cv::image.
  488. return InferBlobShape(cv_img);
  489. #else
  490. LOG(FATAL) << "Encoded datum requires OpenCV; compile with USE_OPENCV.";
  491. #endif // USE_OPENCV
  492. }
  493. // 否则直接粗暴地从datum里面获取形状的数据
  494. const int crop_size = param_.crop_size();
  495. const int datum_channels = datum.channels();
  496. const int datum_height = datum.height();
  497. const int datum_width = datum.width();
  498. // Check dimensions.检查维度
  499. CHECK_GT(datum_channels, );
  500. CHECK_GE(datum_height, crop_size);
  501. CHECK_GE(datum_width, crop_size);
  502. // Build BlobShape. 创建BlobShape对象
  503. vector<int> shape();
  504. shape[] = ;
  505. shape[] = datum_channels;
  506. shape[] = (crop_size)? crop_size: datum_height;
  507. shape[] = (crop_size)? crop_size: datum_width;
  508. return shape;
  509. }
  510.  
  511. template<typename Dtype>
  512. vector<int> DataTransformer<Dtype>::InferBlobShape(
  513. const vector<Datum> & datum_vector) {
  514. const int num = datum_vector.size();
  515. CHECK_GT(num, ) << "There is no datum to in the vector";
  516. // Use first datum in the vector to InferBlobShape.使用第一个推断
  517. vector<int> shape = InferBlobShape(datum_vector[]);
  518. // Adjust num to the size of the vector.
  519. shape[] = num;
  520. return shape;
  521. }
  522.  
  523. #ifdef USE_OPENCV
  524. // 如果使用OpenCV
  525. // 使用CVMat中的信息来推断形状
  526. template<typename Dtype>
  527. vector<int> DataTransformer<Dtype>::InferBlobShape(const cv::Mat& cv_img) {
  528. const int crop_size = param_.crop_size();
  529. const int img_channels = cv_img.channels();
  530. const int img_height = cv_img.rows;
  531. const int img_width = cv_img.cols;
  532. // Check dimensions.
  533. CHECK_GT(img_channels, );
  534. CHECK_GE(img_height, crop_size);
  535. CHECK_GE(img_width, crop_size);
  536. // Build BlobShape.
  537. vector<int> shape();
  538. shape[] = ;
  539. shape[] = img_channels;
  540. shape[] = (crop_size)? crop_size: img_height;
  541. shape[] = (crop_size)? crop_size: img_width;
  542. return shape;
  543. }
  544.  
  545. template<typename Dtype>
  546. vector<int> DataTransformer<Dtype>::InferBlobShape(
  547. const vector<cv::Mat> & mat_vector) {
  548. const int num = mat_vector.size();
  549. CHECK_GT(num, ) << "There is no cv_img to in the vector";
  550. // Use first cv_img in the vector to InferBlobShape.
  551. vector<int> shape = InferBlobShape(mat_vector[]);
  552. // Adjust num to the size of the vector.
  553. shape[] = num;
  554. return shape;
  555. }
  556. #endif // USE_OPENCV
  557.  
  558. // 初始化随机数种子
  559. template <typename Dtype>
  560. void DataTransformer<Dtype>::InitRand() {
  561. // 要么需要镜像要么训练阶段和需要crop同时满足的情况下才初始化随机数种子
  562. const bool needs_rand = param_.mirror() ||
  563. (phase_ == TRAIN && param_.crop_size());
  564. if (needs_rand) {
  565. const unsigned int rng_seed = caffe_rng_rand();// 获得随机数种子(通过熵池或者时间生成种子)
  566. rng_.reset(new Caffe::RNG(rng_seed));//初始化随机数种子并实例化随机数生成器
  567. } else {
  568. rng_.reset();//否则随机数生成器设置为空
  569. }
  570. }
  571.  
  572. // 产生从0到n的随机数
  573. template <typename Dtype>
  574. int DataTransformer<Dtype>::Rand(int n) {
  575. CHECK(rng_);
  576. CHECK_GT(n, );
  577. caffe::rng_t* rng =
  578. static_cast<caffe::rng_t*>(rng_->generator());
  579. return ((*rng)() % n);
  580. }
  581.  
  582. INSTANTIATE_CLASS(DataTransformer);
  583. /*
  584. 初始化类的宏定义
  585. #define INSTANTIATE_CLASS(classname) \
  586. char gInstantiationGuard##classname; \
  587. template class classname<float>; \
  588. template class classname<double>
  589. */
  590. } // namespace caffe

摘抄参考赵永科《21天实战caffe》

同时参考http://blog.csdn.net/langb2014/article/details/51050213

【caffe I/O】数据变换器(图像的预处理部分) 代码注释的更多相关文章

  1. 【撸码caffe 五】数据层搭建

    caffe.cpp中的train函数内声明了一个类型为Solver类的智能指针solver: // Train / Finetune a model. int train() { -- shared_ ...

  2. caffe添加python数据层

    caffe添加python数据层(ImageData) 在caffe中添加自定义层时,必须要实现这四个函数,在C++中是(LayerSetUp,Reshape,Forward_cpu,Backward ...

  3. 【caffe Blob】caffe中与Blob相关的代码注释、使用举例

    首先,Blob使用的小例子(通过运行结果即可知道相关功能): #include <vector> #include <caffe/blob.hpp> #include < ...

  4. json转换数据后面参数要带ture,代码

    强大的PHP已经提供了内置函数:json_encode() 和 json_decode().很容易理解,json_encode()就是将PHP数组转换成Json.相反,json_decode()就是将 ...

  5. 使用gfortran将数据写成Grads格式的代码示例

    使用gfortran将数据写成Grads格式的代码示例: !-----'Fortran4Grads.f90' program Fortran4Grads implicit none integer,p ...

  6. c#将Excel数据导入到数据库的实现代码

    这篇文章主要介绍了c#将Excel数据导入到数据库的实现代码,有需要的朋友可以参考一下 假如Excel中的数据如下: 数据库建表如下: 其中Id为自增字段: 代码: 代码如下: using Syste ...

  7. Hadoop基础-HDFS数据清理过程之校验过程代码分析

    Hadoop基础-HDFS数据清理过程之校验过程代码分析 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 想称为一名高级大数据开发工程师,不但需要了解hadoop内部的运行机制,还需 ...

  8. MySQL 数据备份与还原的示例代码

    MySQL 数据备份与还原的示例代码 这篇文章主要介绍了MySQL 数据备份与还原的相关知识,本文通过示例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下 一.数据备份 1.使用 ...

  9. 07.深入浅出 Spring Boot - 数据访问之Mybatis(附代码下载)

    MyBatis 在Spring Boot应用非常广,非常强大的一个半自动的ORM框架. 代码下载:https://github.com/Jackson0714/study-spring-boot.gi ...

  10. POI 导入excel数据自动封装成model对象--代码分析

    上完代码后,对代码进行主要的分析: 1.主要使用反射api将数数据注入javabean对象 2.代码中的日志信息级别为debug级别 3.获取ExcelImport对象后需要调用init()方法初始化 ...

随机推荐

  1. Jenkins多环境持续集成架构实践

    自动化部署主要是为了解决项目多.环境多.持续集成慢.部署操作麻烦.手动操作易出错.自动化运维等问题. Jenkins是开源CI&CD软件领导者, 提供超过1000个插件来支持构建.部署.自动化 ...

  2. XML 约束

    XML约束 一.约束 约束:规定 xml 文档的书写规则 要求: 1.能够在 xml 中引入约束文档 2.能够简单的读懂约束文档 分类: 1.DTD:一种简单的约束技术(后缀.dtd) 2.Schem ...

  3. Qt Table Widget常用操作

    一.鼠标悬浮在item上 显示提示信息 1.在构造函数开启table Widget控件的鼠标捕获功能 // 开启鼠标捕获功能(实现table widget的悬浮功能) ui.tableWidget-& ...

  4. Selenium文件上传

    转自:https://www.cnblogs.com/miaojjblog/p/9679915.html Web上本地上传图片,弹出的框Selenium是无法识别的,也就是说,selenium本身没有 ...

  5. android 给ImageView设置路径

    ImageView是Android程序中经常用到的组件,它将一个图片显示到屏幕上. 在UI xml定义一个ImageView如下: public void onCreate(Bundle savedI ...

  6. stm32 CAN过滤器组

    在互联型产品中, CAN1和CAN2分享28个过滤器组 其它STM32F103xx系列产品中有14个过滤器组 位宽设置 四种配置方式: 1个32位的屏蔽位模式 2个32位的标识符列表模式,可以过滤2个 ...

  7. WPF如何设置启动窗口

    在做系统时,我们想在启动时显示自己想显示的界面,和Winform不同的是它有两种方法 1.在App.xaml中 <Application x:Class="WpfApp1.App&qu ...

  8. 【JUC】4.Synchronized与ReentrantLock对比

    与synchronized相同,ReentrantLock也是一种互斥锁: synchronized与ReentrantLock的对比: 都是可重入锁 可以再次获取自己的内部锁,即:一个线程获取某对象 ...

  9. docer安装之pure-ftp

    https://hub.docker.com/r/stilliard/pure-ftpd Docker Pure-ftpd Server https://hub.docker.com/r/stilli ...

  10. markdown锚点

    转:https://blog.csdn.net/u012260238/article/details/87815170 markdown 语法文档:https://www.w3cschool.cn/l ...