深度学习3番外篇---mnist数据集格式及转换

mnist是在图像机器学习占据“Hello World”地位的库。下载地址如下:http://yann.lecun.com/exdb/mnist/
  train-images-idx3-ubyte(训练集数据,存放训练图像的集合)
  train-labels-idx1-ubyte(训练集标签,存放训练图像属于1~9中的哪一个)
  t10k-images-idx3-ubyte(测试集数据,存放测试图像的集合)
  t10k-labels-idx1-ubyte(测试集标签,存放测试图像属于1~9中的哪一个)
  可见其是两类文件,数据和标签。
  首先数据文件的存放格式如下:
  第0~3字节:为魔数,其实就是校验位,告诉我们这个文件就是数据文件
  第4~7字节:图像个数,告诉我们这个数据集里面存放了多少张图像
  第8~11字节:每个图像有多少行
  第12~15字节:每个图像有多少列
  后面的数据是按先列后行的方式存储的图像数据,一张图像的占用空间为:(行×列)个字节
  有了上面这些信息,就可以从数据文件中解析出图像了,代码如下:

#include <opencv2/opencv.hpp>    
using namespace cv;
void main()
{
	char savepath[30];//图像存储路径
	uchar readbuf[4];//信息数据读取空间
	FILE *f;
	fopen_s(&f, "train-images.idx3-ubyte","rb");
	fread_s(readbuf, 4, 1, 4, f);//读取魔数,即文件标志位
	fread_s(readbuf, 4, 1, 4, f);//读取数据集图像个数
	int numOfImg = (readbuf[0] << 24)+ (readbuf[1] << 16)+(readbuf[2]<<8)+ readbuf[3];//图像个数
	fread_s(readbuf, 4, 1, 4, f);//读取数据集图像行数
	int imgheight= (readbuf[0] << 24) + (readbuf[1] << 16) + (readbuf[2] << 8) + readbuf[3];//图像行数
	fread_s(readbuf, 4, 1, 4, f);//读取数据集图像列数
	int imgwidth = (readbuf[0] << 24) + (readbuf[1] << 16) + (readbuf[2] << 8) + readbuf[3];//图像列数
	int imgdatalen = imgheight*imgwidth;//图像数据长度
	Mat img(imgheight, imgwidth, CV_8UC1);
	for (int i = 0; i < numOfImg; i++)
	{
		sprintf_s(savepath, 30,"train-images\\%5d.png", i + 1);
		fread_s(img.data, imgdatalen, 1, imgdatalen, f);//读取数据集图像列数
		imwrite(savepath, img);
		if ((i+1)%100==0)
		{
			printf("%5d.png\n", i + 1);
		}
	}
	img.release();
	fclose(f);
}

因为图像是用来训练测试的,因此光有图像数据本身不够,还要知道图像上面的字符到底是个啥,这也就是标签文件的作用。其格式如下:
  第0~3字节:为魔数,也就是校验位,告诉我们这个文件就是标签文件
  第4~7字节:标签个数,告诉我们这个数据集里面存放了多少个图像的标签
  后面一个字节代表一个标签(0~9中的一个数)
  有了上面这些信息,就可以从标签文件中解析出图像标签了,代码如下:

#include <opencv2/opencv.hpp>    
using namespace cv;
void main()
{
	uchar readbuf[4];//信息数据读取空间
	FILE *f;
	fopen_s(&f, "train-labels.idx1-ubyte", "rb");
	fread_s(readbuf, 4, 1, 4, f);//读取魔数,即文件标志位
	fread_s(readbuf, 4, 1, 4, f);//读取数据集图像个数
	int numOfImg = (readbuf[0] << 24) + (readbuf[1] << 16) + (readbuf[2] << 8) + readbuf[3];//图像个数
	for (int i = 1; i <= numOfImg; i++)
	{
		fread_s(readbuf, 1, 1, 1, f);//读取数据集图像列数
		printf("%d    ", readbuf[0]);
	}
	fclose(f);
}

对比解析出来的图像和标签,很容易发现他们是一一对应的,这也是其意义所在。

为了训练方便,我们一般用一个数组将标签和图像数据存在一起,代码如下:

#include "stdafx.h"
#include <opencv2/opencv.hpp>    
using namespace cv;

class numImg
{
public:
	Mat img;
	uchar tag;
};

void main()
{
	/**********************************/
	/***********读取图片数据***********/
	/**********************************/
	char savepath[30];//图像存储路径
	uchar readbuf[4];//信息数据读取空间
	FILE *f;
	fopen_s(&f, "train-images.idx3-ubyte", "rb");
	fread_s(readbuf, 4, 1, 4, f);//读取魔数,即文件标志位
	fread_s(readbuf, 4, 1, 4, f);//读取数据集图像个数
	int sumOfImg = (readbuf[0] << 24) + (readbuf[1] << 16) + (readbuf[2] << 8) + readbuf[3];//图像个数
	fread_s(readbuf, 4, 1, 4, f);//读取数据集图像行数
	int imgheight = (readbuf[0] << 24) + (readbuf[1] << 16) + (readbuf[2] << 8) + readbuf[3];//图像行数
	fread_s(readbuf, 4, 1, 4, f);//读取数据集图像列数
	int imgwidth = (readbuf[0] << 24) + (readbuf[1] << 16) + (readbuf[2] << 8) + readbuf[3];//图像列数
	int imgdatalen = imgheight * imgwidth;//图像数据长度
	numImg* mNumImg=new	numImg[sumOfImg];
	for (int i = 0; i < sumOfImg; i++)
	{
		mNumImg[i].img = Mat(imgheight, imgwidth, CV_8UC1);
		fread_s(mNumImg[i].img.data, imgdatalen, 1, imgdatalen, f);//读取数据集图像列数
	}
	fclose(f);
	/**********************************/
	/***********读取标签数据***********/
	/**********************************/
	fopen_s(&f, "train-labels.idx1-ubyte", "rb");
	fread_s(readbuf, 4, 1, 4, f);//读取魔数,即文件标志位
	fread_s(readbuf, 4, 1, 4, f);//读取数据集图像个数
	sumOfImg = (readbuf[0] << 24) + (readbuf[1] << 16) + (readbuf[2] << 8) + readbuf[3];//图像个数
	for (int i = 0; i <= sumOfImg; i++)
	{
		fread_s(&mNumImg[i].tag, 1, 1, 1, f);//读取数据集图像列数
		//printf("%d    ", mNumImg[i].tag);
		//imshow("", mNumImg[i].img);
		//waitKey(3000);
	}
	fclose(f);

	//mNumImg 中存着图像和对应的标签,用完记得释放掉内存
}

此外,因为python最近相当火,在这里也放上python读取mnist的代码

import numpy as np
import struct

def loadImageSet(filename):
	print ("load image set",filename)
	binfile= open(filename, 'rb')
	buffers = binfile.read()
	head = struct.unpack_from('>IIII' , buffers ,0)
	print ("head,",head)
	offset = struct.calcsize('>IIII')
	imgNum = head[1]
	width = head[2]
	height = head[3]
	#[60000]*28*28
	bits = imgNum * width * height
	bitsString = '>' + str(bits) + 'B' #读取定长数据段,即字符集图片总和
	imgs = struct.unpack_from(bitsString,buffers,offset)
	binfile.close()
	imgs = np.reshape(imgs,[imgNum,1,width*height])#将字符集图片分隔为单张图片
	print ("load imgs finished")
	return imgs

def loadLabelSet(filename):
	print ("load label set",filename)
	binfile = open(filename, 'rb')
	buffers = binfile.read()
	head = struct.unpack_from('>II' , buffers ,0)
	print ("head,",head)
	imgNum=head[1]
	offset = struct.calcsize('>II')
	numString = '>'+str(imgNum)+"B"
	labels = struct.unpack_from(numString , buffers , offset)
	binfile.close()
	labels = np.reshape(labels,[imgNum,1])
	print ('load label finished')
	return labels
©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页