手写识别数据集.pot文件解析:从笔迹坐标到深度学习训练样本

做中文手写识别,不管你是研究路线,还是已经被业务需求按着头写代码,大概率都会碰到 CASIA OLHWDB 这个名字。数据集虽好,.pot 这套文件格式对新人极其不友好——它不是图片,不是 JSON,不是官方给好读接口的数据库,打开编辑器全是“看不懂的字符”。我能理解那种状态:模型一跑就缺数据,数据明明就在服务器上,但解析脚本却还没着落,人先卡住了。

这篇文章就是把你从“卡住”拉到“能动手”的过渡。我把自己解析 .pot 文件时踩过的坑、最后稳定使用的一套流程全部写出来,代码也会给你,可以直接复制下来跑。适合正在拿 OLHWDB 训练手写识别模型的人、做老系统数据迁移的人,以及任何想从原始笔迹数据里提取坐标点给深度学习模型用的开发者。先说一下结论: .pot 文件本质是文本格式,但其中中文标签的编码、笔段坐标的表示、样本之间的分隔符,都会因为数据版本不同而有细微差异。读完下面这套流程,你至少能在 30 分钟内产出一个能用的解析器,并且不踩我当初那些坑。

1. 别急着写代码:先搞清楚 .pot 文件在整个数据集里的角色

1.1 在线数据和离线数据并不是一回事

OLHWDB 家族里,数据分成“在线”和“离线”两类。离线数据是最直观的:一张张已经写好的汉字图片,你丢给 CNN 或者 OCR 模型直接训练就行。在线数据则不同,它记录的是“这一笔是怎么写出来的”,也就是原始笔迹轨迹。

类比一下你就懂了:离线数据是作文纸上的字,而在线数据是那只笔在纸上从落到抬的所有运动轨迹点。每个轨迹点通常包含 x 坐标、y 坐标,以及时间戳或压力值。 .pot 文件,就是存放这些轨迹点的主要后缀之一。

解析 .pot 文件的最终目标,就是把这一串原始点还原成一段一段的笔画(stroke),再把所有笔画还原成一个又一个字符样本(sample)。后续不管是可视化、生成图像,还是转成序列数据输入 RNN、Transformer,都建立在这一层还原之上。如果这一步做错了,后面所有训练数据都是错位的。

1.2 先观察,再写解析器

拿到一个 .pot 文件,我建议你先别急着在网上下载现成脚本。先花两分钟搞清楚你自己手里这份文件长什么样。马上在命令行里敲:

file sample.pot xxd sample.pot | head -n 30 strings sample.pot | head -n 30

这三个命令的输出,能回答三个问题:文件是纯文本还是二进制?里面能不能看到可读字符串?中文标签有没有可能出现?如果xxd显示一长串连续的 16 进制字节,那你的 pot 可能是二进制变体;如果能看到#、CASIA、SAMPLE这种关键词,那么基本可以确定格式偏向于按行组织的文本。

我实际处理过的 OLHWDB 在线数据大多是文本格式,这也是后面解析思路能一直复用的基础。但不同版本身上的字段分隔符确实有差别,别默认自己手里的一定和网上某个教程一致。最好的办法,就是先把文件的“肉眼结构”看清楚,再决定正则和读取方式。

2. 文件内部拆解:从字符串到结构化样本的四层结构

2.1 头部信息行

文本型 .pot 文件开头一般是若干行元信息,行首最常见的记号是#或者CASIA-OLHWDB这样的数据集声明。我在不同版本的样本里见过这些字段:#File、#DB、#Writer、#Samples、#Pen。它们的作用主要是说明来源,解析时可以直接跳过,但建议不要无脑丢,因为像#DB能告诉你当前这个文件到底是哪个版本,方便你在代码里做分支。

注意一个很容易踩的坑:头部信息行并不总是真的“注释”。有些文件里会有一行#LabelType: GBK之类的东西,它其实是在告诉你后面文本的编码方式。如果你忽略这一行,直接按 UTF-8 去解码后面的中文标签,大概率会看到一堆乱码。正确做法是把头部行里的字段读取出来,而不是简单当作注释丢弃。

2.2 样本级记录

头部之后,就是一个一个样本记录。一个样本通常对应“一个汉字”或者“一个手写文本行”。区分两个样本的最好标志,是样本起始标记。常见形式有#Sample: 12、#Char: 中、#Strokes: 3这种连续多行描述。

我可以给你一个我在实际样本中见过的简化结构,方便你建立直觉:

#Sample: 0 #Char: 中 #StrokeNum: 3 112,311 114,308 118,302 96,411 97,412 98,410 150,500 152,498 155,495

先把这种结构记住:第一行是样本编号,第二行是字符标签,第三行是笔画数量,后面紧跟着的就是每个笔画的数据行。

2.3 笔画数据行

每个笔画数据行,是一组点坐标。坐标点之间通常用空格分隔,x 和 y 之间用逗号分隔。有些格式会在点后面再加一个时间戳,比如:

112,311,34 114,308,87 118,302,122

这里第三个数字是相对时间戳。注意,时间戳不是每个版本的标配。有的会有压力值,有的会多一个按钮状态标记。解析时最稳妥的办法,不是固定写死“三个数字”,而是把每个点拆分后判断长度:只有两个数字就补默认时间戳 0,三个数字就把第三个当作时间戳,四个数字再尝试解析成压力值。这样做的好处是,同一套解析代码能应对更多老数据。

2.4 先确保你不被分隔符坑死

文本格式的 pot 有一个让人头痛的地方:分隔符不统一。有的样本之间用空行分隔,有的用#开头的行分隔,有的直接在笔画数据后面紧跟下一个#Sample。我建议在写正则前,先用字符串操作把整个文件拆成一个列表,再逐行标记状态。这个做法比全文件正则匹配更稳,因为你的代码不会因为某个样本里多了一个空行就崩掉。

3. 完整解析代码:从原始文本到干净的样本对象

下面这套代码是我现在重建基准数据时会直接用的版本,已经处理过编码、样本分隔和笔画拆分三个核心问题。整体结构是“逐行扫描”,而不是一次性正则匹配整个文件,原因后面会解释。

import re from dataclasses import dataclass, field from typing import List, Iterator, Optional @dataclass class Point: x: int y: int t: int = 0 @dataclass class Stroke: points: List[Point] = field(default_factory=list) @dataclass class POTSample: sample_id: int = 0 label: str = "" strokes: List[Stroke] = field(default_factory=list) def decode_pot_bytes(raw: bytes) -> str: for enc in ("utf-8", "gb18030", "gbk"): try: return raw.decode(enc) except UnicodeDecodeError: continue return raw.decode("utf-8", errors="replace") def parse_point_tokens(token: str) -> Optional[Point]: nums = token.replace(",", " ").split() if len(nums) < 2: return None try: x = int(nums[0]) y = int(nums[1]) t = int(nums[2]) if len(nums) >= 3 else 0 return Point(x, y, t) except ValueError: return None def parse_pot_text(text: str) -> List[POTSample]: samples: List[POTSample] = [] cur: Optional[POTSample] = None pending_strokes: Optional[int] = None for raw_line in text.splitlines(): line = raw_line.strip() if not line: continue # 样本起始标记,兼容多种写法 sample_match = re.match(r"^#(?:Sample|S)\s*[:#]?\s*(\d+)", line) if sample_match: if cur is not None: samples.append(cur) cur = POTSample(sample_id=int(sample_match.group(1))) pending_strokes = None continue # 标签行 label_match = re.match(r"^#(?:Char|Character|Label)\s*[:#]?\s*(.*)", line) if label_match and cur is not None: cur.label = label_match.group(1).strip() continue # 笔画数量行 stroke_match = re.match(r"^#(?:StrokeNum|Strokes|Stroke)\s*[:#]?\s*(\d+)", line) if stroke_match and cur is not None: pending_strokes = int(stroke_match.group(1)) cur.strokes = [] continue # 头部元信息,直接跳过 if line.startswith("#") or line.startswith("CASIA"): continue # 如果确认进入笔画阶段,这行应该是坐标点行 if cur is not None and pending_strokes is not None and len(cur.strokes) < pending_strokes: stroke = Stroke() for token in re.split(r"[\s;]+", line): pt = parse_point_tokens(token) if pt is not None: stroke.points.append(pt) # 防止空行被误判为空笔画 if stroke.points: cur.strokes.append(stroke) if cur is not None: samples.append(cur) return samples def read_pot_file(path: str) -> List[POTSample]: with open(path, "rb") as f: raw = f.read() text = decode_pot_bytes(raw) return parse_pot_text(text)

这段代码核心思路是“状态机式解析”:当前有没有一个正在累积的样本、还差几个笔画没读、下一行是不是坐标行。你不需要一次性判断整个文件的格式,只需要知道此刻处在什么状态。这样遇到各种小的变体都不容易崩。

使用方式很简单:

samples = read_pot_file("/path/to/sample.pot") for sample in samples[:5]: print(sample.sample_id, sample.label, len(sample.strokes))

如果样本里有大量数据,打印前几个就够了。配合一个.pot文件,你很快能看到类似这样的输出:

0 中 3 1 国 2 2 人 4

这里要特别提醒一句:上面这个解析器是按照我个人整理的常见版本来写的,不能保证覆盖所有 OLHWDB 镜像里的奇怪变体。拿到新文件时,先打印前 100 行,观察有没有你没见过的分隔方式,再微调正则。

4. 解析到的坐标要怎么变成机器学习能用的数据

4.1 编码陷阱与中文标签

这是 .pot 解析里最磨人的一块。不少中文样本文件的标签不是 UTF-8,而是 GBK 或 GB18030 编码。如果你直接打开就是乱码,不要怀疑自己眼睛,先做一件事:把解码顺序从 UTF-8 改成 GB18030。所以上面代码我特意写了decode_pot_bytes函数,采用尝试解码的方式:先用 UTF-8 解,解不开就转 GB18030。这个顺序能覆盖绝大多数文件。

GB18030 不是生僻的怪编码,它是 GBK 的超集,基本把简体中文里所有常用字符都覆盖了。我的经验是:在处理老版本中文笔迹数据时,GB18030 的容错率比 UTF-8 高得多。前提是你别忘了在最后一步用errors="replace"兜底,防止样本里出现个别异常字节导致整个解析器抛异常。

4.2 坐标归一化:别让原始坐标骗了你

OLHWDB 的在线笔迹坐标,来自数位板或者专门的采集设备。这些坐标往往是绝对坐标,数值范围可能是 0 到几万。如果你直接把原始坐标丢给模型,模型第一眼看到的就是一个极度倾斜的特征空间。训练还没开始,梯度方向就已经被你自己的数据搞乱了。

正确的做法是做归一化。最简单也最常用的是“最小最大缩放”:

def normalize_points(sample: POTSample, target_size: int = 128) -> List[Stroke]: all_x = [p.x for st in sample.strokes for p in st.points] all_y = [p.y for st in sample.strokes for p in st.points] min_x, max_x = min(all_x), max(all_x) min_y, max_y = min(all_y), max(all_y) range_x = max_x - min_x range_y = max_y - min_y scale = min(target_size / range_x, target_size / range_y) if range_x and range_y else 1.0 new_strokes = [] for st in sample.strokes: new_pts = [] for p in st.points: nx = int((p.x - min_x) * scale) ny = int((p.y - min_y) * scale) new_pts.append(Point(nx, ny, p.t)) new_strokes.append(Stroke(new_pts)) return new_strokes

这里scale = target_size / max(range_x, range_y)也是一种做法,但如果还要保留笔迹的原始比例,用min而不是max更合适,因为这样长边不超过目标尺寸,短边会被压缩到目标尺寸以下,留出一侧空白。具体用哪个,取决于你的任务是“整图输入分类”还是“序列建模”。别在这上面过度纠结,先跑通,后期用验证集对比结果再调整。

4.3 用 PIL 把笔画渲染成图像

很多 OCR 和手写识别任务,最后还是要落到像素级输入。把归一化后的笔画渲染成灰度图,是一个高频需求。用 PIL 就能干,不需要引入额外图形库:

from PIL import Image, ImageDraw def render_sample(sample: POTSample, size: int = 128, margin: int = 4) -> Image.Image: all_x = [p.x for st in sample.strokes for p in st.points] all_y = [p.y for st in sample.strokes for p in st.points] min_x, max_x = min(all_x), max(all_x) min_y, max_y = min(all_y), max(all_y) span = max(max_x - min_x, max_y - min_y, 1) scale = (size - 2 * margin) / span img = Image.new("L", (size, size), 255) draw = ImageDraw.Draw(img) for st in sample.strokes: pts = [ (int((p.x - min_x) * scale + margin), int((p.y - min_y) * scale + margin)) for p in st.points ] if len(pts) == 1: draw.point(pts[0], fill=0) elif len(pts) >= 2: draw.line(pts, fill=0, width=2, joint="curve") return img

joint="curve"是我后来才注意的一个细节。默认的line在坐标点非常密集时,笔画连接处会显得生硬,曲线式连接能让渲染出的汉字看起来更圆润,接近真实书写过程。模型喂这种图,比喂那些有大量锯齿的图收敛更快。

4.4 写个 Dataset 接入 PyTorch

解析器不稳定,后面全白搭。把一个 pot 文件读完只是第一步,更常见的是要把整个目录里的 pot 文件都加载进训练管线。封装一个简易 PyTorch Dataset 并不复杂:

import glob import torch from torch.utils.data import Dataset class OLHWDBPotDataset(Dataset): def __init__(self, pot_paths: List[str], size: int = 128): self.samples = [] for path in pot_paths: self.samples.extend(read_pot_file(path)) self.size = size def __len__(self): return len(self.samples) def __getitem__(self, idx): sample = self.samples[idx] img = render_sample(sample, size=self.size) img_tensor = torch.from_numpy(np.array(img, dtype=np.float32) / 255.0) # 标签如果是中文,先映射成整数 id label = char_to_id(sample.label) return img_tensor.unsqueeze(0), label

char_to_id是你的字符表映射函数。它可以是简单字典,也可以是从训练集里统计出来的字符到 id 的映射。这一步看起来简单,但对最终模型准确率影响巨大,一定要保证训练集和测试集使用同一个映射表。

5. 常见问题与排查实录

下面是我在解析 OLHWDB 时实际见过的问题,整理成速查表,你可以直接拿来对照。

5.1 乱码不是文件坏了,是编码没选对

表现原因解决办法
标签全变成锟斤拷这种字实际编码是 GBK,却按 UTF-8 解了改用decode_pot_bytes的编码尝试顺序
头部一切正常,但标签乱码文件前半部分 ASCII,后半部分 GBK不要整个文件一次性解码,尝试逐行解码
标签里出现?或方框字符超出当前编码范围用 GB18030 兜底,确保生僻字能映射

我遇到的最诡异的一回,是同一个文件里,前半段是 GBK 编码的中文标签,后半段却混着 UTF-8 的中文。单靠整个文件解码永远都有乱码。后来我的解法是把整个 .pot 当作字节流逐行处理,每一行单独尝试解码。代价是速度稍慢,但换来了稳定,个人觉得非常值得。

5.2 解析结果比预期少了很多样本

表现原因解决办法
一个文件读出来只有 10 个样本,但打开文本看到有几百个样本标记样本起始标记不叫#Sample,而是#S或者数字开头先用 `strings file.pot
同一个文件里,相邻样本之间没有标记,只有空行样本间的分隔符就是空行,不是标记行解析器遇到两个连续换行时自动切新样本
读到一半就停了,后面还有大量数据代码因为某个异常点直接跳出了文件给解析器加 try/except,记录异常行号而不是中断整个流程

第一次写 pot 解析器时,我因为懒得看标记名,直接用固定正则匹配#Sample,结果解析完发现只有预期数据的四分之一。后来用编辑器打开原文件一搜,发现标记是#S而不是#Sample。从那以后,任何数据集的解析代码,我都会先打印前 200 个非空行,再写正则。

5.3 坐标点对不上,图像渲染出来缺笔画

表现原因解决办法
图像里只有第一条笔画笔画数量行没读到,状态机一直停留在第一个笔画确认笔画数量行字段名,以及坐标行之前有没有额外注释行
图像里笔画全部挤在左上角坐标最大值远大于渲染画布,归一化错了先打印坐标的最小值和最大值,确认范围
图像上下颠倒数位板的 y 轴方向和图像坐标方向相反渲染时把 y 换成max_y + min_y - y

上下颠倒这个问题最容易忽略。屏幕坐标系的 y 轴通常向下,而一些采集设备的数据 y 轴向上,或者相反。解析后做可视化时,我习惯一次性渲染一批样本查看,一眼就能判断方向是否是反的。如果 90% 的字符都是镜像翻转的,那不是你的解析器坏了,只是坐标系需要整体变换。

5.4 性能优化:不要每条样本都重新打开文件

把 pot 数据直接塞进 DataLoader,最愚蠢的写法是每次迭代都重新读一遍整个文件。文件大的时候,训练速度会直接掉到不可接受。更稳妥的做法是先用一次性脚本把全部样本解析并缓存成 numpy 阵列或者 Parquet 文件,训练时直接从缓存读。解析这步只做一次,后续所有实验都能受益。

python parse_pot_to_npy.py --input_dir ./OLHWDB1.2 --output_dir ./cached

缓存文件里最好额外保存一份字符映射表 JSON,这样不会因为重新解析而丢失标签顺序。我在实际项目里就是因为重新标定映射表,导致前后两次训练结果对不上,浪费了两天时间排查。

6. 我的实操体会与几个额外建议

解析 CASIA OLHWDB 的 .pot 文件,本质上不是一个算法问题,而是一个工程问题。只要愿意花时间观察文件结构、对编码保持警惕、把状态机写稳,它基本不会给你带来真正的技术难度。真正会坑到你的,反而是那些不起眼的小事:字符标签的编码,坐标点之间的分隔符,以及样本标记到底是#Sample还是某个冷门写法。

最后分享一个我自己的小习惯,每次拿到一个新的数据仓库,我不会一上来就写完整解析器,而是先写一个极简的dump脚本,打开文件,读取前 100 行,把每一行原样打印出来。很多时候,问题不是解析算法不够强,而是你压根没有看清数据长什么样。先看清楚,再动手,这比任何“万能解析库”都管用。

相关新闻

强化学习基石:值迭代与策略迭代算法深度解析

强化学习基石:值迭代与策略迭代算法深度解析

很多人刚开始接触强化学习时&#xff0c;容易被“智能体跟环境不断试错”这个叙事带偏&#xff0c;觉得强化学习就是从零开始瞎探索。但实际上&#xff0c;强化学习里有一整套完全不一样的思路&#xff1a;当环境模型——也就是状态转移概率和奖励函数——你已经知道得明明白白…

2026/10/19 17:42:49 阅读更多 →
华为防火墙SNMP v2c配置与Zabbix丢包监控实战指南

华为防火墙SNMP v2c配置与Zabbix丢包监控实战指南

最近帮一个客户排查了几天Zabbix里华为防火墙丢包监控无数据的问题&#xff0c;来来回回折腾了三个晚上&#xff0c;最后发现症结不在Zabbix&#xff0c;也不在Python脚本&#xff0c;而是华为防火墙侧SNMP v2c的配置没做对。事情本身不大&#xff0c;但能绕晕不少人。这篇把整…

2026/10/19 17:42:49 阅读更多 →
MySQL 8一键安装与巡检脚本实战:从部署到健康检查

MySQL 8一键安装与巡检脚本实战:从部署到健康检查

跑数据库运维没几年&#xff0c;但我越来越确认一件事&#xff1a;装 MySQL 这件事&#xff0c;如果每次都靠手工敲命令&#xff0c;总有一天会因为一个参数写错而丢掉一个通宵。尤其到了 MySQL 8&#xff0c;初始化方式、认证插件、参数默认值都和 5.7 有差异&#xff0c;照着…

2026/10/19 17:42:49 阅读更多 →

最新新闻

三维立体画生成器:从灰度深度图到视差编码的完整实现

三维立体画生成器:从灰度深度图到视差编码的完整实现

简介&#xff1a;这是一套面向图形处理爱好者与三维立体画创作者的三维立体画生成工具&#xff0c;适合希望快速上手立体图制作、又不想依赖昂贵商业软件的用户。软件在真实三维场景中以“照相”方式生成作品&#xff0c;内部采用双深度缓存技术&#xff0c;3D信息全面且左右对…

2026/10/19 18:26:20 阅读更多 →
10元ESP32-S3裸机跑YOLOv5s:边缘AI轻量化实战

10元ESP32-S3裸机跑YOLOv5s:边缘AI轻量化实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 18:23:17 阅读更多 →
Git常用命令实战指南:从数据模型到分支合并与撤销恢复

Git常用命令实战指南:从数据模型到分支合并与撤销恢复

Git 这个东西&#xff0c;说难不难&#xff0c;说简单也真不简单。我见过不少人把add和commit背得滚瓜烂熟&#xff0c;可是一遇到分支合并、代码冲突、提交撤销就手足无措&#xff0c;最后只能靠复制粘贴网上的命令来救急&#xff0c;运气好没事&#xff0c;运气差直接把同事的…

2026/10/19 18:23:17 阅读更多 →
毕业论文智能导航:从选题到查重全流程的AI辅助指南

毕业论文智能导航:从选题到查重全流程的AI辅助指南

毕业论文这个东西&#xff0c;只有真正常年带学生、自己也经历过完整写作过程的人才会明白&#xff1a;绝大多数人最后卡住的地方&#xff0c;根本不是“文笔差”或者“肚子里没货”&#xff0c;而是整个写作过程缺乏一条清晰的路径。选题反复推翻、文献越搜越乱、框架改了又改…

2026/10/19 18:23:17 阅读更多 →
AI辅助毕业论文写作全指南:功能、实操与避坑技巧

AI辅助毕业论文写作全指南:功能、实操与避坑技巧

1. 毕业论文的痛&#xff0c;AI真的能解吗每年到了毕业季&#xff0c;我身边就会冒出一大批“深夜改稿人”。有的在图书馆对着空白文档发呆&#xff0c;有的在跟参考文献格式搏斗到凌晨两点&#xff0c;还有的因为查重报告里的红色标记焦虑到脱发。毕业论文这件事&#xff0c;说…

2026/10/19 18:23:17 阅读更多 →
Kafka Java客户端实战:原理、参数与排障全解析

Kafka Java客户端实战:原理、参数与排障全解析

Kafka这名字&#xff0c;在Java后端圈子里&#xff0c;基本属于“躲不开”的那一类技术。不管是搞微服务、大数据管道&#xff0c;还是简单的异步解耦&#xff0c;消息队列总得选一款&#xff0c;而Kafka往往是选项里最“硬核”的那个。很多人第一反应是“分布式、高吞吐、源码…

2026/10/19 18:22:16 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介&#xff1a;本资源为电源技术方向的学术研究文档&#xff0c;聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略&#xff0c;面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址&#xff1a; https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集&#xff0c;共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →