CASIA手写体数据集HWDB1.0 gnt和dgrl格式解析

本文档介绍了如何解析CASIA手写体数据库中的GNT和DGRL文件格式。提供了一个修复后的Python3代码示例,用于读取和处理这些文件,包括将GNT文件转换为PNG图像和TXT标签文件,以及解析DGRL文件并保存其标签和图像数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言
  • 最近用到了CASIA这个手写体数据集,但是HWDB1.0~1.2系列其存储格式为gnt
  • 虽说官网也给了读取方式,但是仍然具有一定门槛
  • 于是上网搜了解析gnt格式的python代码,找到了CASIA中文手写体字库gnt文件格式解析(python)
  • 这篇博客代码是2014年用python2写的,有些年久失修,正好顺手修复一下,改为了python3的
Gnt格式解析代码
# !/usr/bin/env python
# -*- encoding: utf-8 -*-
# @File: data_process.py
# @Author: SWHL
# @Contact: liekkaskono@163.com
import struct
from pathlib import Path

from PIL import Image


def write_txt(save_path: str, content: list, mode='w'):
    """
    将list内容写入txt中
    @param
    content: list格式内容
    save_path: 绝对路径str
    @return:None
    """
    with open(save_path, mode, encoding='utf-8') as f:
        for value in content:
            f.write(value + '\n')


path = 'raw_data'
save_dir = 'HWDB1'  # 目录下均为gnt文件

gnt_paths = list(Path(path).iterdir())

label_list = []
for gnt_path in gnt_paths:
    count = 0
    print(gnt_path)
    with open(str(gnt_path), 'rb') as f:
        while f.read(1) != "":
            f.seek(-1, 1)
            count += 1
            try:
                # 只所以添加try,是因为有时f.read会报错 struct.error: unpack requires a buffer of 4 bytes
                # 原因尚未找到
                length_bytes = struct.unpack('<I', f.read(4))[0]

                tag_code = f.read(2)

                width = struct.unpack('<H', f.read(2))[0]

                height = struct.unpack('<H', f.read(2))[0]

                im = Image.new('RGB', (width, height))
                img_array = im.load()
                for x in range(height):
                    for y in range(width):
                        pixel = struct.unpack('<B', f.read(1))[0]
                        img_array[y, x] = (pixel, pixel, pixel)

                filename = str(count) + '.png'
                tag_code = tag_code.decode('gbk').strip('\x00')
                save_path = f'{save_dir}/images/{gnt_path.stem}'
                if not Path(save_path).exists():
                    Path(save_path).mkdir(parents=True, exist_ok=True)
                im.save(f'{save_path}/{filename}')

                label_list.append(f'{gnt_path.stem}/{filename}\t{tag_code}')
            except:
                break

write_txt(f'{save_dir}/gt.txt', label_list)

dgrl格式解析代码
# !/usr/bin/env python
# -*- encoding: utf-8 -*-
# @Author: SWHL
# @Contact: liekkaskono@163.com
import os
import struct
from pathlib import Path

import cv2 as cv
import numpy as np
from tqdm import tqdm


def read_from_dgrl(dgrl):
    if not os.path.exists(dgrl):
        print('DGRL not exis!')
        return

    dir_name, base_name = os.path.split(dgrl)
    label_dir = dir_name+'_label'
    image_dir = dir_name+'_images'
    if not os.path.exists(label_dir):
        os.makedirs(label_dir)
    if not os.path.exists(image_dir):
        os.makedirs(image_dir)

    with open(dgrl, 'rb') as f:
        # 读取表头尺寸
        header_size = np.fromfile(f, dtype='uint8', count=4)
        header_size = sum([j << (i*8) for i, j in enumerate(header_size)])
        # print(header_size)

        # 读取表头剩下内容,提取 code_length
        header = np.fromfile(f, dtype='uint8', count=header_size-4)
        code_length = sum([j << (i*8) for i, j in enumerate(header[-4:-2])])
        # print(code_length)

        # 读取图像尺寸信息,提取图像中行数量
        image_record = np.fromfile(f, dtype='uint8', count=12)
        height = sum([j << (i*8) for i, j in enumerate(image_record[:4])])
        width = sum([j << (i*8) for i, j in enumerate(image_record[4:8])])
        line_num = sum([j << (i*8) for i, j in enumerate(image_record[8:])])
        print('图像尺寸:')
        print(height, width, line_num)

        # 读取每一行的信息
        for k in range(line_num):
            print(k+1)

            # 读取该行的字符数量
            char_num = np.fromfile(f, dtype='uint8', count=4)
            char_num = sum([j << (i*8) for i, j in enumerate(char_num)])
            print('字符数量:', char_num)

            # 读取该行的标注信息
            label = np.fromfile(f, dtype='uint8', count=code_length*char_num)
            label = [label[i] << (8*(i % code_length))
                     for i in range(code_length*char_num)]
            label = [sum(label[i*code_length:(i+1)*code_length])
                     for i in range(char_num)]
            label = [struct.pack('I', i).decode(
                'gbk', 'ignore')[0] for i in label]
            print('合并前:', label)
            label = ''.join(label)
            # 去掉不可见字符 \x00,这一步不加的话后面保存的内容会出现看不见的问题
            label = ''.join(label.split(b'\x00'.decode()))
            print('合并后:', label)

            # 读取该行的位置和尺寸
            pos_size = np.fromfile(f, dtype='uint8', count=16)
            y = sum([j << (i*8) for i, j in enumerate(pos_size[:4])])
            x = sum([j << (i*8) for i, j in enumerate(pos_size[4:8])])
            h = sum([j << (i*8) for i, j in enumerate(pos_size[8:12])])
            w = sum([j << (i*8) for i, j in enumerate(pos_size[12:])])
            # print(x, y, w, h)

            # 读取该行的图片
            bitmap = np.fromfile(f, dtype='uint8', count=h*w)
            bitmap = np.array(bitmap).reshape(h, w)

            # 保存信息
            label_file = os.path.join(
                label_dir, base_name.replace('.dgrl', '_'+str(k)+'.txt'))
            with open(label_file, 'w') as f1:
                f1.write(label)
            bitmap_file = os.path.join(
                image_dir, base_name.replace('.dgrl', '_'+str(k)+'.jpg'))
            cv.imwrite(bitmap_file, bitmap)


if __name__ == '__main__':
    dgrl_paths = Path('dataset/HandWriteDBRecog/HWDB2.2Train').iterdir()
    dgrl_paths = list(dgrl_paths)
    for dgrl_path in tqdm(dgrl_paths):
        read_from_dgrl(dgrl_path)

相关资料
HWDB2.0-2.2 是一个广泛使用的手写汉字文本识别数据集,其中 HWDB2.0 版本是该系列的起始版本之一。该数据集由多个版本的训练集测试集组成,每个版本均包含多个 DGRL 文件,每个 DGRL 文件中包含多个手写文本行[^1]。这些文件格式是专门为手写识别任务设计的,通常包含了图像数据及其对应的文本标签信息。 HWDB2.0 中包含了大约 37,000 个不同的汉字,适用于训练测试手写识别模型,尤其是针对中文场景下的识别任务。该数据集的一个显著特点是其规模随着版本更新而逐步扩大,例如 HWDB2.1 包含了约 45,000 个汉字,而 HWDB2.2 则扩展到了约 52,000 个汉字[^1]。这种逐步扩展的特性使得研究者可以根据实际需求选择合适规模的数据集进行实验。 在数据采集方式上,HWDB 系列数据集CASIA-HWDB CASIA-OLHWDB 数据库具有相似之处,它们均由中科院自动化研究所于 2007 至 2010 年间收集[^2]。这些数据集均采用了 Anoto 笔在点阵纸上书写后扫描、分割的方式获取手写样本,从而确保了数据的真实性多样性。HWDB2.0 及其后续版本继承了这一高质量的数据采集标准,进一步提升了数据集的实用价值。 HWDB2.0 数据集的典型用途包括但不限于: - **训练深度学习模型**:用于构建基于卷积神经网络(CNN)、循环神经网络(RNN)或 Transformer 的手写识别系统。 - **文本行识别评估**:由于数据集中包含多个文本行,因此非常适合用于评估模型在实际书写场景中的表现。 - **跨版本迁移学习研究**:由于 HWDB2.0、2.1 2.2 版本之间存在汉字数量的差异,研究者可以利用这些版本进行迁移学习或增量学习的实验。 若需获取 HWDB2.0 DGRL 数据集,通常需要通过相关学术机构或数据集发布平台进行申请,部分数据集可能需要签署使用协议以确保其用于非商业目的。 ### 数据格式说明 DGRL 文件是一种结构化的二进制文件格式,通常包含以下信息: - 手写图像的像素数据 - 对应的文本标签 - 书写者的 ID - 书写时间戳 - 其他元数据(如书写设备信息等) 处理 DGRL 文件通常需要专门的解析工具或脚本,部分研究团队会提供读取 DGRL 文件的 Python 或 MATLAB 示例代码。 ### 示例代码:读取 DGRL 文件(Python) ```python import struct def read_dgrl_file(file_path): with open(file_path, 'rb') as f: while True: # 读取样本长度 len_data = f.read(4) if not len_data: break sample_length = struct.unpack('I', len_data)[0] # 读取样本数据 sample_data = f.read(sample_length) # 解析 sample_data(具体结构取决于 DGRL 的定义) # ... yield sample_data ```
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值