MNIST图片文件格式
train-images-idx3-ubyte
文件偏移量 | 数据类型 | 值 | 描述 |
---|---|---|---|
0000 | 32位整型 | 2051 | 魔数(大端存储) |
0004 | 32位整型 | 60000 | 文件包涵条目总数 |
0008 | 32位整型 | 28 | 行数 |
0012 | 32位整型 | 28 | 列数 |
0016 | 8位字节 | ? | 像素值(0~255) |
0017 | 8位字节 | ? | 像素值(0~255) |
… | … | … | … |
train-labels-idx1-ubyte
文件偏移量 | 数据类型 | 值 | 描述 |
---|---|---|---|
0000 | 32位整型 | 2051 | 魔数(大端存储) |
0004 | 32位整型 | 60000 | 文件包涵条目总数 |
0008 | 8位字节 | ? | 标签值(0~9) |
0009 | 8位字节 | ? | 标签值(0~9) |
… | … | … | … |
测试集的数据格式和训练及相同
MNIST数据集格式转换
在训练网络前我们使用create_mnist.sh脚本将MNIST数据集转换成lmdb格式,在该脚本中调用了convert_mnist_data.bin,这个可执行文件的源代码在examples/mnist/convert_mnist_data.cpp中。通过修改convert_mnist_data.cpp中的代码,可以将MNIST数据集转换成图片。在examples/mnist/目录下新建convert_mnist_image.cpp文件,内容如下:
// This script converts the MNIST dataset to image (png) format
// Usage:
// convert_mnist_image [FLAGS] input_image_file output_png_file
// The MNIST dataset could be downloaded at
// http://yann.lecun.com/exdb/mnist/
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fstream> // NOLINT(readability/streams)
#include <string>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using std::string;
DEFINE_int32(rows, 25, "The rows of index in image");
DEFINE_int32(cols, 40, "The cols of index in image");
DEFINE_int32(offset, 0, "The offset of index in raw image");
//大端模式小端模式转换
uint32_t swap_endian(uint32_t val) {
val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF);
return (val << 16) | (val >> 16);
}
//数据集转换函数,输入参数:MNIST数据集文件,图片文件
void convert_image(const char* image_filename, const char* png_filename) {
// Open files
std::ifstream image_file(image_filename, std::ios::in | std::ios::binary);
CHECK(image_file) << "Unable to open file " << image_filename;
// Read the magic and the meta data
uint32_t magic;
uint32_t num_items;
uint32_t rows;
uint32_t cols;
//读取魔数
image_file.read(reinterpret_cast<char*>(&magic), 4);
magic = swap_endian(magic);
CHECK_EQ(magic, 2051) << "Incorrect image file magic.";
//读取数据条目总数
image_file.read(reinterpret_cast<char*>(&num_items), 4);
num_items = swap_endian(num_items);
//读取行数
image_file.read(reinterpret_cast<char*>(&rows), 4);
rows = swap_endian(rows);
//读取列数
image_file.read(reinterpret_cast<char*>(&cols), 4);
cols = swap_endian(cols);
//命令行参数读取
const int flag_rows = FLAGS_rows;
const int flag_cols = FLAGS_cols;
const int offset = FLAGS_offset;
const int width = flag_cols*cols;
const int height = flag_rows*rows;
char* pixels = new char[rows * cols];
cv::Mat tp = cv::Mat::zeros(height, width, CV_8UC1);
//使用读取MINST数据,写入到opencv中的Mat类对象中
image_file.seekg(offset*rows*cols, std::ios::cur);
for(int i=0; i<flag_rows; i++) {
for(int j=0; j<flag_cols; j++) {
if(!image_file.eof()) {
image_file.read(pixels, rows * cols);
for(int k=0; k<rows; k++) {
for(int l=0; l<cols; l++) {
tp.at<uchar>(k + i*rows, j*cols + l) = (int)pixels[k*cols+l];
}
}
}
else {
for(int k=0; k<rows; k++) {
for(int l=0; l<cols; l++) {
tp.at<uchar>(k + i*rows, j*cols + l) = 0;
}
}
}
}
}
//调用opencv中的函数保存图片
cv::imwrite(png_filename, tp);
}
int main(int argc, char** argv) {
#ifndef GFLAGS_GFLAGS_H_
namespace gflags = google;
#endif
FLAGS_alsologtostderr = 1;
// 设设置命令行参数帮助信息
gflags::SetUsageMessage("This script converts the MNIST dataset to\n"
"image(png) format.\n"
"Usage:\n"
" convert_mnist_data [FLAGS] input_image_file "
"output_png_file\n"
"The MNIST dataset could be downloaded at\n"
" http://yann.lecun.com/exdb/mnist/\n"
"You should gunzip them after downloading,"
"or directly use data/mnist/get_mnist.sh\n");
gflags::ParseCommandLineFlags(&argc, &argv, true);
if (argc != 3) {
gflags::ShowUsageWithFlagsRestrict(argv[0],
"examples/mnist/convert_mnist_data");
} else {
google::InitGoogleLogging(argv[0]);
//转换图片
convert_image(argv[1], argv[2]);
}
return 0;
}
在Caffe根目录下执行make命令就可以完成该文件的编译
$ make
在build/examples/mnist/目录下会生成convert_mnist_image.bin文件。通过执行这个文件可以生成图片。
$ ./build/examples/mnist/convert_mnist_image.bin data/mnist/train-images-idx3-ubyte examples/mnist/image.png
执行该命令后输出如下图片:
图片默认横向40个数据,纵向25个数据。可以加命令行参数,如-cols=20 -rows=15改变图像大小为横向20个数据,纵向15个数据。