文件解析的方法与原理

文件的解析使用python的struct模块,接下来会用到的2个方法:

        解包unpack()方法 : 使用该方法可以从写好的二进制文件中读出文件。它的函数原型为:struct.unpack(fmt,string),fmt参数是格式字符串。string表示要转换的python值。最终函数返回一个元组。

        calcsize()方法 : 该方法用于计算格式字符串所对应的结果长度,如:struct.calcsize("ii"),返回8。因为一个i代表一个int类型,占用的长度是4个字节。两个i就是两个int,长度为8个字节。

解析图片文件的核心代码示例如下:

def decode_idx3_ubyte(idx3_file):
     # 读取二进制数据
     with open(idx3_file, 'rb') as file:
         file_data =file.read()
         
    #定义偏移量,初始值为0
     offset = 0
     # 以大端法读取4个 unsinged int32
     file_header = '>iiii'  
     #解析文件头信息,依次为魔数、图片数量、每张图片高、每张图片宽
     magic_number, num_images, num_rows, num_cols = struct.unpack_from(
                                             file_header, file_data, offset)
     #读取完文件头信息后,偏移量向后移动16位
     offset += struct.calcsize(file_header)
     #以图片的像素大小读取图片
     file_image = '>' + str(num_rows * num_cols) + 'B'
     
     #生成和图片数量相同的数组,且每个数组的形状大小等于图片的像素大小
     images = np.empty((num_images, num_rows, num_cols))
      #循环读取每个图片的像素信息
     for i in range(num_images):
        image = struct.unpack_from(file_image, file_data, offset)
        #将读取的图片信息按照规定的形状形成数组
        images[i] = np.array(image).reshape((num_rows, num_cols))
        #每读取完一个图片,偏移量向后移动到下一个图片文件的起始位置
        offset += struct.calcsize(file_image)
     return images

        解析函数通过参数接收到测试集图片文件的路径后,以二进制格式rb打开文件,并读取文件数据。

        定义一个变量offset,代表偏移量,初始值为0。再定义格式符为4个i。然后解析并读取文件头信息,依次获得魔数、图片的数量,每张图片的高度和宽度。读取完后,使用struct.calcsize方法将偏移量向后移动16位。并定义接下来读取图片文件信息的格式符,即784个字节。

        开始读取前,生成和图片数量相同的数组,每个数组的形状大小等于图片的像素大小,以便接下来存储图片。然后循环读取每个图片,并将图片存入数组中。最终将数组返回。

解析图片文件的核心代码示例如下:

def decode_idx1_ubyte(idx1_file):
    #读取二进制数据
    with open(idx1_file, 'rb') as file:
        file_data = file.read()
    #定义偏移量,初始值为0
    offset = 0
    # 以大端法读取4个 unsinged int32
    file_header = '>ii'  
    #解析文件头信息,依次为魔数、标签数
    magic_number, label_num = struct.unpack_from(file_header, 
                                                 file_data, offset)
    #读取完文件头信息后,偏移量向后移动8位
    offset += struct.calcsize(file_header)
    #定义存储标签值的数组
    labels = []
     
    #每次读取一个 byte
    file_label = '>B'
    #循环读取每个标签的信息    
    for i in range(label_num):
        #将读取的标签信息添加到数组中
        labels.append(struct.unpack_from(file_label, file_data, offset)[0])
        #每读取完一个标签,偏移量向后移动一个byte
        offset += struct.calcsize(file_label)
    return labels

        解析标签文件的代码逻辑和解析图片文件的逻辑一致。只是需要注意,解析并读取的标签文件头信息,只有魔数和标签数。且在循环读取标签时,每次读取一个字节。

        解析成功后,会在指定的文件夹下生成相应的文件夹,其中存放了解析后的图片。

完整示例代码如下:

import struct
import numpy as np
import os
import cv2

def decode_idx3_ubyte(idx3_file):
     # 读取二进制数据
     with open(idx3_file, 'rb') as file:
         file_data =file.read()
         
    #定义偏移量,初始值为0
     offset = 0
     # 以大端法读取4个 unsinged int32
     file_header = '>iiii'  
     #解析文件头信息,依次为魔数、图片数量、每张图片高、每张图片宽
     magic_number, num_images, num_rows, num_cols = struct.unpack_from(
                                             file_header, file_data, offset)
     #读取完文件头信息后,偏移量向后移动16位
     offset += struct.calcsize(file_header)
     #以图片的像素大小读取图片
     file_image = '>' + str(num_rows * num_cols) + 'B'
     
     #生成和图片数量相同的数组,且每个数组的形状大小等于图片的像素大小
     images = np.empty((num_images, num_rows, num_cols))
      #循环读取每个图片的像素信息
     for i in range(num_images):
        image = struct.unpack_from(file_image, file_data, offset)
        #将读取的图片信息按照规定的形状形成数组
        images[i] = np.array(image).reshape((num_rows, num_cols))
        #每读取完一个图片,偏移量向后移动到下一个图片文件的起始位置
        offset += struct.calcsize(file_image)
     return images

def decode_idx1_ubyte(idx1_file):
    #读取二进制数据
    with open(idx1_file, 'rb') as file:
        file_data = file.read()
    #定义偏移量,初始值为0
    offset = 0
    # 以大端法读取4个 unsinged int32
    file_header = '>ii'  
    #解析文件头信息,依次为魔数、标签数
    magic_number, label_num = struct.unpack_from(file_header, 
                                                 file_data, offset)
    #读取完文件头信息后,偏移量向后移动8位
    offset += struct.calcsize(file_header)
    #定义存储标签值的数组
    labels = []
     
    #每次读取一个 byte
    file_label = '>B'
    #循环读取每个标签的信息    
    for i in range(label_num):
        #将读取的标签信息添加到数组中
        labels.append(struct.unpack_from(file_label, file_data, offset)[0])
        #每读取完一个标签,偏移量向后移动一个byte
        offset += struct.calcsize(file_label)
    return labels

def check_folder(folder):
    #检查文件文件夹是否存在,不存在则创建
    if not os.path.exists(folder):
        os.mkdir(folder)
        print(folder)
    else:
        if not os.path.isdir(folder):
            os.mkdir(folder)

def export_img(exp_dir, img_ubyte, lable_ubyte):   
    check_folder(exp_dir)
    #生成数据集
    images = decode_idx3_ubyte(img_ubyte)
    labels = decode_idx1_ubyte(lable_ubyte)

    nums = len(labels)
    for i in range(nums):
        img_dir = os.path.join(exp_dir, str(labels[i]))
        check_folder(img_dir)
        img_file = os.path.join(img_dir, str(i)+'.png')
        imarry = images[i]
        cv2.imwrite(img_file, imarry)

def parser_mnist(file_dir):
    #在指定的路径下,创建一个文件夹“train”,用于保存解析后的图片和标签
    train_dir = os.path.join(file_dir, 'train')
    #获得训练集图片文件的路径
    train_img_ubyte = os.path.join(file_dir, 'train-images.idx3-ubyte')
    #获得训练集标签文件的路径
    train_label_ubyte = os.path.join(file_dir, 'train-labels.idx1-ubyte')
    export_img(train_dir, train_img_ubyte, train_label_ubyte)

    #在指定的路径下,创建一个文件夹“test”,,用于保存解析后的图片和标签
    test_dir = os.path.join(file_dir, 'test')
    #获得测试集图片文件的路径
    test_img_ubyte = os.path.join(file_dir, 't10k-images.idx3-ubyte')
    #获得测试集标签文件的路径
    test_label_ubyte = os.path.join(file_dir, 't10k-labels.idx1-ubyte')
    export_img(test_dir, test_img_ubyte, test_label_ubyte)

if __name__ == '__main__':
    file_dir = 'D:/MNIST_Download/unzip'
    parser_mnist(file_dir)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值