Tesseract 是什么
Tesseract 是 Google 维护的开源 OCR 引擎,最早源自 HP,2005 年开源后逐步成为离线 OCR 的事实标准。.NET 生态下最常用的封装是同名 NuGet 包 Tesseract(历史上由 charlesw 维护,后由社区接手),它把 Tesseract C++ 库和 C# 绑定打包在一起,并提供 TesseractEngine、Pix、Page 等高层 API。
它适合的场景:
- 本地离线 OCR,无外部 API 调用与数据外传
- 扫描件、截图、票据等规整印刷体
- 对识别成本敏感或不能上云的业务
不适合的场景在文末"能力边界"单独列。
环境与 NuGet 包
推荐用 .NET 6+ 控制台或类库承载。新建项目:
dotnet new console -n OcrDemo
cd OcrDemo
dotnet add package Tesseract
Tesseract NuGet 自带原生依赖,Windows 下无需再装额外运行时;Linux 下需 libtesseract-dev 与 libleptonica-dev,macOS 走 Homebrew 即可。
Tesseract 5.x 已经把原生库打包进 runtimes/ 目录,按目标平台自动选择。tessdata 语言包
Tesseract 不内置任何语言模型。识别中文必须手动下载 chi_sim.traineddata:
- 去 tesseract-ocr/tessdata 找
chi_sim.traineddata(简体) - 如果需要更准但更慢的版本,去 tessdata_best 仓库取同一文件名
- 项目根目录建
tessdata/,把文件放进去,复制到输出目录
在 csproj 里设置复制规则:
<ItemGroup>
<None Update="tessdata\chi_sim.traineddata">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
多语言混排时把多个 .traineddata 文件放同一目录,构造引擎时写 "chi_sim+eng" 这种组合串即可。
最小可运行示例
以下为可直接编译运行的现代写法:
using Tesseract;
var imagePath = args.Length > 0 ? args[0] : "test.jpg";
using var engine = new TesseractEngine(@"./tessdata", "chi_sim", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath);
using var page = engine.Process(img);
Console.WriteLine($"Mean confidence: {page.GetMeanConfidence():P2}");
Console.WriteLine(page.GetText());
// 遍历器 5.x 改用 IEnumerable API
foreach (var block in page iterate blocks)
{
Console.WriteLine("<BLOCK>");
foreach (var para in block iterate paragraphs)
{
foreach (var line in para iterate lines)
{
foreach (var word in line iterate words)
{
Console.Write($"{word.Text} ");
}
Console.WriteLine();
}
Console.WriteLine();
}
}
IEnumerable 的扩展方法。4 层 do { } while (...) 写法属于 3.x 时代,5.x 编译不会通过。文档示例一定要按当前主版本号对照。调优与图像预处理
OCR 准确率的最大杠杆不是引擎参数,是**输入图像质量**。建议在调用 Tesseract 之前先做预处理:
- DPI 提升到 300 以上。手机截图、远景拍摄往往低于 150 DPI,先放大再识别。
- 灰度 + 二值化。用 Leptonica(
Tesseract已带)或 OpenCV 走一遍自适应阈值。 - 去噪与去边框。手机拍文档经常带阴影,先做顶帽/白顶变换。
- 校正倾斜。霍夫变换或投影法估角度,再仿射旋转回正。
Leptonica 端做这些比较顺手:
using var src = Pix.LoadFromFile(imagePath);
using var gray = src.ConvertRGBToGray();
using var binarized = gray.BinarizeOtsu();
using var page = engine.Process(binarized);
引擎与页面分割模式
引擎构造的第三个参数决定走哪条路径:
EngineMode.Default:Tesseract 自动选择 LSTM 或 LegacyEngineMode.LstmOnly:仅 LSTM(适合 4.x+ 训练数据,几乎所有现代语言包)EngineMode.TesseractOnly:仅 Legacy(仅在识别老格式时考虑)
页面分割模式(PSM)通过 engine.SetVariable 配置:
engine.SetVariable("page_separator", "\n");
engine.DefaultPageSegMode = PageSegMode.Auto;
常见取值:
PageSegMode.Auto:默认,带方向检测的整页识别PageSegMode.SingleBlock:已知是单块文本,关闭额外版面分析PageSegMode.SingleLine:只识别一行PageSegMode.SingleChar:只识别一个字符(验证码场景)
只识别图片中的某个区域
整张图是截图、只有左下角二维码旁边有编号时,可以裁矩形区域:
using var page = engine.Process(img, new Rect(x, y, width, height));
矩形坐标是像素单位,原点 (0, 0) 在左上角。这能显著减少误识别,也跳过版面分析。
可信度阈值
结果里每段都有自己的均值可信度;做批量识别时建议过滤掉低于 0.6 的段,再走人工兜底:
foreach (var block in page iterate blocks)
{
if (block.Confidence < 60) continue;
// 进一步处理
}
能力边界
这些场景 Tesseract 表现差或根本不能做:
- GIF 动图:只取首帧,识别无意义。需要先
ffmpeg -i x.gif -vsync 1 frame_%04d.png抽帧,再逐帧识别。 - 手写体:在中文场景识别率"低得可怜",Tesseract 本质仍是印刷体模型。手写场景考虑 PaddleOCR 或云 OCR。
- 低分辨率 / 强压缩:JPEG 块状噪点会让 LSTM 严重退化,先做超分或换源图。
- 表格与多列复杂版面:默认会按阅读顺序混排,需要先版面分析或切列再识别。
- 公式与代码:默认 Tesseract 不识别 LaTeX,需要专用模型。
选型准则
- 数据不能出本地、对成本敏感、印刷体为主 → Tesseract 5.x + 预处理。
- 需要中文手写或公式识别 → PaddleOCR、MathPix 或云 OCR。
- 需要方向检测、版面分析 → Tesseract 4.x+ 的 LSTM + 外部版面分析(LayoutParser)。
- 任何场景都应先做图像预处理,再谈调引擎参数。