C++基于文件流和armadillo读取mnist

C++基于文件流和armadillo读取mnist

发现网上大把都是用python读取mnist的,用C++大都是用opencv读取的,但我不怎么用opencv,因此自己摸索了个使用文件流读取mnist的方法,armadillo仅作为储存矩阵的一种方式。

1. mnist文件

首先避坑,这些文件要解压。
%title插图%num
官网截图可知,文件头很简单,只有若干个32位整数,MSB,像素和标签均是无符号字节(即unsigned char)可以先读取文件头,再读取剩下的部分。

2. 读取文件头

我觉得没什么必要啊,直接跳过不行吗
文件头都是32位,那就整四个unsigned char呗。

	uchar a, b, c, d;
	File >> a >> b >> c >> d;

这样a、b、c、d就保存了一个整数。

x = ((((a * 256) + b) * 256) + c) * 256 + d;

然后就得到了呗。
看每个文件有多少文件头,就操作几次(并可以顺便与官方的magic number进行对比),剩下的就是文件的内容了。

3. 读取内容

这部分可以依照之前的方法,一次读取一个字符,再保存至矩阵当中。例如:

uchar a;
mat image(28, 28, fill::zeros); // 这是个矩阵!
for(int i = 0; i < 28; i++) //28行28列的图像懒得改了
	for(int j = 0; j < 28; j++)
	{
		File >> a;
		image(i, j) = double(a);
	}

这样就读取了一张图片。其余以此类推吧。

4. 完整代码

可以复制,可以修改,也可以用于商用和学术,但是请标注原作者(就是我)。
mnist.h

#ifndef MNIST_H  
#define MNIST_H
#include<iostream>
#include<fstream>
#include<armadillo>

#define uchar unsigned char

using namespace std;
using namespace arma;

//小端存储转换
int reverseInt(uchar a, uchar b, uchar c, uchar d);

//读取image数据集信息
mat read_mnist_image(const string fileName);

//读取label数据集信息
mat read_mnist_label(const string fileName);
#endif

mnist.cpp

//mnist.cpp
//作者:C艹
#include "mnist.h"

int reverseInt(uchar a, uchar b, uchar c, uchar d)
{
	return ((((a * 256) + b) * 256) + c) * 256 + d;
}

mat read_mnist_image(const string fileName)
{
	fstream File;
	mat image;
	File.open(fileName);
	if (!File.is_open()) // cannot open file
	{
		cout << "文件打不开啊" << endl;
		return mat(0, 0, fill::zeros);
	}
	uchar a, b, c, d;
	File >> a >> b >> c >> d;
	int magic = reverseInt(a, b, c, d);
	if (magic != 2051) //magic number wrong
	{
		cout << magic;
		return mat(0, 0, fill::zeros);
	}
	File >> a >> b >> c >> d;
	int num_img = reverseInt(a, b, c, d);
	File >> a >> b >> c >> d;
	int num_row = reverseInt(a, b, c, d);
	File >> a >> b >> c >> d;
	int num_col = reverseInt(a, b, c, d);
	// 文件头读取完毕
	image = mat(num_img, num_col * num_row, fill::zeros);
	for(int i = 0; i < num_img; i++)
		for (int j = 0; j < num_col * num_row; j++)
		{
			File >> a;
			image(i, j) = double(a);
		}
	return image;
}

mat read_mnist_label(const string fileName)
{
	fstream File;
	mat label;
	File.open(fileName);
	if (!File.is_open()) // cannot open file
	{
		cout << "文件打不开啊" << endl;
		return mat(0, 0, fill::zeros);
	}
	uchar a, b, c, d;
	File >> a >> b >> c >> d;
	int magic = reverseInt(a, b, c, d);
	if (magic != 2049) //magic number wrong
	{
		cout << magic;
		return mat(0, 0, fill::zeros);
	}
	File >> a >> b >> c >> d;
	int num_lab = reverseInt(a, b, c, d);
	// 文件头读取完毕
	label = mat(num_lab, 10, fill::zeros);
	for (int i = 0; i < num_lab; i++)
	{
		File >> a;
		label(i, int(a)) = 1;
	}
	return label;
}

分享到 :
相关推荐