mnist数据集格式转换---机器学习(0)

来源:互联网 发布:mysql约束 编辑:程序博客网 时间:2024/06/06 22:14

  之前一直在用caffe跑深度学习的东西,虽然经过了无数的挫折跑通了一些,但终究是“纸上得来终觉浅”,还是从头自己搞一下的好。

  于是从本篇开始,将放出本人用C++一步一步实现图像上的机器学习的代码和体会。

  由于已经有开源库进行了支持,因此这份代码的目的并非为了实用,而只是本人的练手之做,其主要着眼于简单、详细和易懂,不太考虑性能方面的问题。

  既然要自己实现,那么第一步总是要有学习素材的,本人选择的是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);}

  解析出来的图像标签如下:

这里写图片描述

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