测量数独照片识别器带给我们的经验
更新于 2026年11月5日
怎样才算读对
只有81个格全部正确,一道题才算读对:错一个数字就成了另一道题。所以我们按整道题计数,而不是按格计数。两种计法可能讲出截然不同的结论,本页就是例子:在印刷题照片上,识别器现在能读对98.9%的格,但整题读对的比例几乎没变,因为大多数错格集中在少数几张难认的图片里。
我们还统计最危险的一类错误:读错了却仍然恰好只有一个解的题目。真正的数独只有一个解,所以读出无解或多解的结果会立即被发现。读错但只有一个解的题目看起来没有问题,因此求解器会标出每一个它没有把握的格,并请你在求解前将这些格与你的题目核对。
只有200张图片时,结果的精确度是有限的。对于主要结果,我们给出95%区间(Wilson 区间):200张图片中的89.5%意味着真实比例很可能在84.5%到93.0%之间。
我们用来测试的图片
我们从两个公开数据集入手。Lexski 的 Sudoku Image Recognition 数据集(CC0)有1400张图片,大多是网上分享的截图和照片:各种风格的应用、深色主题、铅笔标记、在纸上解到一半的题目。Baptiste Wicht 和 Jean Hennebert 的数据集(CC BY 4.0)收录了用手机拍摄的报纸数独,其中一些已用笔手工填完。
在做任何改动之前,我们先留出了三个测试集:200张 Lexski 图片、40张报纸照片和40道手工填完的报纸题目。工作期间我们既没有用它们训练,也没有查看它们。所有决定都基于另外200张 Lexski 图片(即调优集)作出,测试集只在最后读取一次。
起点
10月31日的第一个版本完全读对了200张 Lexski 图片中的101张、40张报纸照片中的34张,40道填完的题目则一道也没读对。它的大部分问题出在识别数字之前。它把最大的近似正方形墨迹当作盘面,而在截图上,这个形状常常把页眉或数字键盘也包了进去,深色主题中细细的灰色线条则完全被漏掉。在调优集的200张图片中,它只有118张把网格定位在了正确的位置。
我们一步步改了什么
每一行是一项改动,数字表示改动后200张调优图片中被完全读对的张数。最后三行属于第二轮。
| 改动 | 完全读对的调优图片(共200张) |
|---|---|
| 第一个版本,10月31日 | 99 |
| 按线条寻找网格:每个方向十条等距线 | 129 |
| 并排评判网格;尝试平移一格 | 136 |
| 利用淡细线寻找网格 | 138 |
| 完整切出各格;用真实格学习数字 | 161 |
| 小型网络标出盘面位置 | 162 |
| 沿书页弯曲处跟踪线条 | 163 |
| 更好的数字网络,铅笔标记单独成类 | 173 |
| 三个数字网络取平均 | 177 |
| 谨慎的唯一解规则;填完的盘面整体读取 | 177 |
| 第二轮:全尺寸照片先减半再缩小 | 178 |
| 第二轮:短而淡的墨迹视为铅笔标记 | 179 |
| 第二轮:侧转照片由全部三个网络判断 | 179 |
大部分提升来自三项改动。现在按线条来寻找网格:每一个对盘面位置的猜测都会被对齐到每个方向十条等距的线上,再并排比较评判,一个专门标出盘面位置的小型网络也参与投票。每个格都被完整切出,这样铅笔标记在角落里仍然显得很小,深色方块上的浅色数字看起来就像纸上的墨迹。数字网络改为从 Lexski 训练图片中切出的真实格来学习,并把铅笔标记单独作为一类。现在由三个分开训练的小型网络读取每个格,并对它们的答案取平均,因为它们出错的格各不相同。
填完的题目会得到额外帮助。当盘面上有79个或更多数字时,识别器会寻找最可能的完整网格,使每一行、每一列和每一宫都包含1到9。逐格读取时,40道手写测试题中只有7道被完全读对;作为填完的数独整体读取时,40道全部读对。
第二轮又加入了三项较小的改动。全尺寸的手机照片在缩小之前会先逐级减半,这样细线和铅笔笔画会被平均进去,而不会被跳过。如果某个格中的墨迹比盘面上有把握的数字既短得多、又淡得多,就会被视为可能的铅笔标记。侧转照片的旋转方向改由全部三个网络共同判断,而不是只由一个网络判断。

没有帮助的尝试
这些我们也在调优集上测量过,最终没有采用:
- 更大的数字网络:用59,000个权重代替42,000个,只多读对了一张调优图片,在浏览器中却慢了3.8倍。
- 3000张带铅笔标记和深色主题的生成应用截图:用与不用,分数都一样。
- 读取彩色而非灰度图像,使红笔与黑色墨迹一样深:多读对两张调优图片,但手写识别变差了。
- 把训练用的数字扭曲得更像手写:手写识别变差了。
- 让唯一解规则改动更多的格:读对的题目更多了,但读错却只有一个解的危险题目也更多了。
- 用新数据重新训练这三个网络,或改用四个或六个网络:差异在噪声范围内,所以沿用了最初的网络。
- 对于被画面边框截断的盘面,把图片边缘当作盘面边缘:读错的图片和新读对的一样多。
首批测试集上的结果
各测试集中被完全读对的题目数,分别为第一个版本和当前识别器的结果:
| 测试集 | 10月31日 | 现在 |
|---|---|---|
| 网上分享的截图和照片(Lexski)图片数: 200 | 10150.5% | 17989.5% |
| 报纸照片(Wicht 和 Hennebert)图片数: 40 | 3485.0% | 40100.0% |
| 手工填完的报纸题目(Wicht 和 Hennebert)图片数: 40 | 00.0% | 40100.0% |
在 Lexski 图片上,识别器从50.5%提升到89.5%(84.5%到93.0%),读错却只有一个解的题目从7道降到4道。这4道中有3道,多出的那个数字正是该格应填的数字,因此题目仍会得出正确的解;第4道是一个印刷清晰的1,而数据集把该格标为空格。179道中有177道在第一轮结束时就已读对。最后两道是在第二轮、我们研究过失败案例之后才读对的,因此这个测试集已不再是未经接触的。
40道全对听起来很完美,但40张图片只能说明真实比例高于约91%。还有一项我们本该先做的检查:40张报纸测试照片中有4张也出现在该数据集的训练集中,其中两张逐像素相同。去掉这4张,结果是36道中36道读对。
新测试:任何版本都没见过的200张照片
那时首批测试集已经被读取过,失败案例也已被研究过,所以它们已无法告诉我们识别器在从未见过的图片上表现如何。我们在 Hugging Face、Kaggle、GitHub、Zenodo、Figshare 和 AIcrowd 上搜寻了更多带标注的数独照片。大多数数据集是生成的盘面、单个数字,或是 Wicht 照片的副本。有三个 GitHub 合集包含真实的带标注照片,全部是印刷题目:一本公开题集的100张照片(NatalijaPetric/SudokuDataset)、80张以报纸为主的照片(mineshpatel1/sudoku-solver,已剔除49张本身就是 Wicht 照片的图片和一张副本),以及来自布加勒斯特大学一门计算机视觉课程项目的20张印刷题纸(danielsociu/SudokuRecognition)。
这三个合集都没有注明许可,所以我们只用它们来测量:从不用于训练,也不在此处展示。图片清单在做任何改动之前就已确定并保存,依据文件哈希和标注按规则选出,而且直到第二轮最后一项改动完成之前都没有打开过这些图片。之后,识别器的每个版本各读取它们一次。表中统计的是被完全读对的题目数。
| 来源 | 10月31日 | 第一轮 | 现在 |
|---|---|---|---|
| 一本公开题集(NatalijaPetric)照片数: 100 | 7979.0% | 7676.0% | 7878.0% |
| 以报纸为主(mineshpatel1)照片数: 80 | 6581.3% | 6885.0% | 6986.3% |
| 印刷题纸(布加勒斯特大学课程)照片数: 20 | 20100.0% | 20100.0% | 20100.0% |
| 全部200张照片数: 200 | 16482.0% | 16482.0% | 16783.5% |
在识别器从未见过的印刷题目上,两轮的全部工作带来的变化不大。第一个版本完全读对了其中的82.0%,当前版本为83.5%(77.7%到88.0%):新读对14道,又丢了11道。真正改善的是格:读对的格从94.2%提高到98.9%,网格在每张照片中都被找到,而不是200张中的195张。读错却只有一个解的题目:之前5道,现在6道。
这些退步有明确的原因。为了读取铅笔标记和深色主题,现在每个格都被完整切出,淡淡的墨迹也会计入。在薄薄的报纸上,背面的内容会透过来,既淡又是镜像的,新识别器会把这些阴影读成数字;第一个版本只看格中最大的墨迹形状,从来看不到它们。在卷曲的书页上,盘面的外框线或宫线可能落进格内,被读成1。
有两处未读对其实是标注错误:照片上是3和9,标注却写作9和8;照片上是4,标注却写作2。按正确标注计算,当前识别器的读对率为84.5%。
仍会出错的地方
200张新照片中有33张没有被完全读对。其中22张是那本公开题集的书页:靠近书脊处,页面的卷曲超出了识别器能跟踪的程度,于是线条落进格内被读成1,或者角上的格在切割时跨过了一条线。7张是背面透印的报纸。其余是一张带摩尔纹的屏幕照片、一个被读成1的盘面边缘,以及那两处标注错误。
200张 Lexski 图片中有21张没有被完全读对:铅笔标记被读成数字,包括擦掉的铅笔留下淡淡数字痕迹的情况(7张);多出一个数字,大多是单独一个铅笔标记被当成填入的数字(5张);网格位置错误或未找到,出现在格与格之间没有线条的应用主题或手绘网格上(5张);不常见的方块样式和颜色(4张)。
为什么没到97%,以及下一步
所有处理都在你的浏览器中运行:一个224 KB的模型和约850行 JavaScript,在笔记本电脑上每张照片的处理时间中位数约为300毫秒,在把处理器降速四倍(相当于一部慢速手机)时约为1.2秒。在这个预算内,更大的网络并没有帮助。剩下的是长尾问题:卷曲的书页、透印、铅笔标记和不常见的应用风格。我们找到的每个公开带标注数据集现在都已被使用或看过,所以下一轮需要我们自己拍摄并标注的照片,并在这些照片上修复和测量淡墨迹与书页卷曲的问题。
如何获得最佳扫描效果
- 将手机正对题目上方,让整个网格都在画面内。
- 把书或报纸压平:在印刷题目上,大多数识别失败都是书页卷曲造成的。
- 对于薄报纸,在页面背后垫一张白纸,以免背面内容透过来。
- 在题目上写铅笔标记之前先扫描。
- 求解之前,将求解器标出的格与你的题目核对。
数据与来源
- Lexski, Sudoku Image Recognition (Hugging Face), CC0 1.0
- Wicht, B. and Hennebert, J., Sudoku dataset (GitHub), CC BY 4.0; "Camera-based Sudoku recognition with deep belief network", SoCPaR 2014
- NatalijaPetric, SudokuDataset (GitHub), 未注明许可,仅用于测量
- mineshpatel1, sudoku-solver (GitHub), 未注明许可,仅用于测量
- danielsociu, SudokuRecognition (GitHub), University of Bucharest course project, 未注明许可,仅用于测量
- 一步步了解解题器如何识别照片 (English)