十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Windows 32位下Tesseract OCR库配置:避开所有链接陷阱

Windows 32位下Tesseract OCR库配置:避开所有链接陷阱 简介面向Windows 32位C开发者的Tesseract 3.02.02 OCR引擎SDK资源包整合了官方头文件、静态库、动态库以及版本属性配置适合需要离线接入OCR识别能力的中高级开发者可直接用于VS工程中处理图片文字提取、扫描件识别等典型场景。压缩包共36个文件以24个H头文件、4个LIB库文件和2个DLL动态库为核心辅以2个VSPROPS工程属性文件、3个TXT说明文档和1个EXP导出文件整体大小约27.1MB目录结构按include与lib分区存放便于复制到现有项目直接引用。目前已有452人学习/下载。借助这组SDK开发者可免去从源码编译Tesseract的繁琐过程按需选择静态链接库或动态链接库并通过VS属性文件快速同步版本号设置同时提供调试库与发布库能适配不同构建配置。附带说明文档还能帮助排查工程参数配置问题总体可有效缩短OCR模块的集成周期降低Windows平台下Tesseract的环境搭建成本。 如果你手里也存着这么个压缩包名字是一长串tesseract-3.02.02-win32-lib-include-dirs源文件.zip那你大概率正打算在 Windows 32 位环境下接入 Tesseract OCR。这个包不是官方直接给的那种安装程序而是有人提前编译好的开发包里面只有 lib 库、include 头文件运气好还会附带源码示例。它能解决的事情很明确让你不用从源码一路编译 Tesseract而是直接把现成的库接进自己的 C/C 工程里用。我当年第一次拿到这种包的时候也被里面乱糟糟的目录搞得一头雾水后来在几个老项目里反复踩坑才把这一套配置流程彻底摸清楚。这篇东西就是给那些同样拿到这个包、想赶紧把 OCR 功能跑起来的人看的不管你是接手老项目还是想在 Windows 某个 x86 程序里临时加个文字识别能力照着下面走一遍基本就够了。1. 先搞清楚这个包里到底装了什么1.1 从包名能读出哪些关键信息文件名tesseract-3.02.02-win32-lib-include-dirs其实把信息都写在脸上了只是很多人没细看。3.02.02是 Tesseract 的版本号这个版本属于 3.x 时代的经典维护版本发布日期大约在 2013 年前后。win32说明它是 32 位 Windows 平台的产物对应的库只能在 x86 程序里链接。lib-include-dirs说的是包的内容形态——包含库文件目录和头文件目录不是安装程序也不带 tessdata 语言数据。最后那个“源文件”字样比较有意思意思是这个包在 lib 和 include 之外可能还夹带了部分源码、示例程序或者构建脚本。解压之后如果看到src、examples、README这类目录先别急着删里面的示例通常会告诉你这个包是用哪个 Visual Studio 版本编译出来的这对接下来的链接配置非常关键。这种“lib include”的结构跟嵌入式开发里把 C 文件编译成 lib 库再拿给别的工程用的套路一个逻辑头文件给编译器看库文件给链接器用两者配合开发者才能写出调用 Tesseract API 的代码。1.2 include 和 lib 目录里分别是什么打开 include 目录你会看到tesseract和leptonica两个子目录。tesseract下面最核心的是baseapi.h和capi.h前者是 C 接口的入口后者是 C 接口的入口。3.x 版本的 API 比 4.x 简单得多因为当时还没有引入 LSTM 神经网络那一套所以函数调用方式非常直白。leptonica是 Tesseract 在 3.x 时代必须依赖的图像处理库负责读取图片、做二值化、区域分割等操作。你在代码里需要用Pix*类型承载图像数据就得包含allheaders.h头文件。这也是新手最容易忽略的地方——只配了 Tesseract 的头文件路径没配 Leptonica编译时会直接报找不到allheaders.h。lib 目录里通常放着libtesseract.lib、liblept.lib这样的导入库文件。注意不同编译者给库起的名字可能不一样有人会省略lib前缀直接叫tesseract.lib也有人会加上版本号。配置链接器的时候先看一眼 lib 目录里实际的.lib文件名别想当然地写死。2. 把开发包接进 Visual Studio 工程的标准姿势2.1 目录摆放和工程属性配置拿到包之后建议不要直接把整个文件夹塞进系统 PATH 或者全局包含目录这样以后换个环境就乱了。我的习惯是在工程目录下建一个third_party文件夹把解压后的整个目录放进去然后用相对路径引用。假设你的工程文件在D:\myproject\那么这个包就放在D:\myproject\third_party\tesseract-3.02.02\头文件在include子目录里库文件在lib子目录里。然后在 Visual Studio 工程上右键进入属性页需要配置三个位置配置项操作路径填写的值附加包含目录C/C → 常规 → 附加包含目录$(SolutionDir)third_party\tesseract-3.02.02\include附加库目录链接器 → 常规 → 附加库目录$(SolutionDir)third_party\tesseract-3.02.02\lib附加依赖项链接器 → 输入 → 附加依赖项libtesseract.lib;liblept.lib$(SolutionDir)是 VS 内置的宏会在编译时自动展开成解决方案目录的绝对路径。用宏的好处是工程换台电脑、换个路径不需要重新改配置。如果你用的是 CMake那就是include_directories和link_directories的对应操作但imported library的处理方式还稍有不同这里先不展开。2.2 字符集和多字节字符集的坑3.02.02 那个年代Visual Studio 的项目向导默认还在用多字节字符集Tesseract 内部也大量使用char*处理文本。如果你把工程设成 Unicode 字符集倒不会直接编译失败但只要你需要把识别结果往界面、文件里写就到处要处理wchar_t和char的转换非常折磨人。所以在新建工程或者调整现有工程时建议把字符集设为“使用多字节字符集”。万一工程已经依赖 Unicode 了也不是不能用只是需要在拿到TessBaseAPIGetUTF8Text()返回的 UTF-8 字符串后自己调用MultiByteToWideChar转成宽字符。字符集转换这一层我在后面第 3 章再展开说。还有一个容易忽略的配置是运行库。如果你的工程用的运行库是/MT静态链接运行时而 lib 是用/MD动态链接运行时编译的链接时很可能报LNK2038运行时库不匹配。检查方式属性页 → C/C → 代码生成 → 运行库看当前值对照一下。不确定这个包的编译方式时先试试工程默认的/MD报错再切/MT。2.3 用一段最小演示代码验证配置配置完上述属性写个最简单的识别程序来验证能不能跑通。新建一个控制台工程写入以下代码#include tesseract/baseapi.h #include leptonica/allheaders.h #include cstdio #pragma comment(lib, libtesseract.lib) #pragma comment(lib, liblept.lib) int main() { const char* imagePath test.png; Pix* image pixRead(imagePath); if (!image) { printf(read image failed\n); return -1; } TessBaseAPI* api TessBaseAPICreate(); if (TessBaseAPIInit3(api, tessdata, eng) ! 0) { printf(init tesseract failed\n); return -1; } TessBaseAPISetImage2(api, image); char* text TessBaseAPIGetUTF8Text(api); if (text) { printf(result:\n%s\n, text); TessDeleteText(text); } TessBaseAPIDestroy(api); pixDestroy(image); return 0; }这段代码里TessBaseAPIInit3(api, tessdata, eng)的第二个参数是语言数据tessdata文件夹的路径第三个参数是语言代码eng是英文。执行前保证test.png和tessdata里面至少有一个eng.traineddata文件都在当前工作目录或指定路径下编译链接能通过、程序能输出文字就说明整个开发包接成功了。3. 链接和运行时最容易踩的坑逐个拆解3.1 LNK2019unresolved external symbol这是最经典、也是问得最多的链接错误报错样式大概是error LNK2019: unresolved external symbol TessBaseAPICreate referenced in function main。意思很清楚编译器认得这个函数但链接器找不到它的实现。大部分情况下是附加依赖项没填或者填的名字和 lib 里实际导出的符号不一致。如果你确认加了libtesseract.lib还是报错那就把lib目录里的文件列表挨个看一遍找到那个和tesseract相关的.lib用dumpbin /exports libtesseract.lib查看导出符号确认里面确实有TessBaseAPICreate。这个包如果是从源码编译的还有可能把 Tesseract 和 Leptonica 合并成了一个静态库那样就不需要两个 lib 了。另外要提一句#pragma comment(lib, libtesseract.lib)这种写在代码里的方式也可以它能避免在工程属性里手动配置附加依赖项但前提是库文件路径已经在“附加库目录”里配好否则 pragma 也找不到文件。3.2 LNK1112x86 和 x64 冲突error LNK1112: module machine type x86 conflicts with target machine type x64这个错出现在你拿 win32 版的 lib 去编译 x64 工程时。包名里的 win32 已经写得很清楚了这个 lib 只能给 32 位程序用。解决办法有两个一是把工程的目标平台从 x64 改成 Win32在 VS 工具栏的平台下拉框里切换或者进入配置管理器手动调整二是去找对应 x64 版的 Tesseract 开发包。如果是 C# 或者 Java 项目通过 P/Invoke 或 JNI 调用更要小心进程位数必须一致——x86 的 DLL 只能由 32 位进程加载。这里有个隐蔽的情况有些人建工程时默认是 Any CPU编译出的 exe 在 64 位系统上会以 64 位进程运行但链接时却走的 x86 导入库于是各种诡异错误都冒出来了。C# 工程建议直接指定平台为 x86省得后面运行时才炸。3.3 运行时找不到 DLL或 tessdata 加载失败链接过了程序刚跑起来就弹窗说找不到libtesseract.dll或liblept.dll这是典型的运行时 DLL 路径问题。编译器链接的.lib只是导入库真正干活的还是同名的 DLL 文件。解决方案很简单把这两个 DLL以及它们依赖的 zlib、libpng 等和你的 exe 放在同一个目录下或者把 DLL 所在路径加入系统 PATH 环境变量后重启终端。tessdata 加载失败则是另一类问题。报错信息通常是Error opening data file或Tesseract couldnt load any languages!。原因多半是TessBaseAPIInit3第二个参数传的路径不对或者根本没有设置TESSDATA_PREFIX环境变量。这个 3.02.02 版本对语言数据的版本很敏感必须使用 3.x 配套的traineddata文件拿 4.x 的语言包替换后十有八九加载不出来会报数据文件格式不兼容。3.4 VSCode 用户特别容易碰到的 includePath 问题如果你不是在 Visual Studio 里开发而是在 VSCode 里写代码开头热词里那条“检测到 #include 错误。请更新你的 includepath”说的就是这种场景。VSCode 的 C/C 扩展不读工程属性它读的是.vscode/c_cpp_properties.json里的includePath配置。{ configurations: [ { name: Win32, includePath: [ ${workspaceFolder}/third_party/tesseract-3.02.02/include, ${workspaceFolder}/third_party/tesseract-3.02.02/include/tesseract, ${workspaceFolder}/third_party/tesseract-3.02.02/include/leptonica ], defines: [], compilerPath: C:/Program Files (x86)/Microsoft Visual Studio/.../cl.exe, cStandard: c11, cppStandard: c17, intelliSenseMode: windows-msvc-x86 } ], version: 4 }改完这个文件VSCode 的智能提示通常就认识tesseract/baseapi.h了。但注意这个文件只影响编辑器的代码分析和跳转真正编译仍然由你在 tasks.json 或 CMake 里指定的命令负责两边都要配置好才能顺畅工作。4. 3.02.02 这个老版本什么时候用、什么时候果断换4.1 老版本的优势轻量、稳定、易于嵌入既然这个包还在网上流传就说明确实有人在用它。3.02.02 最大的好处是体积小、依赖少编译出来的可执行文件比 4.x 小不少对运行环境的要求也低。在 Windows XP、老式工控机、或者内存只有几百 MB 的嵌入式设备上3.x 反而更舒服。同时3.x 的 C API 接口非常稳定几乎没变过。很多老项目从 2014、2015 年维护到现在代码里还写着TessBaseAPICreate()这类调用。对这种情况升级到 4.x/5.x 意味着要把整套 API 调用层重写一遍风险和成本都高反而不如继续用老版本实在。它的识别能力也并非一无是处。处理白底黑字的印刷体文档、截图、单据用合适的阈值和页面分割模式识别率还是相当可观的。我自己做过对比清晰扫描件下 3.x 和 4.x 的准确率差距没有想象中大主要差距体现在复杂排版、低分辨率、带噪声的图片上。4.2 老版本的硬伤LSTM、语言包、多语言混合3.x 的识别引擎本质上是传统计算机视觉方法基于连通域分析、模板匹配和特征分类那一套。4.0 引入的 LSTM 神经网络模型确实在识别率上全面超出 3.x尤其在非标准字体、手写体、自然场景文字上差距是代际级别的。语言包也是个大问题。3.x 的 traineddata 和 4.x/5.x 完全不通用你在 4.x 时代下载的中文简体chi_sim.traineddata塞给 3.02.02 是没法用的。如果项目需要现在语言包3.x 的数据文件不好找下载渠道也大多是第三方分流这本身有安全风险。多语言混合识别场景比如中英文混排3.x 需要指定同时加载多个语言文件处理不好会出现乱码识别结果里中英文互相干扰。4.x 在这块改进很多OEM_LSTM_ONLY模式下对混排文字的鲁棒性好不少。4.3 升级到 4.x/5.x 的成本评估如果项目还在早期或者识别效果已经成为瓶颈我建议直接换 4.x 或 5.x。需要付出的代价主要是三块API 从 C 风格向 C 类风格的迁移依赖库从 Leptonica Tesseract 变成了 OpenCV 也常被牵扯进来以及平台支持上 4.x/5.x 对 Windows 32 位的支持越来越弱很多预编译包只给 x64。从 3.02.02 换到 4.x最典型的变化是初始化接口从TessBaseAPIInit3变成TessBaseAPI::Init图像设置从TessBaseAPISetImage2变成SetImage返回的 UTF-8 文本处理方式基本不变。如果原本代码就是用 C 封装好的一层迁移成本并不算高。我的判断标准就一条如果只是维护老系统识别效果能接受那就别折腾3.02.02 依然够用如果新项目、效果要求高、或者要处理复杂版面直接把 4.x 起步别在 3.x 上浪费时间。5. 高频问题速查与几条独家经验5.1 典型报错和处理方法对照报错信息问题原因处理方式fatal error C1083: Cannot open include file: tesseract/baseapi.h附加包含目录没配或路径不对检查 include 目录路径确认不是 include/tesseract 直接当 includeerror LNK2019: unresolved external symbol TessBaseAPICreatelib 没链接或 lib 名字不对检查附加依赖项用 dumpbin 看导出符号error LNK2038: mismatch detected for RuntimeLibrary运行库设置/MT与/MD不一致修改 C/C → 代码生成 → 运行库和 lib 保持同一种error LNK1112: module machine type x86 conflicts with target machine type x64平台位数和 lib 类型不一致将工程平台改为 x86 或更换 x64 版 libError opening data fileTESSDATA_PREFIX 没设或路径错误设置环境变量或在 Init 时传 tessdata 目录绝对路径The code execution cannot proceed because libtesseract.dll was not foundDLL 不在 exe 目录或 PATH 中把相关 DLL 复制到 exe 同目录或加入 PATH5.2 几条实操经验第一拿到这种民间编译的开发包先去查 DLL 编译时用的 VC 版本。如果包里没有文档就用 PE 工具或者查看导入表的加载器版本再决定自己的 Visual Studio 最好用哪个版本。VC2010 编译的 lib 硬喂给 VC2015 工程链接时通常没事但运行时的 CRT 版本差异可能在某个隐蔽路径上炸开。第二TESSDATA_PREFIX这个环境变量最好还是老老实实设一下即使你在代码里调 Init 时传了路径。因为 3.x 的很多内部函数在加载语言数据时会额外读取一次环境变量路径两边不一致时会出现间歇性加载失败。第三字符集问题不要等出乱码再处理。用TessBaseAPIGetUTF8Text()拿到的文本是 UTF-8 编码在 Windows 控制台直接printf输出中文时几乎必然乱码。稳妥的做法是转成 GBK 再输出或者写入文件后用支持 UTF-8 的编辑器查看。#include windows.h #include string std::string utf8ToGbk(const char* utf8) { int len MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); wchar_t* wstr new wchar_t[len]; MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, len); int size WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL); char* str new char[size]; WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, size, NULL, NULL); std::string result(str); delete[] wstr; delete[] str; return result; }第四处理识别效果时3.x 的TessBaseAPISetPageSegMode值得认真调一下。默认的PSM_SINGLE_BLOCK对整页文本适用但识别单行文字或单个数字时要切成PSM_SINGLE_LINE识别表格里的单元格切成PSM_SINGLE_BLOCK配合SetRectangle手动指定区域效果会好很多。这个技巧在做单据识别的老项目里特别有用。5.3 关于这个压缩包来源的一点提醒再次提一句这类第三方编译包的数据文件和源文件下载后建议先用杀毒软件扫一遍再用时尽量选口碑好的分流渠道。Tesseract 本身是开源软件但第三方打包的 DLL 是否经过二次修改谁也没法百分百保证。如果项目对安全性有严格要求可以考虑用 vcpkg 或源码自行编译这条路上花的时间多一点但库的来源和编译参数完全可控。本文还有配套的精品资源点击获取
返回列表