CASIA简介
CASIA是一个非常有价值的手写单字数据集。它涵盖了众多的汉字以及字母、数字和符号。由中科院自动化研究所在 2007-2010 年间收集;包含1020人书写的脱机(联机)手写中文单字样本和手写文本;联机数据是采用 Anoto 笔在点阵纸上书写后扫描、分割得到。主要由离线(HWDB)和在线(OLHWDB)两部分。
具体可以前往官网了解:https://nlpr.ia.ac.cn/databases/handwriting/Home.html
这里只介绍在线手写数据集部分,离线的网上介绍比较多。在线手写数据集单字主要包括OLHWDB1.0 与 OLHWDB1.2。一共收录汉字 7185 个,涵盖了 GB2312 中全部 6763 个汉字。这个数据集以.pot
文件存储,其数据组织形式独特。这些版本的数据集可以用于训练和测试在线手写汉字识别模型。CASIA - OLHWDB 为手写汉字识别、字形分析等相关任务提供了丰富的数据资源。
pot文件的解析
pot文件的解析相关教程并不多,官网也只给出了文件头信息,和一个预览的软件。
我这里按照文件头规则直接写了一版python的,会将在线的点集转换为json文件存储,方便后期使用,文件夹的命名使用的是这个汉字字符对应的md5编码,当然你也可以修改为其他的,解析时间很长,因为一个字符大概有100多个样本。
import hashlib
import json
import os
import struct
def parse_pot_file(filename):
with open(filename, 'rb') as f:
while True:
# 读取样本大小
sample_size_data = f.read(2)
if not sample_size_data:
break # 文件读取结束
sample_size = struct.unpack('<H', sample_size_data)[0]
# 读取字符的 GBK 编码
tag_code_data = f.read(4)
tag_code = struct.unpack('<I', tag_code_data)[0]
gbk_code = tag_code & 0xFFFF # 提取低16位
character = gbk_code.to_bytes(2, 'big').decode('gbk', errors='ignore').strip('\x00')
# print(f"Character: {character}")
# c.append(character)
# 读取笔画数量
stroke_count_data = f.read(2)
stroke_count = struct.unpack('<H', stroke_count_data)[0]
# print(f"Number of strokes: {stroke_count}")
# 读取每个笔画
strokes = []
for _ in range(stroke_count):
stroke = []
while True:
# 读取一个坐标对
x, y = struct.unpack('<hh', f.read(4))
if (x, y) == (-1, 0): # 笔画结束标志
break
stroke.append((x, y))
strokes.append(stroke)
# 将字符编码为md5
md5_hash = hashlib.md5(character.encode('utf-8')).hexdigest()
# 创建以MD5为名的文件夹
folder_path = os.path.join(output_dir, md5_hash)
os.makedirs(folder_path, exist_ok=True)
# 计算已有文件数量,确定当前文件名
existing_files = os.listdir(folder_path)
json_filename = f"{len(existing_files) + 1}.json"
# 将strokes保存为JSON文件
json_file_path = os.path.join(folder_path, json_filename)
with open(json_file_path, 'w', encoding='utf-8') as json_file:
json.dump(strokes, json_file, ensure_ascii=False, separators=(',', ':'))
# print(f"Strokes: {strokes}")
# 检查字符结束标志 (-1, -1)
end_marker = struct.unpack('<hh', f.read(4))
if end_marker != (-1, -1):
raise ValueError("Invalid character end marker.")
output_dir = 'D:\\VeenCode\\MyCode\\DataSet\\OLHWDB\\PotTrainJson'
input_dir = 'D:\\VeenCode\\MyCode\\DataSet\\OLHWDB\\Pot1.0Train'
# 遍历文件夹中的所有 .pot 文件
for root, _, files in os.walk(input_dir):
for file in files:
if file.endswith('.pot'):
file_path = os.path.join(root, file)
parse_pot_file(file_path)
print(os.path.join(root, file))
文件夹Pot1.0Train
用来存放全部pot文件,会将结果输出到PotTrainJson
文件夹。
结果预览
将pot转换成json后,处理起来就方便太多了,随机来一首诗预览一下字符:
下面是预览的代码,大家也可以拿去玩玩,使用了Tk库,在canvas上绘制的:
import hashlib
import json
import tkinter as tk
import os
import random
# 读取JSON文件并解析数据
def load_json(file_path):
with open(file_path, 'r') as file:
data = json.load(file)
return data
# 归一化点的坐标,放缩到90x90区域并居中
def normalize_data(strokes, offset_x, offset_y, word_size=90, box_size=100):
# 获取所有点的最大值和最小值,以便归一化
all_x = [point[0] for stroke in strokes for point in stroke]
all_y = [point[1] for stroke in strokes for point in stroke]
min_x, max_x = min(all_x), max(all_x)
min_y, max_y = min(all_y), max(all_y)
# 归一化到90x90的绘制区域
scale_x = word_size / (max_x - min_x) if max_x - min_x != 0 else 1
scale_y = word_size / (max_y - min_y) if max_y - min_y != 0 else 1
# 计算居中的偏移量
center_x_offset = (box_size - word_size) / 2
center_y_offset = (box_size - word_size) / 2
normalized_strokes = []
for stroke in strokes:
normalized_stroke = []
for x, y in stroke:
norm_x = (x - min_x) * scale_x + offset_x + center_x_offset
norm_y = (y - min_y) * scale_y + offset_y + center_y_offset
normalized_stroke.append((norm_x, norm_y))
normalized_strokes.append(normalized_stroke)
return normalized_strokes
# 在canvas上绘制笔画
def draw_strokes(canvas, strokes):
for i, stroke in enumerate(strokes):
color = "red" if i == 0 else "black"
for j in range(len(stroke) - 1):
x1, y1 = stroke[j]
x2, y2 = stroke[j + 1]
canvas.create_line(x1, y1, x2, y2, fill=color, width=2)
# 主函数:随机挑选10个JSON文件并渲染到画布上
def main(selected_files):
# Canvas的大小设置为500x500
canvas_width = 500
canvas_height = 500
box_size = 100 # 每个字的框大小为100x100
word_size = 50 # 字的大小为90x90
# 创建Tkinter窗口和Canvas
root = tk.Tk()
root.title("Drawing Random Strokes")
canvas = tk.Canvas(root, width=canvas_width, height=canvas_height)
canvas.pack()
# 按照5列2行的顺序排列和绘制笔画
num_cols = 5
for index, file_name in enumerate(selected_files):
# 计算子区域的左上角的坐标
col = index % num_cols
row = index // num_cols
offset_x = col * box_size
offset_y = row * box_size
# 加载和归一化数据
strokes = load_json(os.path.join(folder_path, file_name))
normalized_strokes = normalize_data(strokes, offset_x, offset_y, word_size, box_size)
# 在子区域内绘制笔画
draw_strokes(canvas, normalized_strokes)
# 运行Tkinter主循环
root.mainloop()
# 示例调用
if __name__ == "__main__":
# 给定字符
chars = "白日依山尽黄河入海流欲穷千里目更上一层楼"
json_path = []
# 遍历字符并生成对应的JSON文件路径
for char in chars:
# 将字符md5加密
char_md5 = hashlib.md5(char.encode()).hexdigest()
folder_path = os.path.join(r"D:\VeenCode\MyCode\DataSet\OLHWDB\PotTrainJson", char_md5)
# 随机从folder_path文件夹中挑选一个json文件
json_files = [f for f in os.listdir(folder_path) if f.endswith('.json')]
json_file = random.choice(json_files)
json_path.append(os.path.join(folder_path, json_file))
main(json_path)
站点介绍:记录所学知识,缩短和大神的差距!
站点图标:https://res.liuyuyang.net/usr/images/avatar.jpg
站点地址:https://liuyuyang.net/
描 述:什么都懂一点点皮毛
链 接:https://blog.qsuu.cn
头 像:https://cdn.qsuu.cn/2024/02/25/65daa884f34be.jpg
已添加贵站信息