梳理caffe代码io(十三)

梳理caffe代码io(十三)

io包含了创建临时文件临时目录操作,以及从txt文件以及bin文件读取proto数据或者写入proto的数据到txt或者bin文件。io其实就是提供如何读取如何写入的一些读取图像或者文件,以及它们之间的一些转化的函数。

hpp文件:

 

[cpp] view plain copy
 
  1. #ifndef CAFFE_UTIL_IO_H_  
  2. #define CAFFE_UTIL_IO_H_  
  3.   
  4. #include <unistd.h>  
  5. #include <string>  
  6.   
  7. #include "google/protobuf/message.h"  
  8.   
  9. #include "caffe/blob.hpp"  
  10. #include "caffe/common.hpp"  
  11. #include "caffe/proto/caffe.pb.h"  
  12.   
  13. namespace caffe {  
  14.   
  15. using ::google::protobuf::Message;  
  16. // 内联函数,创建临时文件  
  17. inline void MakeTempFilename(string* temp_filename) {  
  18.   temp_filename->clear();  
  19.   *temp_filename = "/tmp/caffe_test.XXXXXX";  
  20.   char* temp_filename_cstr = new char[temp_filename->size() + 1];  
  21.   // NOLINT_NEXT_LINE(runtime/printf)  
  22.   strcpy(temp_filename_cstr, temp_filename->c_str());  
  23.   int fd = mkstemp(temp_filename_cstr);  
  24.   CHECK_GE(fd, 0) << "Failed to open a temporary file at: " << *temp_filename;  
  25.   close(fd);  
  26.   *temp_filename = temp_filename_cstr;  
  27.   delete[] temp_filename_cstr;  
  28. }  
  29.   
  30. // 内联函数,创建临时目录  
  31. inline void MakeTempDir(string* temp_dirname) {  
  32.   temp_dirname->clear();  
  33.   *temp_dirname = "/tmp/caffe_test.XXXXXX";  
  34.   char* temp_dirname_cstr = new char[temp_dirname->size() + 1];  
  35.   // NOLINT_NEXT_LINE(runtime/printf)  
  36.   strcpy(temp_dirname_cstr, temp_dirname->c_str());  
  37.   char* mkdtemp_result = mkdtemp(temp_dirname_cstr);  
  38.   CHECK(mkdtemp_result != NULL)  
  39.       << "Failed to create a temporary directory at: " << *temp_dirname;  
  40.   *temp_dirname = temp_dirname_cstr;  
  41.   delete[] temp_dirname_cstr;  
  42. }  
  43. // 从txt读取proto的定义  
  44. bool ReadProtoFromTextFile(const char* filename, Message* proto);  
  45.   
  46. // 从text读取proto的定义  
  47. inline bool ReadProtoFromTextFile(const string& filename, Message* proto) {  
  48.   return ReadProtoFromTextFile(filename.c_str(), proto);  
  49. }  
  50. // 从text读取proto的定义,只是增加了检查而已  
  51. inline void ReadProtoFromTextFileOrDie(const char* filename, Message* proto) {  
  52.   CHECK(ReadProtoFromTextFile(filename, proto));  
  53. }  
  54. // 从text读取proto的定义,只是增加了检查而已  
  55. inline void ReadProtoFromTextFileOrDie(const string& filename, Message* proto) {  
  56.   ReadProtoFromTextFileOrDie(filename.c_str(), proto);  
  57. }  
  58. // 将proto写入到txt文件  
  59. void WriteProtoToTextFile(const Message& proto, const char* filename);  
  60. inline void WriteProtoToTextFile(const Message& proto, const string& filename) {  
  61.   WriteProtoToTextFile(proto, filename.c_str());  
  62. }  
  63. // 从bin读取proto的定义  
  64. bool ReadProtoFromBinaryFile(const char* filename, Message* proto);  
  65. // 从bin读取proto的定义  
  66. inline bool ReadProtoFromBinaryFile(const string& filename, Message* proto) {  
  67.   return ReadProtoFromBinaryFile(filename.c_str(), proto);  
  68. }  
  69. // 从bin读取proto的定义,只是增加了检查而已  
  70. inline void ReadProtoFromBinaryFileOrDie(const char* filename, Message* proto) {  
  71.   CHECK(ReadProtoFromBinaryFile(filename, proto));  
  72. }  
  73. // 从bin读取proto的定义,只是增加了检查而已  
  74. inline void ReadProtoFromBinaryFileOrDie(const string& filename,  
  75.                                          Message* proto) {  
  76.   ReadProtoFromBinaryFileOrDie(filename.c_str(), proto);  
  77. }  
  78.   
  79. // 将proto写入到bin文件  
  80. void WriteProtoToBinaryFile(const Message& proto, const char* filename);  
  81. // 内联函数,将proto写入到bin文件  
  82. inline void WriteProtoToBinaryFile(  
  83.     const Message& proto, const string& filename) {  
  84.   WriteProtoToBinaryFile(proto, filename.c_str());  
  85. }  
  86. // 从文件读取数据到Datum  
  87. bool ReadFileToDatum(const string& filename, const int label, Datum* datum);  
  88. // 内联函数,从文件读取数据到Datum  
  89. inline bool ReadFileToDatum(const string& filename, Datum* datum) {  
  90.   return ReadFileToDatum(filename, -1, datum);  
  91. }  
  92.   
  93. // 从图像文件读取数据到Datum  
  94. bool ReadImageToDatum(const string& filename, const int label,  
  95.     const int height, const int width, const bool is_color,  
  96.     const std::string & encoding, Datum* datum);  
  97. // 内联函数,从图像文件(彩色还是黑白?)读取数据到Datum,指定图像大小  
  98. inline bool ReadImageToDatum(const string& filename, const int label,  
  99.     const int height, const int width, const bool is_color, Datum* datum) {  
  100.   return ReadImageToDatum(filename, label, height, width, is_color,  
  101.                           "", datum);  
  102. }  
  103. // 内联函数,从彩色图像文件读取数据到Datum,指定图像大小  
  104. inline bool ReadImageToDatum(const string& filename, const int label,  
  105.     const int height, const int width, Datum* datum) {  
  106.   return ReadImageToDatum(filename, label, height, width, true, datum);  
  107. }  
  108. // 内联函数,从图像文件(彩色还是黑白?)读取数据到Datum,自动获取图像大小  
  109. inline bool ReadImageToDatum(const string& filename, const int label,  
  110.     const bool is_color, Datum* datum) {  
  111.   return ReadImageToDatum(filename, label, 0, 0, is_color, datum);  
  112. }  
  113. // 内联函数,从彩色图像文件读取数据到Datum,自动获取图像大小  
  114. inline bool ReadImageToDatum(const string& filename, const int label,  
  115.     Datum* datum) {  
  116.   return ReadImageToDatum(filename, label, 0, 0, true, datum);  
  117. }  
  118. // 内联函数,从彩色图像文件读取数据到Datum,自动获取图像大小,指定编码格式  
  119. inline bool ReadImageToDatum(const string& filename, const int label,  
  120.     const std::string & encoding, Datum* datum) {  
  121.   return ReadImageToDatum(filename, label, 0, 0, true, encoding, datum);  
  122. }  
  123. // 对Datum进行解码  
  124. bool DecodeDatumNative(Datum* datum);  
  125. // 对彩色图像的Datum进行解码  
  126. bool DecodeDatum(Datum* datum, bool is_color);  
  127.   
  128. #ifdef USE_OPENCV  
  129. // 将图像读取到CVMat,指定图像大小,是否彩色  
  130. cv::Mat ReadImageToCVMat(const string& filename,  
  131.     const int height, const int width, const bool is_color);  
  132. // 将图像读取到CVMat,指定图像大小  
  133. cv::Mat ReadImageToCVMat(const string& filename,  
  134.     const int height, const int width);  
  135. // 将图像读取到CVMat,指定是否彩色  
  136. cv::Mat ReadImageToCVMat(const string& filename,  
  137.     const bool is_color);  
  138. // 将图像读取到CVMat  
  139. cv::Mat ReadImageToCVMat(const string& filename);  
  140. // 将Datum解码为为CVMat  
  141. cv::Mat DecodeDatumToCVMatNative(const Datum& datum);  
  142. // 将彩色图像的Datum解码为为CVMat  
  143. cv::Mat DecodeDatumToCVMat(const Datum& datum, bool is_color);  
  144. // 将CVMat转换为Datum  
  145. void CVMatToDatum(const cv::Mat& cv_img, Datum* datum);  
  146. #endif  // USE_OPENCV  
  147.   
  148. }  // namespace caffe  
  149.   
  150. #endif   // CAFFE_UTIL_IO_H_  

实现:

[cpp] view plain copy
 
 在CODE上查看代码片派生到我的代码片
    1. #include <fcntl.h>  
    2. #include <google/protobuf/io/coded_stream.h>  
    3. #include <google/protobuf/io/zero_copy_stream_impl.h>  
    4. #include <google/protobuf/text_format.h>  
    5. #include <opencv2/core/core.hpp>  
    6. #ifdef USE_OPENCV  
    7. #include <opencv2/highgui/highgui.hpp>  
    8. #include <opencv2/highgui/highgui_c.h>  
    9. #include <opencv2/imgproc/imgproc.hpp>  
    10. #endif  // USE_OPENCV  
    11. #include <stdint.h>  
    12.   
    13. #include <algorithm>  
    14. #include <fstream>  // NOLINT(readability/streams)  
    15. #include <string>  
    16. #include <vector>  
    17.   
    18. #include "caffe/common.hpp"  
    19. #include "caffe/proto/caffe.pb.h"  
    20. #include "caffe/util/io.hpp"  
    21.   
    22. const int kProtoReadBytesLimit = INT_MAX;  // Max size of 2 GB minus 1 byte.  
    23.   
    24. namespace caffe {  
    25.   
    26. using google::protobuf::io::FileInputStream;  
    27. using google::protobuf::io::FileOutputStream;  
    28. using google::protobuf::io::ZeroCopyInputStream;  
    29. using google::protobuf::io::CodedInputStream;  
    30. using google::protobuf::io::ZeroCopyOutputStream;  
    31. using google::protobuf::io::CodedOutputStream;  
    32. using google::protobuf::Message;  
    33.   
    34. // 从文件读取Proto的txt文件  
    35. bool ReadProtoFromTextFile(const char* filename, Message* proto) {  
    36.   int fd = open(filename, O_RDONLY);  
    37.   CHECK_NE(fd, -1) << "File not found: " << filename;  
    38.   FileInputStream* input = new FileInputStream(fd);//新建一个FileInputStream对象 input  
    39.   // 注意如何使用protobuf去读取,解析input文件中的Message, 即使文件中参数定义顺序与Message中的参数定义顺序不一致,也可以解析。  
    40.   bool success = google::protobuf::TextFormat::Parse(input, proto);  
    41.   delete input;  
    42.   close(fd);  
    43.   return success;  
    44. }  
    45.   
    46. // 将proto写入到txt文件  
    47. void WriteProtoToTextFile(const Message& proto, const char* filename) {  
    48.   int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);  
    49.   FileOutputStream* output = new FileOutputStream(fd);  
    50.   // 注意如何写入  
    51.   CHECK(google::protobuf::TextFormat::Print(proto, output));  
    52.   delete output;  
    53.   close(fd);// 和ReadProtoFromTextFile功能相反  
    54. }  
    55.   
    56. // 从bin读取proto的定义  
    57. bool ReadProtoFromBinaryFile(const char* filename, Message* proto) {//读取二进制文件  
    58.   int fd = open(filename, O_RDONLY);  
    59.   CHECK_NE(fd, -1) << "File not found: " << filename;  
    60.   ZeroCopyInputStream* raw_input = new FileInputStream(fd);  
    61.   //  解码流com.google.protobuf.CodedInputStream  
    62.   CodedInputStream* coded_input = new CodedInputStream(raw_input);  
    63.  // 建立CodedInputStream类的对象coded_input  
    64.   coded_input->SetTotalBytesLimit(kProtoReadBytesLimit, 536870912);  
    65. //折设置最大字节限制  
    66.   bool success = proto->ParseFromCodedStream(coded_input);  
    67.   
    68.   delete coded_input;  
    69.   delete raw_input;  
    70.   close(fd);  
    71.   return success;  
    72. }  
    73.   
    74. // 将proto写入到bin文件  
    75. void WriteProtoToBinaryFile(const Message& proto, const char* filename) {  
    76.   fstream output(filename, ios::out | ios::trunc | ios::binary);  
    77.   CHECK(proto.SerializeToOstream(&output));  
    78. }  
    79.   
    80. #ifdef USE_OPENCV  
    81. // 将图像读取到CVMat,指定图像大小,是否彩色  
    82. cv::Mat ReadImageToCVMat(const string& filename,  
    83.     const int height, const int width, const bool is_color) {  
    84. //height,width都不为0则把图像resize 到height*width  
    85.   cv::Mat cv_img;  
    86.   int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR :  
    87.     CV_LOAD_IMAGE_GRAYSCALE);  
    88.   cv::Mat cv_img_origin = cv::imread(filename, cv_read_flag);//读入图像  
    89.   if (!cv_img_origin.data) {  
    90.     LOG(ERROR) << "Could not open or find file " << filename;  
    91.     return cv_img_origin;  
    92.   }  
    93.   if (height > 0 && width > 0) {  
    94.     cv::resize(cv_img_origin, cv_img, cv::Size(width, height));  
    95.   } else {  
    96.     cv_img = cv_img_origin;  
    97.   }  
    98.   return cv_img;  
    99. }  
    100.   
    101. cv::Mat ReadImageToCVMat(const string& filename,//is_color 为1读入彩色图像,0灰度图  
    102.     const int height, const int width) {  
    103.   return ReadImageToCVMat(filename, height, width, true);  
    104. }//重载函数,读入彩色图  
    105.   
    106. cv::Mat ReadImageToCVMat(const string& filename,  
    107.     const bool is_color) {  
    108.   return ReadImageToCVMat(filename, 0, 0, is_color);  
    109. }//重载函数,读入图像但不resize  
    110.   
    111. cv::Mat ReadImageToCVMat(const string& filename) {  
    112.   return ReadImageToCVMat(filename, 0, 0, true);  
    113. }//重载函数,读入彩色图像且不resize  
    114.   
    115. // Do the file extension and encoding match?  
    116. // 看看是不是jpg还是jpeg的图像  
    117. static bool matchExt(const std::string & fn,  
    118.                      std::string en) {  
    119.   size_t p = fn.rfind('.');//p 为文件名中“.”所在位置的索引  
    120.   std::string ext = p != fn.npos ? fn.substr(p) : fn;//ext为文件后缀名".xxx"  
    121.   std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);  
    122.  //把ext中的大写字母转化小写字母  
    123.   std::transform(en.begin(), en.end(), en.begin(), ::tolower);  
    124.   if ( ext == en )  
    125.     return true;  
    126.   if ( en == "jpg" && ext == "jpeg" )  
    127.     return true;  
    128.   return false;  
    129. }  
    130. // 从图像文件读取数据到Datum  
    131. bool ReadImageToDatum(const string& filename, const int label,  
    132.     const int height, const int width, const bool is_color,  
    133.     const std::string & encoding, Datum* datum) {  
    134.   cv::Mat cv_img = ReadImageToCVMat(filename, height, width, is_color);  
    135.   if (cv_img.data) {  
    136.     if (encoding.size()) {  
    137.       if ( (cv_img.channels() == 3) == is_color && !height && !width &&  
    138.           matchExt(filename, encoding) )  
    139.         return ReadFileToDatum(filename, label, datum);  
    140.       std::vector<uchar> buf;  
    141.       // 对数据解码  
    142.       cv::imencode("."+encoding, cv_img, buf);  
    143.       datum->set_data(std::string(reinterpret_cast<char*>(&buf[0]),  
    144.                       buf.size()));  
    145.       // 数据标签  
    146.       datum->set_label(label);  
    147.       // 是否被编码  
    148.       datum->set_encoded(true);  
    149.       return true;  
    150.     }  
    151.     CVMatToDatum(cv_img, datum);//cvmat转为Datum格式  
    152.     datum->set_label(label);  
    153.     return true;  
    154.   } else {  
    155.     return false;  
    156.   }  
    157. }  
    158. #endif  // USE_OPENCV  
    159. // 从文件读取数据到Datum  
    160. bool ReadFileToDatum(const string& filename, const int label,  
    161.     Datum* datum) {  
    162.   std::streampos size;//获取文件指针位置 size  
    163.   
    164.   fstream file(filename.c_str(), ios::in|ios::binary|ios::ate);  
    165.   if (file.is_open()) {  
    166.     size = file.tellg();//代表当前get 流指针的位置  
    167.     std::string buffer(size, ' ');  
    168.     file.seekg(0, ios::beg);//设置0输入文件流的起始位置  
    169.     file.read(&buffer[0], size);  
    170.     file.close();  
    171.     datum->set_data(buffer);//data_->assign(buffer)  
    172.     datum->set_label(label);//label_ = label  
    173.     datum->set_encoded(true);  
    174.     return true;  
    175.   } else {  
    176.     return false;  
    177.   }  
    178. }  
    179.   
    180. #ifdef USE_OPENCV  
    181. // 直接编码数据的Datum到CVMat  
    182. cv::Mat DecodeDatumToCVMatNative(const Datum& datum) {  
    183.   cv::Mat cv_img;  
    184.   CHECK(datum.encoded()) << "Datum not encoded";  
    185.   const string& data = datum.data();  
    186.   std::vector<char> vec_data(data.c_str(), data.c_str() + data.size());  
    187.   cv_img = cv::imdecode(vec_data, -1);//flag=-1  
    188.   if (!cv_img.data) {  
    189.     LOG(ERROR) << "Could not decode datum ";  
    190.   }  
    191.   return cv_img;  
    192. }  
    193.   
    194. // 直接编码彩色或者非彩色Datum到CVMat  
    195. cv::Mat DecodeDatumToCVMat(const Datum& datum, bool is_color) {  
    196.   cv::Mat cv_img;  
    197.   CHECK(datum.encoded()) << "Datum not encoded";  
    198.   const string& data = datum.data();  
    199.   std::vector<char> vec_data(data.c_str(), data.c_str() + data.size());  
    200.   int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR :  
    201.     CV_LOAD_IMAGE_GRAYSCALE);  
    202.   cv_img = cv::imdecode(vec_data, cv_read_flag);// flag为用户指定的,从内存都入图片  
    203.   if (!cv_img.data) {  
    204.     LOG(ERROR) << "Could not decode datum ";  
    205.   }  
    206.   return cv_img;//将encode 的Datum转化为cvMat  
    207. }  
    208.   
    209. // If Datum is encoded will decoded using DecodeDatumToCVMat and CVMatToDatum  
    210. // If Datum is not encoded will do nothing  
    211. bool DecodeDatumNative(Datum* datum) {  
    212.   if (datum->encoded()) {  
    213.     cv::Mat cv_img = DecodeDatumToCVMatNative((*datum));  
    214.     CVMatToDatum(cv_img, datum);  
    215.     return true;  
    216.   } else {  
    217.     return false;  
    218.   }  
    219. }  
    220.   
    221. // 将Datum进行解码  
    222. bool DecodeDatum(Datum* datum, bool is_color) {  
    223.   if (datum->encoded()) {  
    224.     cv::Mat cv_img = DecodeDatumToCVMat((*datum), is_color);  
    225.     CVMatToDatum(cv_img, datum);  
    226.     return true;  
    227.   } else {  
    228.     return false;  
    229.   }  
    230. }//将encodedDatum转化为没有encode的Datum  
    231.   
    232. // 将CVMat转换到Datum  
    233. void CVMatToDatum(const cv::Mat& cv_img, Datum* datum) {  
    234.   CHECK(cv_img.depth() == CV_8U) << "Image data type must be unsigned byte";  
    235.   datum->set_channels(cv_img.channels());  
    236.   datum->set_height(cv_img.rows);  
    237.   datum->set_width(cv_img.cols);//分别设置channel, height,width  
    238.   datum->clear_data();  
    239.   datum->clear_float_data();  
    240.   datum->set_encoded(false);  
    241.   int datum_channels = datum->channels();  
    242.   int datum_height = datum->height();  
    243.   int datum_width = datum->width();  
    244.   int datum_size = datum_channels * datum_height * datum_width;  
    245.   std::string buffer(datum_size, ' ');//将buffer初始化为字符''的datum_size个副本   
    246.   for (int h = 0; h < datum_height; ++h) {  
    247.     const uchar* ptr = cv_img.ptr<uchar>(h);//指向图像第h行的指针  
    248.     int img_index = 0;  
    249.     for (int w = 0; w < datum_width; ++w) {  
    250.       for (int c = 0; c < datum_channels; ++c) {  
    251.         int datum_index = (c * datum_height + h) * datum_width + w;  
    252.         buffer[datum_index] = static_cast<char>(ptr[img_index++]);  
    253.       }  
    254.     }  
    255.   }  
    256.   datum->set_data(buffer);  
    257. }  
    258. #endif  // USE_OPENCV  
    259. }  // namespace caffe  
posted @ 2016-04-12 10:31  菜鸡一枚  阅读(851)  评论(0编辑  收藏  举报