内容中心 › 扫描件
扫描件翻译缺字,多数不是识别认错,是笔画在进识别器之前就断了。中间隔着四层,每层都能单独把字弄坏,坏法还不一样。
文字在 PDF 里是矢量,落到图上就是像素。同一个 10pt 的字,150dpi 时笔画宽 2.8 像素,200dpi 是 4.0,300dpi 是 4.39。抗锯齿还要让边缘各占一格灰,2.8 像素的一个笔画,真正实心的只剩 1–2 像素。
电子版渲染的背景是 255,直方图上就一根尖峰。扫描件是一张有纹理的纸:乘 0.92(白场落到 235 附近),叠 σ=6 高斯噪声,再按 q60 压一次 JPEG。尖峰变成几百灰度宽的肩膀,墨和纸不再是两个峰,是一个峰拖了条长尾巴。
规则只有一句:灰度 ≤ 阈值判为墨。往左偏,浅笔画被判成纸;往右偏,纸的颗粒被判成墨。
同一页 300dpi,阈值从 100 走到 220,孤立碎块(面积 ≤6 像素)依次是 48 → 2 → 0 → 211 → 38524。左端笔画被切碎,右端噪点被收进来,中间只有 132 到 160 这一小段是干净的。自动阈值算出来正好 132。
二值化后按 8 邻域求连通块,面积 ≤6 像素的孤立块单独计数,这个比例就是碎块率。
gray = render(page, dpi=300) # 采样:决定笔画厚度
scan = paper_noise(gray, gain=0.92, sigma=6, q=60) # 纸面:背景不再是纯白
_, bin_ = cv2.threshold(scan, t, 255, cv2.THRESH_BINARY_INV)
n, lab, st, _ = cv2.connectedComponentsWithStats(bin_, connectivity=8)
areas = st[1:, cv2.CC_STAT_AREA]
frag_rate = (areas <= 6).sum() / len(areas) # 碎块率:笔画断没断
同一页、同样 300dpi、同一段代码,只差"扫过没扫过":
| 阈值 | 干净渲染 碎块 | 扫描件 碎块 | 说明 |
|---|---|---|---|
| 100 | 75(2.63%) | 48(1.72%) | 两边都断笔 |
| 160 | 0 | 0 | 都干净 |
| 190 | 0 | 211(7.84%) | 扫描件开始收噪点 |
| 220 | 0 | 38524(94.97%) | 干净图无感,扫描件崩掉 |
噪点把安全窗口从"190 到 220 都行"压成了"132 到 160 这一小段"。干净图怎么调都不出事,扫描件的容错只剩几十个灰度级。
分辨率那一侧更狠:150 / 200 / 300dpi,碎块 588 / 158 / 2 个,碎块率 18.68% / 5.78% / 0.08%,笔画宽 2.8 / 4.0 / 4.39 像素,体积 646KB / 1060KB / 2121KB。多花 1.5MB,换回两个数量级。
拿到扫描件,先做三步,别急着译:
1. 量厚度:看最小字号笔画几像素宽,低于 3 直接重扫。
2. 算碎块率:二值化后统计 ≤6 像素孤立块占比。≤1% 可继续,1%–5% 只适合正文,>5% 回炉。
3. 看白带:行间空白放大,本该全白的带子上有星星点点,行切分必糊。
能力边界照实说:对印刷体最友好;手写体、竖排古籍识别率明显低;三栏以上可能错位;扫描件准确率比电子版低一档,重要交付建议人工过一遍。
[扫描件按页走 OCR 通道的做法与计费口径](https://trans.sunnytranslation.com/saomiao-fanyi)