读取MNIST数据集并保存为图片

这篇博客介绍了MNIST手写数字数据集,包括其组成、文件格式和读取方法。通过Python的open()函数以二进制模式读取数据,结合int.from_bytes()和struct.unpack()函数进行数据转换,将数据集中的图像保存为图片。
部署运行你感兴趣的模型镜像


MNIST数据集简介

MNIST是一个手写数字的数据库,它由一个包含有60000个样本的训练集和一个包含有10000个样本的测试集组成。数据集中所有的手写数字都已经被标准化,并且以固定大小的图像形式保存。
完整数据集可从MNIST数据集的官网THE MNIST DATABASE of handwritten digits上进行下载。
下载完成后,解压即可得到我们所需的数据集。

MNIST数据集文件格式

数据集用字节形式进行存储,采用MSB(Most Significant Bit) first模式,即大端模式。
MNIST数据集由四个文件组成:

文件名说明
train-images-idx3-ubyte训练集图片
train-labels-idx1-ubyte训练集标签
t10k-images-idx3-ubyte测试集图片
t10k-labels-idx1-ubyte测试集标签

train-images-idx3-ubyte

字节偏移量数据类型数值说明
000032 bit integer0x00000803(2051)魔数
000432 bit integer60000图片数量
000832 bit integer28图片像素的行数(row)
001232 bit integer28图片像素的列数(column)
0016unsigned byte??像素的值
0017unsigned byte??像素的值
xxxxunsigned byte??像素的值

像素按行排列。 像素值为0到255。0表示背景(白色),255表示前景(黑色)。

train-labels-idx1-ubyte

字节偏移量数据类型数值说明
000032 bit integer0x00000801(2049)魔数 (MSB first)
000432 bit integer60000标签数量
0008unsigned byte??标签值
0009unsigned byte??标签值
xxxxunsigned byte??标签值

标签的值为0到9的整数。

t10k-images-idx3-ubyte

字节偏移量数据类型数值说明
000032 bit integer0x00000803(2051)魔数
000432 bit integer10000图片数量
000832 bit integer28图片像素的行数(row)
001232 bit integer28图片像素的列数(column)
0016unsigned byte??像素的值
0017unsigned byte??像素的值
xxxxunsigned byte??像素的值

像素按行排列。 像素值为0到255。0表示背景(白色),255表示前景(黑色)。

t10k-labels-idx1-ubyte

字节偏移量数据类型数值说明
000032 bit integer0x00000801(2049)魔数 (MSB first)
000432 bit integer10000标签数量
0008unsigned byte??标签值
0009unsigned byte??标签值
xxxxunsigned byte??标签值

标签的值为0到9的整数。

读取方法

open() 函数

文件以二进制格式进行存储,我们同样的也就需要用二进制格式进行读取。所以我们在使用Python的open()函数时,需指明模式为rb,即以二进制格式打开一个文件用于只读。

f = open(file_name, "rb")

open()将打开一个文件,创建一个file对象,这时调用相关方法便可以对文件进行读写。

file.read(size)

size指定了需要读取的字符数或字节数,若未指定,则返回整个文件,如果文件大小大于 倍内存则有问题,file.read(size)读到文件尾时返回""(空字串)。

file.close()

关闭文件是个好习惯。

int.from_bytes() 函数

我们直接读取到数据的类型为bytes,并不是我们所希望的数据类型,因此需要进行转换。由于所有的数都是整数,所以我们可以直接用int.from_bytes()完成。

res = int.from_bytes(s, byteorder="big", signed=False)

s为需要转换的数。
byteorder指定了为大端模式"big"或者小端模式"little"
signed表示是否要区分二进制的正负数含义。

struct.unpack() 函数

struct.unpack()也能完成将字节流转换为Python指定的数据类型的操作。

推荐博客:python之struct详解

完整代码

import os
import cv2
import numpy as np

TRAIN_IMAGES_DIR = "train_images/"
TEST_IMAGES_DIR = "test_images/"

TRAIN_IMAGE_DATASET_PATH = "train-images.idx3-ubyte"
TRAIN_LABEL_DATASET_PATH = "train-labels.idx1-ubyte"
TEST_IMAGE_DATASET_PATH = "t10k-images.idx3-ubyte"
TEST_LABEL_DATASET_PATH = "t10k-labels.idx1-ubyte"


def convert_to_image(dataset_type):
    if dataset_type == "train":
        images_dir = TRAIN_IMAGES_DIR
        image_dataset = open(TRAIN_IMAGE_DATASET_PATH, "rb")
        label_dataset = open(TRAIN_LABEL_DATASET_PATH, "rb")
    elif dataset_type == "test":
        images_dir = TEST_IMAGES_DIR
        image_dataset = open(TEST_IMAGE_DATASET_PATH, "rb")
        label_dataset = open(TEST_LABEL_DATASET_PATH, "rb")
    else:
        print("Invalid type.")
        return

    counter = [0] * 10

    image_magic_number = int.from_bytes(image_dataset.read(4), byteorder='big', signed=False)
    image_num = int.from_bytes(image_dataset.read(4), byteorder='big', signed=False)
    image_row = int.from_bytes(image_dataset.read(4), byteorder='big', signed=False)
    image_col = int.from_bytes(image_dataset.read(4), byteorder='big', signed=False)

    label_magic_number = int.from_bytes(label_dataset.read(4), byteorder='big', signed=False)
    label_num = int.from_bytes(label_dataset.read(4), byteorder='big', signed=False)

    for i in range(10):
        if not os.path.exists(images_dir + str(i)):
            os.makedirs(images_dir + str(i))

    for i in range(image_num):
        image = []
        for j in range(image_row * image_col):
            image.append(int.from_bytes(image_dataset.read(1), byteorder='big', signed=False))

        image = np.array(image, dtype=np.uint8).reshape((image_row, image_col))

        label = int.from_bytes(label_dataset.read(1), byteorder='big', signed=False)

        counter[label] += 1

        image_path = images_dir + str(label) + "/" + str(label) + "." + str(counter[label]) + ".jpg"

        cv2.imwrite(image_path, image)

        if (i + 1) % 1000 == 0:
            print("Running, " + dataset_type + " images: " + str(i + 1) + "/" + str(image_num))

        # cv2.imshow('image', image)
        # cv2.waitKey(0)
        # cv2.destroyAllWindows()
    image_dataset.close()
    label_dataset.close()

    print(dataset_type + " dataset finished.")


if __name__ == "__main__":
    convert_to_image("train")
    convert_to_image("test")
    print("All finished.")

您可能感兴趣的与本文相关的镜像

Python3.9

Python3.9

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值