难度跳变在哪
单个数字的实验室里,MNIST 把每个数字都切好、摆正了才交给模型。 真实世界不会这么客气:表单、支票、图纸上是一串连续的字迹, 在"认字"之前得先回答"哪里到哪里算一个字"——这一步叫切割(segmentation), 从这一页开始它是我们自己的活。写一串号码试试,看机器怎么下刀。
手写板(写一串数字,数字之间留点空隙;也可以载入一张图片,还能在图上补笔)
正在加载 6 万张训练图(6MB)…
识别结果(k-NN,k=3,逐段判定)
写完停笔半秒自动识别,或点"识别"
机器是怎么下刀的:竖直投影
- 把画板逐列统计墨水量,得到下方那条投影直方图——有字的地方隆起,字与字之间塌下去;
- 先切碎:用很小的阈值(3 列空白就切)把字迹剁成"原子块"——分两笔写的 5 会被剁开,没关系。疑似连笔的块(宽超过高的 0.9 倍)再找连笔点补刀:逐列数竖直方向穿过几段笔画,只穿 1 段且墨量最少的列,就是两个字相连的"脖颈"——不小心写连的数字通常只在一根细笔画上相触,这一刀正断在那里;
- 让识别得分决定怎么拼:相邻的原子块可以合并成一段(最多三块,合出来宽超过高的 1.3 倍直接否决——单个数字不会那么扁)。每种拼法都拿去识别,一段的得分基于墨量归一化的最近邻距离(否则几个字压扁成一段后墨水蒸发,距离会虚低)加平方惩罚,再扣一笔"开段费"防碎片蹭分。动态规划从所有拼法里选总分最高的。这就是"识别驱动切割":切与不切,由认得像不像说了算;
- 每一段各自走一遍老流程:裁包围盒 → 等比缩到 20×20 → 按重心居中到 28×28;
- 逐段用 k-NN(6 万张全量,XOR + popcount,平移容忍 ±1 像素,k=3 投票)认出数字,从左到右拼成号码。三票不一致的段用橙色标出——那是机器"没把握"的字。取消勾选"识别驱动切割"可以退回固定阈值的老切法,拖滑杆感受"阈值太小腰斩、太大焊死"的两难——再切回自动模式看它怎么两头都接住。
课堂挑战:写一个上横和主体分开的 5——固定阈值模式把灵敏度调小,看它被腰斩成两段各认成什么; 切回自动模式,看 DP 怎么把它拼回一个 5。再故意把两个数字写得几乎挨上: 固定阈值下它们被焊成一团,自动模式会在投影最薄处补刀、由得分决定切不切。 翻车与被救回都在展示同一件事:识别系统的上限往往不在分类器,而在切割和预处理——而让切割听识别的话,是两个模块联动的第一步。