【caffe I/O】数据变换器(图像的预处理部分) 代码注释
caffe.proto中TransformationParameter部分
- // Message that stores parameters used to apply transformation
- // to the data layer's data
- message TransformationParameter {
- // For data pre-processing, we can do simple scaling and subtracting the
- // data mean, if provided. Note that the mean subtraction is always carried
- // out before scaling.
- //像素幅度缩放参数,默认不缩放
- optional float scale = [default = ];
- // Specify if we want to randomly mirror data.
- //图像随机镜像开关。默认false,不进行随机镜像操作
- optional bool mirror = [default = false];
- // Specify if we would like to randomly crop an image.
- //图像随机切块的大小。默认不切块。
- optional uint32 crop_size = [default = ];
- // mean_file and mean_value cannot be specified at the same time
- //存储图像均值的文件
- optional string mean_file = ;
- // if specified can be repeated once (would subtract it from all the channels)
- // or can be repeated the same number of times as channels
- // (would subtract them from the corresponding channel)
- //均值数值。无需读取文件。
- //如果均值数目和通道数一致,则每个通道分别减去对应均值;
- //如果没有均值只有一个,则每个通道减去相同的均值。
- repeated float mean_value = ;
- // Force the decoded image to have 3 color channels.
- //强制为三通道三色图像输入 默认false
- optional bool force_color = [default = false];
- // Force the decoded image to have 1 color channels.
- //强制为单通道灰度图像输入 默认false
- optional bool force_gray = [default = false];
- }
caffe.proto中Datum部分
- //Datum用来从LMDB/LEVELDB 中读取数据,或将数据写入其中。和BlobProto有相似功能,只是
- //BlobProto用于模型权值序列化反序列化,而Datum用于数据或特征图(feature map)提供序列化反序列化
- message Datum {
- //数据维度信息:channels*height*width
- optional int32 channels = ;
- optional int32 height = ;
- optional int32 width = ;
- // the actual image data, in bytes
- //图像数据,以字节类型存储
- optional bytes data = ;
- //标签数据,统一用int32类型存储
- optional int32 label = ;
- // Optionally, the datum could also hold float data.
- repeated float float_data = ;
- // If true data contains an encoded image that need to be decoded
- optional bool encoded = [default = false];//是否为编码数据,默认false
- }
include/caffe/data_transformer.hpp
- #ifndef CAFFE_DATA_TRANSFORMER_HPP
- #define CAFFE_DATA_TRANSFORMER_HPP
- #include <vector>
- #include "caffe/blob.hpp"
- #include "caffe/common.hpp"
- #include "caffe/proto/caffe.pb.h"
- namespace caffe {
- /**
- * @brief Applies common transformations to the input data, such as
- * scaling, mirroring, substracting the image mean...
- */
- template <typename Dtype>
- class DataTransformer {
- public:
- explicit DataTransformer(const TransformationParameter& param, Phase phase);
- virtual ~DataTransformer() {}
- /**
- * @brief Initialize the Random number generations if needed by the
- * transformation.
- */
- //初始化随机数种子函数
- void InitRand();
- /**
- * @brief Applies the transformation defined in the data layer's
- * transform_param block to the data.
- *
- * @param datum
- * Datum containing the data to be transformed.
- * @param transformed_blob
- * This is destination blob. It can be part of top blob's data if
- * set_cpu_data() is used. See data_layer.cpp for an example.
- */
- //数据读取层中transform_param块所声明的变换应用到输入数据中。
- //以下为多个重载函数
- void Transform(const Datum& datum, Blob<Dtype>* transformed_blob);
- /**
- * @brief Applies the transformation defined in the data layer's
- * transform_param block to a vector of Datum.
- *
- * @param datum_vector
- * A vector of Datum containing the data to be transformed.
- * @param transformed_blob
- * This is destination blob. It can be part of top blob's data if
- * set_cpu_data() is used. See memory_layer.cpp for an example.
- */
- void Transform(const vector<Datum> & datum_vector,
- Blob<Dtype>* transformed_blob);
- //使用OPENCV
- #ifdef USE_OPENCV
- /**
- * @brief Applies the transformation defined in the data layer's
- * transform_param block to a vector of Mat.
- *
- * @param mat_vector
- * A vector of Mat containing the data to be transformed.
- * @param transformed_blob
- * This is destination blob. It can be part of top blob's data if
- * set_cpu_data() is used. See memory_layer.cpp for an example.
- */
- void Transform(const vector<cv::Mat> & mat_vector,
- Blob<Dtype>* transformed_blob);
- /**
- * @brief Applies the transformation defined in the data layer's
- * transform_param block to a cv::Mat
- *
- * @param cv_img
- * cv::Mat containing the data to be transformed.
- * @param transformed_blob
- * This is destination blob. It can be part of top blob's data if
- * set_cpu_data() is used. See image_data_layer.cpp for an example.
- */
- void Transform(const cv::Mat& cv_img, Blob<Dtype>* transformed_blob);
- #endif // USE_OPENCV
- /**
- * @brief Applies the same transformation defined in the data layer's
- * transform_param block to all the num images in a input_blob.
- *
- * @param input_blob
- * A Blob containing the data to be transformed. It applies the same
- * transformation to all the num images in the blob.
- * @param transformed_blob
- * This is destination blob, it will contain as many images as the
- * input blob. It can be part of top blob's data.
- */
- void Transform(Blob<Dtype>* input_blob, Blob<Dtype>* transformed_blob);
- /**
- * @brief Infers the shape of transformed_blob will have when
- * the transformation is applied to the data.
- *
- * @param datum
- * Datum containing the data to be transformed.
- */
- //获取执行变换后输出Blob的形状
- vector<int> InferBlobShape(const Datum& datum);
- /**
- * @brief Infers the shape of transformed_blob will have when
- * the transformation is applied to the data.
- * It uses the first element to infer the shape of the blob.
- *
- * @param datum_vector
- * A vector of Datum containing the data to be transformed.
- */
- vector<int> InferBlobShape(const vector<Datum> & datum_vector);
- /**
- * @brief Infers the shape of transformed_blob will have when
- * the transformation is applied to the data.
- * It uses the first element to infer the shape of the blob.
- *
- * @param mat_vector
- * A vector of Mat containing the data to be transformed.
- */
- #ifdef USE_OPENCV
- vector<int> InferBlobShape(const vector<cv::Mat> & mat_vector);
- /**
- * @brief Infers the shape of transformed_blob will have when
- * the transformation is applied to the data.
- *
- * @param cv_img
- * cv::Mat containing the data to be transformed.
- */
- vector<int> InferBlobShape(const cv::Mat& cv_img);
- #endif // USE_OPENCV
- protected:
- /**
- * @brief Generates a random integer from Uniform({0, 1, ..., n-1}).
- *
- * @param n
- * The upperbound (exclusive) value of the random number.
- * @return
- * A uniformly random integer value from ({0, 1, ..., n-1}).
- */
- //产生取值0到n-1的随机整数,服从均匀分布
- virtual int Rand(int n);
- void Transform(const Datum& datum, Dtype* transformed_data);
- // Tranformation parameters
- //变换参数,该数据结构由ProtoBuffer工具自动生成
- TransformationParameter param_;
- //随机数生成器。声明在include/caffe/common.hpp中
- shared_ptr<Caffe::RNG> rng_;
- Phase phase_;//当前运行阶段。TRAIN或TEST。阶段不同,变换会有差异
- Blob<Dtype> data_mean_;//均值图像,从均值文件中读取
- vector<Dtype> mean_values_;//均值数值,从param_中提取
- };
- } // namespace caffe
- #endif // CAFFE_DATA_TRANSFORMER_HPP_
src/caffe/data_transformer.cpp
- #ifdef USE_OPENCV
- #include <opencv2/core/core.hpp>
- #endif // USE_OPENCV
- #include <string>
- #include <vector>
- #include "caffe/data_transformer.hpp"
- #include "caffe/util/io.hpp"
- #include "caffe/util/math_functions.hpp"
- #include "caffe/util/rng.hpp"
- namespace caffe {
- template<typename Dtype>
- DataTransformer<Dtype>::DataTransformer(const TransformationParameter& param,
- Phase phase)
- : param_(param), phase_(phase) {//初始化
- // check if we want to use mean_file
- //查看是否使用均值文件
- if (param_.has_mean_file()) {
- //如果param_中指定了均值文件又指定了均值数值则报错,二选一
- CHECK_EQ(param_.mean_value_size(), ) <<
- "Cannot specify mean_file and mean_value at the same time";
- const string& mean_file = param.mean_file();//获取均值文件名
- if (Caffe::root_solver()) {
- LOG(INFO) << "Loading mean file from: " << mean_file;
- }
- BlobProto blob_proto;//从均值文件中读取数据到blob_proto对象中
- ReadProtoFromBinaryFileOrDie(mean_file.c_str(), &blob_proto);
- data_mean_.FromProto(blob_proto);//从blob_proto将均值反序列化到data_mean_内存中
- }
- // check if we want to use mean_value
- //查看是否使用均值数值
- if (param_.mean_value_size() > ) {
- CHECK(param_.has_mean_file() == false) <<
- "Cannot specify mean_file and mean_value at the same time";
- for (int c = ; c < param_.mean_value_size(); ++c) {
- //读取均值数值,不再读取均值文件
- mean_values_.push_back(param_.mean_value(c));
- }
- }
- }
- //若干重载变换函数
- //该函数以Datum作为输入,结构体在caffe.proto中可见。输出为数据指针
- template<typename Dtype>
- void DataTransformer<Dtype>::Transform(const Datum& datum,
- Dtype* transformed_data) {
- //获得datum数据字串、维度信息
- const string& data = datum.data();
- const int datum_channels = datum.channels();
- const int datum_height = datum.height();
- const int datum_width = datum.width();
- //从param_获得处理参数。如切块大小、幅度缩放、随机镜像、图像均值等
- const int crop_size = param_.crop_size();
- const Dtype scale = param_.scale();
- const bool do_mirror = param_.mirror() && Rand();
- const bool has_mean_file = param_.has_mean_file();
- const bool has_uint8 = data.size() > ;
- const bool has_mean_values = mean_values_.size() > ;
- CHECK_GT(datum_channels, );//保证输入通道数大于零
- CHECK_GE(datum_height, crop_size);//保证输入数据的宽和高大于切块尺寸
- CHECK_GE(datum_width, crop_size);
- //获得图像均值
- Dtype* mean = NULL;
- if (has_mean_file) {//若指定了图像均值文件
- //保证图像的均值文件的维度和输入图像数据的维度完全相同
- CHECK_EQ(datum_channels, data_mean_.channels());
- CHECK_EQ(datum_height, data_mean_.height());
- CHECK_EQ(datum_width, data_mean_.width());
- mean = data_mean_.mutable_cpu_data();//获得图像均值数据控制权
- }
- if (has_mean_values) {//未指定图像均值文件,直接给出均值数值
- //保证均值数据维数是1,或与输入图像数据的通道数相同
- CHECK(mean_values_.size() == || mean_values_.size() == datum_channels) <<
- "Specify either 1 mean_value or as many as channels: " << datum_channels;
- if (datum_channels > && mean_values_.size() == ) {
- // Replicate the mean_value for simplicity
- //如果均值数据维度为1,且输入数据通道数大于1,则重复channels次
- for (int c = ; c < datum_channels; ++c) {
- mean_values_.push_back(mean_values_[]);
- }
- }
- }
- //输入图像的宽和高
- int height = datum_height;
- int width = datum_width;
- //开始图像切块
- int h_off = ;
- int w_off = ;
- if (crop_size) {//若不为0则进行切块,为0不切块
- height = crop_size;
- width = crop_size;
- // We only do random crop when we do training.
- // 在训练的时候随机crop图像块,这里需要自己实现Rand这个函数来确定是如何随机的
- if (phase_ == TRAIN) {
- h_off = Rand(datum_height - crop_size + );// 产生从0到datum_height - crop_size的随机数
- w_off = Rand(datum_width - crop_size + );//切块的width偏移量
- } else {//测试阶段只切取图像中心位置
- h_off = (datum_height - crop_size) / ;
- w_off = (datum_width - crop_size) / ;
- }
- }
- // 对数据进行变换,主要是将原来的像素值减去均值,然后乘以scale这么一个操作
- // 如果需要crop则最终转换的Blob的大小即为crop*crop
- // 如果不是,则最终的Blob大小即为datum_height*datum_width
- Dtype datum_element;//存放输入图像的像素值
- int top_index, data_index;//分别存放输出index和输入index
- for (int c = ; c < datum_channels; ++c) {
- for (int h = ; h < height; ++h) {
- for (int w = ; w < width; ++w) {
- data_index = (c * datum_height + h_off + h) * datum_width + w_off + w;
- if (do_mirror) {//若需要镜像操作,则输出index时设置width反向
- top_index = (c * height + h) * width + (width - - w);
- } else {
- top_index = (c * height + h) * width + w;
- }
- if (has_uint8) {// Datum中如果是uint8存储图像数据则转换为float
- datum_element =
- static_cast<Dtype>(static_cast<uint8_t>(data[data_index]));
- } else {//否则为float
- datum_element = datum.float_data(data_index);
- }
- if (has_mean_file) {//若指定了均值文件
- transformed_data[top_index] =
- (datum_element - mean[data_index]) * scale;//去均值,幅度缩放
- } else {
- if (has_mean_values) {//若指定了均值数值
- transformed_data[top_index] =
- (datum_element - mean_values_[c]) * scale;//去均值,幅度缩放
- } else {
- transformed_data[top_index] = datum_element * scale;//不去均值,只幅度缩放
- }
- }
- }
- }
- }
- }
- //与上一个函数类似,只是输出变成blob
- template<typename Dtype>
- void DataTransformer<Dtype>::Transform(const Datum& datum,
- Blob<Dtype>* transformed_blob) {
- // If datum is encoded, decode and transform the cv::image.
- if (datum.encoded()) {// 检查datum是否经过编码的图像,如果是则解码
- #ifdef USE_OPENCV
- // 先检查是不是两个属性都设置, 如果是则说明参数设置有误
- CHECK(!(param_.force_color() && param_.force_gray()))
- << "cannot set both force_color and force_gray";
- cv::Mat cv_img;
- if (param_.force_color() || param_.force_gray()) {
- // If force_color then decode in color otherwise decode in gray.
- // 如果强制彩色或者强制灰度图像一个成立则使用DecodeDatumToCVMat解码
- cv_img = DecodeDatumToCVMat(datum, param_.force_color());
- } else {// 否则使用DecodeDatumToCVMatNative解码
- cv_img = DecodeDatumToCVMatNative(datum);
- }
- // Transform the cv::image into blob.将cv::image 变换为 blob
- return Transform(cv_img, transformed_blob);
- #else
- LOG(FATAL) << "Encoded datum requires OpenCV; compile with USE_OPENCV.";
- #endif // USE_OPENCV
- } else {// 如果没有编码则检查force_color和force_gray是否设置,如果设置则不合法,因为该选项只适合于编码后的数据
- if (param_.force_color() || param_.force_gray()) {
- LOG(ERROR) << "force_color and force_gray only for encoded datum";
- }
- }
- const int crop_size = param_.crop_size();
- const int datum_channels = datum.channels();
- const int datum_height = datum.height();
- const int datum_width = datum.width();
- // Check dimensions.检查维度
- const int channels = transformed_blob->channels();
- const int height = transformed_blob->height();
- const int width = transformed_blob->width();
- const int num = transformed_blob->num();
- CHECK_EQ(channels, datum_channels);
- CHECK_LE(height, datum_height);
- CHECK_LE(width, datum_width);
- CHECK_GE(num, );
- if (crop_size) {
- CHECK_EQ(crop_size, height);
- CHECK_EQ(crop_size, width);
- } else {
- CHECK_EQ(datum_height, height);
- CHECK_EQ(datum_width, width);
- }
- // 参数变换完毕,调用现有函数
- Dtype* transformed_data = transformed_blob->mutable_cpu_data();
- Transform(datum, transformed_data);
- }
- //对一组datum数据进行变换
- template<typename Dtype>
- void DataTransformer<Dtype>::Transform(const vector<Datum> & datum_vector,
- Blob<Dtype>* transformed_blob) {
- const int datum_num = datum_vector.size();
- const int num = transformed_blob->num();// 变换到的目标blob的形状
- const int channels = transformed_blob->channels();
- const int height = transformed_blob->height();
- const int width = transformed_blob->width();
- CHECK_GT(datum_num, ) << "There is no datum to add";
- CHECK_LE(datum_num, num) <<
- "The size of datum_vector must be no greater than transformed_blob->num()";
- Blob<Dtype> uni_blob(, channels, height, width);// 新建一个uni_blob,里面只有一个batch。临时Blob
- //依次对每一个datum进行变换,放入对应的Blob之中
- for (int item_id = ; item_id < datum_num; ++item_id) {
- int offset = transformed_blob->offset(item_id);
- uni_blob.set_cpu_data(transformed_blob->mutable_cpu_data() + offset);
- Transform(datum_vector[item_id], &uni_blob);
- }
- }
- #ifdef USE_OPENCV
- //对一组cv::Mat对象进行变换,放入Blob中
- template<typename Dtype>
- void DataTransformer<Dtype>::Transform(const vector<cv::Mat> & mat_vector,
- Blob<Dtype>* transformed_blob) {
- // 获取mat的参数
- const int mat_num = mat_vector.size();
- const int num = transformed_blob->num();
- const int channels = transformed_blob->channels();
- const int height = transformed_blob->height();
- const int width = transformed_blob->width();
- CHECK_GT(mat_num, ) << "There is no MAT to add";
- CHECK_EQ(mat_num, num) <<
- "The size of mat_vector must be equals to transformed_blob->num()";
- Blob<Dtype> uni_blob(, channels, height, width);
- for (int item_id = ; item_id < mat_num; ++item_id) {
- int offset = transformed_blob->offset(item_id);
- uni_blob.set_cpu_data(transformed_blob->mutable_cpu_data() + offset);
- Transform(mat_vector[item_id], &uni_blob);
- }
- }
- // 对一个cv::Mat对象进行变换,放入Blob中。
- // 如果是图像的话,需要减去均值乘以scale,判断是不是需要做镜像处理
- // 逻辑与前面类似
- template<typename Dtype>
- void DataTransformer<Dtype>::Transform(const cv::Mat& cv_img,
- Blob<Dtype>* transformed_blob) {
- const int crop_size = param_.crop_size();
- const int img_channels = cv_img.channels();
- const int img_height = cv_img.rows;
- const int img_width = cv_img.cols;
- // Check dimensions.检查维度
- const int channels = transformed_blob->channels();
- const int height = transformed_blob->height();
- const int width = transformed_blob->width();
- const int num = transformed_blob->num();
- CHECK_EQ(channels, img_channels);
- CHECK_LE(height, img_height);
- CHECK_LE(width, img_width);
- CHECK_GE(num, );
- CHECK(cv_img.depth() == CV_8U) << "Image data type must be unsigned byte";
- const Dtype scale = param_.scale();
- const bool do_mirror = param_.mirror() && Rand();
- const bool has_mean_file = param_.has_mean_file();
- const bool has_mean_values = mean_values_.size() > ;
- CHECK_GT(img_channels, );
- CHECK_GE(img_height, crop_size);
- CHECK_GE(img_width, crop_size);
- Dtype* mean = NULL;
- if (has_mean_file) {
- CHECK_EQ(img_channels, data_mean_.channels());
- CHECK_EQ(img_height, data_mean_.height());
- CHECK_EQ(img_width, data_mean_.width());
- mean = data_mean_.mutable_cpu_data();
- }
- if (has_mean_values) {
- CHECK(mean_values_.size() == || mean_values_.size() == img_channels) <<
- "Specify either 1 mean_value or as many as channels: " << img_channels;
- if (img_channels > && mean_values_.size() == ) {
- // Replicate the mean_value for simplicity 复制均值便于操作
- for (int c = ; c < img_channels; ++c) {
- mean_values_.push_back(mean_values_[]);
- }
- }
- }
- int h_off = ;
- int w_off = ;
- cv::Mat cv_cropped_img = cv_img;
- if (crop_size) {
- CHECK_EQ(crop_size, height);
- CHECK_EQ(crop_size, width);
- // We only do random crop when we do training.只有训练阶段才随机切块
- if (phase_ == TRAIN) {
- h_off = Rand(img_height - crop_size + );
- w_off = Rand(img_width - crop_size + );
- } else {
- h_off = (img_height - crop_size) / ;
- w_off = (img_width - crop_size) / ;
- }
- cv::Rect roi(w_off, h_off, crop_size, crop_size);
- cv_cropped_img = cv_img(roi);
- } else {
- CHECK_EQ(img_height, height);
- CHECK_EQ(img_width, width);
- }
- CHECK(cv_cropped_img.data);
- Dtype* transformed_data = transformed_blob->mutable_cpu_data();
- int top_index;
- for (int h = ; h < height; ++h) {
- const uchar* ptr = cv_cropped_img.ptr<uchar>(h);
- int img_index = ;
- for (int w = ; w < width; ++w) {
- for (int c = ; c < img_channels; ++c) {
- if (do_mirror) {
- top_index = (c * height + h) * width + (width - - w);
- } else {
- top_index = (c * height + h) * width + w;
- }
- // int top_index = (c * height + h) * width + w;
- Dtype pixel = static_cast<Dtype>(ptr[img_index++]);
- if (has_mean_file) {
- int mean_index = (c * img_height + h_off + h) * img_width + w_off + w;
- transformed_data[top_index] =
- (pixel - mean[mean_index]) * scale;
- } else {
- if (has_mean_values) {
- transformed_data[top_index] =
- (pixel - mean_values_[c]) * scale;
- } else {
- transformed_data[top_index] = pixel * scale;
- }
- }
- }
- }
- }
- }
- #endif // USE_OPENCV
- //输入输出都是Blob
- template<typename Dtype>
- void DataTransformer<Dtype>::Transform(Blob<Dtype>* input_blob,
- Blob<Dtype>* transformed_blob) {
- const int crop_size = param_.crop_size();
- const int input_num = input_blob->num();
- const int input_channels = input_blob->channels();
- const int input_height = input_blob->height();
- const int input_width = input_blob->width();
- if (transformed_blob->count() == ) {
- // Initialize transformed_blob with the right shape.初始化变换后的Blob形状
- if (crop_size) {
- transformed_blob->Reshape(input_num, input_channels,
- crop_size, crop_size);
- } else {
- transformed_blob->Reshape(input_num, input_channels,
- input_height, input_width);
- }
- }
- const int num = transformed_blob->num();
- const int channels = transformed_blob->channels();
- const int height = transformed_blob->height();
- const int width = transformed_blob->width();
- const int size = transformed_blob->count();
- CHECK_LE(input_num, num);
- CHECK_EQ(input_channels, channels);
- CHECK_GE(input_height, height);
- CHECK_GE(input_width, width);
- const Dtype scale = param_.scale();
- const bool do_mirror = param_.mirror() && Rand();
- const bool has_mean_file = param_.has_mean_file();
- const bool has_mean_values = mean_values_.size() > ;
- int h_off = ;
- int w_off = ;
- if (crop_size) {
- CHECK_EQ(crop_size, height);
- CHECK_EQ(crop_size, width);
- // We only do random crop when we do training.只有训练阶段随机切块
- if (phase_ == TRAIN) {
- h_off = Rand(input_height - crop_size + );
- w_off = Rand(input_width - crop_size + );
- } else {
- h_off = (input_height - crop_size) / ;
- w_off = (input_width - crop_size) / ;
- }
- } else {
- CHECK_EQ(input_height, height);
- CHECK_EQ(input_width, width);
- }
- Dtype* input_data = input_blob->mutable_cpu_data();
- if (has_mean_file) {
- CHECK_EQ(input_channels, data_mean_.channels());
- CHECK_EQ(input_height, data_mean_.height());
- CHECK_EQ(input_width, data_mean_.width());
- for (int n = ; n < input_num; ++n) {
- int offset = input_blob->offset(n);
- /*
- template <typename Dtype>
- void caffe_sub(const int N, const Dtype* a, const Dtype* b, Dtype* y);
- math_function中定义的caffe_sub目的是矩阵相减input_data(以offset开始的矩阵) = input_data(以offset开始的矩阵) - data_mean_
- */
- caffe_sub(data_mean_.count(), input_data + offset,
- data_mean_.cpu_data(), input_data + offset);
- }
- }
- if (has_mean_values) {
- CHECK(mean_values_.size() == || mean_values_.size() == input_channels) <<
- "Specify either 1 mean_value or as many as channels: " << input_channels;
- if (mean_values_.size() == ) {
- caffe_add_scalar(input_blob->count(), -(mean_values_[]), input_data);
- } else {
- for (int n = ; n < input_num; ++n) {
- for (int c = ; c < input_channels; ++c) {
- int offset = input_blob->offset(n, c);
- // 给input_data[offset]地址开始的每一个元素加上一个-mean_values_[c]
- caffe_add_scalar(input_height * input_width, -(mean_values_[c]),
- input_data + offset);
- }
- }
- }
- }
- // 如果什么均值都没有则直接复制
- Dtype* transformed_data = transformed_blob->mutable_cpu_data();
- for (int n = ; n < input_num; ++n) {
- int top_index_n = n * channels;
- int data_index_n = n * channels;
- for (int c = ; c < channels; ++c) {
- int top_index_c = (top_index_n + c) * height;
- int data_index_c = (data_index_n + c) * input_height + h_off;
- for (int h = ; h < height; ++h) {
- int top_index_h = (top_index_c + h) * width;
- int data_index_h = (data_index_c + h) * input_width + w_off;
- if (do_mirror) {
- int top_index_w = top_index_h + width - ;
- for (int w = ; w < width; ++w) {
- transformed_data[top_index_w-w] = input_data[data_index_h + w];
- }
- } else {
- for (int w = ; w < width; ++w) {
- transformed_data[top_index_h + w] = input_data[data_index_h + w];
- }
- }
- }
- }
- }
- if (scale != Dtype()) {
- DLOG(INFO) << "Scale: " << scale;
- caffe_scal(size, scale, transformed_data);
- }
- }
- //获得数据变换输出尺寸
- template<typename Dtype>
- vector<int> DataTransformer<Dtype>::InferBlobShape(const Datum& datum) {
- if (datum.encoded()) {
- #ifdef USE_OPENCV
- // 如果使用OpenCV则可以用先转换为CVMat,然后推断blob的形状
- CHECK(!(param_.force_color() && param_.force_gray()))
- << "cannot set both force_color and force_gray";
- cv::Mat cv_img;
- if (param_.force_color() || param_.force_gray()) {
- // If force_color then decode in color otherwise decode in gray.
- cv_img = DecodeDatumToCVMat(datum, param_.force_color());
- } else {
- cv_img = DecodeDatumToCVMatNative(datum);
- }
- // InferBlobShape using the cv::image.
- return InferBlobShape(cv_img);
- #else
- LOG(FATAL) << "Encoded datum requires OpenCV; compile with USE_OPENCV.";
- #endif // USE_OPENCV
- }
- // 否则直接粗暴地从datum里面获取形状的数据
- const int crop_size = param_.crop_size();
- const int datum_channels = datum.channels();
- const int datum_height = datum.height();
- const int datum_width = datum.width();
- // Check dimensions.检查维度
- CHECK_GT(datum_channels, );
- CHECK_GE(datum_height, crop_size);
- CHECK_GE(datum_width, crop_size);
- // Build BlobShape. 创建BlobShape对象
- vector<int> shape();
- shape[] = ;
- shape[] = datum_channels;
- shape[] = (crop_size)? crop_size: datum_height;
- shape[] = (crop_size)? crop_size: datum_width;
- return shape;
- }
- template<typename Dtype>
- vector<int> DataTransformer<Dtype>::InferBlobShape(
- const vector<Datum> & datum_vector) {
- const int num = datum_vector.size();
- CHECK_GT(num, ) << "There is no datum to in the vector";
- // Use first datum in the vector to InferBlobShape.使用第一个推断
- vector<int> shape = InferBlobShape(datum_vector[]);
- // Adjust num to the size of the vector.
- shape[] = num;
- return shape;
- }
- #ifdef USE_OPENCV
- // 如果使用OpenCV
- // 使用CVMat中的信息来推断形状
- template<typename Dtype>
- vector<int> DataTransformer<Dtype>::InferBlobShape(const cv::Mat& cv_img) {
- const int crop_size = param_.crop_size();
- const int img_channels = cv_img.channels();
- const int img_height = cv_img.rows;
- const int img_width = cv_img.cols;
- // Check dimensions.
- CHECK_GT(img_channels, );
- CHECK_GE(img_height, crop_size);
- CHECK_GE(img_width, crop_size);
- // Build BlobShape.
- vector<int> shape();
- shape[] = ;
- shape[] = img_channels;
- shape[] = (crop_size)? crop_size: img_height;
- shape[] = (crop_size)? crop_size: img_width;
- return shape;
- }
- template<typename Dtype>
- vector<int> DataTransformer<Dtype>::InferBlobShape(
- const vector<cv::Mat> & mat_vector) {
- const int num = mat_vector.size();
- CHECK_GT(num, ) << "There is no cv_img to in the vector";
- // Use first cv_img in the vector to InferBlobShape.
- vector<int> shape = InferBlobShape(mat_vector[]);
- // Adjust num to the size of the vector.
- shape[] = num;
- return shape;
- }
- #endif // USE_OPENCV
- // 初始化随机数种子
- template <typename Dtype>
- void DataTransformer<Dtype>::InitRand() {
- // 要么需要镜像要么训练阶段和需要crop同时满足的情况下才初始化随机数种子
- const bool needs_rand = param_.mirror() ||
- (phase_ == TRAIN && param_.crop_size());
- if (needs_rand) {
- const unsigned int rng_seed = caffe_rng_rand();// 获得随机数种子(通过熵池或者时间生成种子)
- rng_.reset(new Caffe::RNG(rng_seed));//初始化随机数种子并实例化随机数生成器
- } else {
- rng_.reset();//否则随机数生成器设置为空
- }
- }
- // 产生从0到n的随机数
- template <typename Dtype>
- int DataTransformer<Dtype>::Rand(int n) {
- CHECK(rng_);
- CHECK_GT(n, );
- caffe::rng_t* rng =
- static_cast<caffe::rng_t*>(rng_->generator());
- return ((*rng)() % n);
- }
- INSTANTIATE_CLASS(DataTransformer);
- /*
- 初始化类的宏定义
- #define INSTANTIATE_CLASS(classname) \
- char gInstantiationGuard##classname; \
- template class classname<float>; \
- template class classname<double>
- */
- } // namespace caffe
摘抄参考赵永科《21天实战caffe》
同时参考http://blog.csdn.net/langb2014/article/details/51050213
【caffe I/O】数据变换器(图像的预处理部分) 代码注释的更多相关文章
- 【撸码caffe 五】数据层搭建
caffe.cpp中的train函数内声明了一个类型为Solver类的智能指针solver: // Train / Finetune a model. int train() { -- shared_ ...
- caffe添加python数据层
caffe添加python数据层(ImageData) 在caffe中添加自定义层时,必须要实现这四个函数,在C++中是(LayerSetUp,Reshape,Forward_cpu,Backward ...
- 【caffe Blob】caffe中与Blob相关的代码注释、使用举例
首先,Blob使用的小例子(通过运行结果即可知道相关功能): #include <vector> #include <caffe/blob.hpp> #include < ...
- json转换数据后面参数要带ture,代码
强大的PHP已经提供了内置函数:json_encode() 和 json_decode().很容易理解,json_encode()就是将PHP数组转换成Json.相反,json_decode()就是将 ...
- 使用gfortran将数据写成Grads格式的代码示例
使用gfortran将数据写成Grads格式的代码示例: !-----'Fortran4Grads.f90' program Fortran4Grads implicit none integer,p ...
- c#将Excel数据导入到数据库的实现代码
这篇文章主要介绍了c#将Excel数据导入到数据库的实现代码,有需要的朋友可以参考一下 假如Excel中的数据如下: 数据库建表如下: 其中Id为自增字段: 代码: 代码如下: using Syste ...
- Hadoop基础-HDFS数据清理过程之校验过程代码分析
Hadoop基础-HDFS数据清理过程之校验过程代码分析 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 想称为一名高级大数据开发工程师,不但需要了解hadoop内部的运行机制,还需 ...
- MySQL 数据备份与还原的示例代码
MySQL 数据备份与还原的示例代码 这篇文章主要介绍了MySQL 数据备份与还原的相关知识,本文通过示例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下 一.数据备份 1.使用 ...
- 07.深入浅出 Spring Boot - 数据访问之Mybatis(附代码下载)
MyBatis 在Spring Boot应用非常广,非常强大的一个半自动的ORM框架. 代码下载:https://github.com/Jackson0714/study-spring-boot.gi ...
- POI 导入excel数据自动封装成model对象--代码分析
上完代码后,对代码进行主要的分析: 1.主要使用反射api将数数据注入javabean对象 2.代码中的日志信息级别为debug级别 3.获取ExcelImport对象后需要调用init()方法初始化 ...
随机推荐
- Jenkins多环境持续集成架构实践
自动化部署主要是为了解决项目多.环境多.持续集成慢.部署操作麻烦.手动操作易出错.自动化运维等问题. Jenkins是开源CI&CD软件领导者, 提供超过1000个插件来支持构建.部署.自动化 ...
- XML 约束
XML约束 一.约束 约束:规定 xml 文档的书写规则 要求: 1.能够在 xml 中引入约束文档 2.能够简单的读懂约束文档 分类: 1.DTD:一种简单的约束技术(后缀.dtd) 2.Schem ...
- Qt Table Widget常用操作
一.鼠标悬浮在item上 显示提示信息 1.在构造函数开启table Widget控件的鼠标捕获功能 // 开启鼠标捕获功能(实现table widget的悬浮功能) ui.tableWidget-& ...
- Selenium文件上传
转自:https://www.cnblogs.com/miaojjblog/p/9679915.html Web上本地上传图片,弹出的框Selenium是无法识别的,也就是说,selenium本身没有 ...
- android 给ImageView设置路径
ImageView是Android程序中经常用到的组件,它将一个图片显示到屏幕上. 在UI xml定义一个ImageView如下: public void onCreate(Bundle savedI ...
- stm32 CAN过滤器组
在互联型产品中, CAN1和CAN2分享28个过滤器组 其它STM32F103xx系列产品中有14个过滤器组 位宽设置 四种配置方式: 1个32位的屏蔽位模式 2个32位的标识符列表模式,可以过滤2个 ...
- WPF如何设置启动窗口
在做系统时,我们想在启动时显示自己想显示的界面,和Winform不同的是它有两种方法 1.在App.xaml中 <Application x:Class="WpfApp1.App&qu ...
- 【JUC】4.Synchronized与ReentrantLock对比
与synchronized相同,ReentrantLock也是一种互斥锁: synchronized与ReentrantLock的对比: 都是可重入锁 可以再次获取自己的内部锁,即:一个线程获取某对象 ...
- docer安装之pure-ftp
https://hub.docker.com/r/stilliard/pure-ftpd Docker Pure-ftpd Server https://hub.docker.com/r/stilli ...
- markdown锚点
转:https://blog.csdn.net/u012260238/article/details/87815170 markdown 语法文档:https://www.w3cschool.cn/l ...