win7 vs2015 下编译 tesseract 4.1.1
此文章为 汉学@博客园 原创作品,转载请保留版权信息
原文链接:https://www.cnblogs.com/c2soft/articles/13194981.html
一、总体思路
各库之间的依赖关系及使用的工具如下:
之前在 win7 64位 + VS2017 + VCPKG 的环境下很顺利地编译了 tesseract 4.1.1,可是当我想对 tesseract 的源码做下改动时,发现编译过程完全被 VCPKG 所接管,没法重新编译 tesseract 库(C语言门外汉,惭愧),于是产生了自己手工编译 tesseract 的想法。
按照网上的教程,直接使用 cppan 、 cmake 编译 tesseract 时,总出现找不到 endianness.h 的问题,经多次尝试,总结出使用 cppan、cmake 生成 leptonica 解决方案,然后使用 cmake-gui 手动生成 tesseract 解决方案的编译方式。
二、环境准备
编译环境:Win7 32位,VS2015
将cmake-3.17.3-win32-x86 解压到 C 盘,cppan.exe 放到 cmake 的 bin 文件夹中,将C:\cmake-3.17.3-win32-x86\bin 添加到 Path 变量中。
三、编译leptonica
1、 在 c 盘创建storage 文件夹,leptonica的所有依赖库都将下载到此文件夹中。编辑C:\Users\用户名\.cppan\cppan.yml,修改storage_dir,使其指向 c:\storage
2、 执行 cppan –V 初始化,将在c:\storage 中创建所需的文件夹结构。
3、 下载leptonica-1.78.0.tar (有网友建议使用1.76版本,说 1.79 版本编译时只生成 dll,没有lib。经验证,1.76, 1.78版本都可以正常编译。根据leptonica官网上的文档,偶数版本为稳定版本,因此直接下载1.78,1.79是否有问题未去尝试),将leptonica-1.78.0 文件夹解压到 C 盘根目录下。
4、 在C:\leptonica-1.78.0 下创建 build 文件夹,CMD窗口中执行:
cd C:\leptonica-1.78.0 cppan cd build cmake .. (在build 文件夹中执行 cmake,别少了两个点点)
C:\leptonica-1.78.0\build 下顺利生成 leptonica.sln 解决方案,使用 VS2015 打开它,VS2015->生成->配置管理器->release,先编译生成cppan-d-b-d,将在C:\storage\bin\020a56a6\Release 下生成pvt.cppan.demo.jpeg-9.2.0.dll 等7个leptonica所需的DLL文件。
5、 再编译生成 leptonica,结果生成:
C:/leptonica-1.78.0/build/src/Release/leptonica-1.78.0.lib
C:/leptonica-1.78.0/build/src/Release/leptonica-1.78.0.exp
C:\leptonica-1.78.0\build\bin\Release\leptonica-1.78.0.dll
6、 如果想生成兼容XP的文件,需要分别对 cppan-d-b-d 和leptonica 项目设置:常规->平台工具集:v140xp,有链接器选项的,还要设置:链接器->系统->所需最低版本:5.01
7、 此时C:\leptonica-1.78.0\build\src 下已经生成endianness.h 文件(网上很多编译的方法都缺少此文件)。
四、编译tesseract
1、 下载 tesseract ,注意选择 4.1.1 稳定分支,不要下载 master 版本,master 代码更新后可能出现其它编译问题。将tesseract-4.1.1文件夹解压到C盘根目录,在tesseract-4.1.1下创建build文件夹。
2、 运行cmake-gui,指定source文件夹到C:\tesseract-4.1.1(必须指定到CMakeLists.txt所在的文件夹),指定 build 文件夹到C:\tesseract-4.1.1\build,点“configure”,将显示红色的错误信息,需要指定leptonica 文件夹。
3、 根据上面的提示,leptonica 文件夹需要定位到包含 LeptonicaConfig.cmake 或 leptonica-config.cmake 的文件夹,在 leptonica 的文件夹中搜索这两个文件,找到C:\leptonica-1.78.0\build\LeptonicaConfig.cmake,因此将Leptonica_DIR 指向C:\leptonica-1.78.0\build\,再次 configure 。
4、 又出现新的错误,根据提示,是因为下载下来的icu32.zip 的 hash 值与预期的不同,打开C:\tesseract-4.1.1\src\training\CMakeLists.txt,第39行中可以发现下载的网址,到该网站手工下载icu4c-56_1-Win32-msvc10.zip,计算它的MD5值,与期待的一致。
在tesseract文件夹中搜索 icu32.zip(就是MD5值错误的文件),将下载的 icu4c-56_1-Win32-msvc10.zip 更名为 icu32.zip 替换刚才搜索到的 icu32.zip,再次configure。
5、 点configure后,结果提示“Configuring incomplete, errors occurred!”,查看提示信息,前后有两处红色的错误,先解决前面的。
cmake 试图在 C:/leptonica-1.78.0/build/ 查找 cppan.cmake 文件,可是没有找到。到 C:/leptonica-1.78.0 中搜索一下 cppan.cmake,在C:\leptonica-1.78.0\build\exports 下发现了这个文件,将其复制到C:/leptonica-1.78.0/build/,再次 configure。
Configuring done!刚才后面还有一处错误,现在没有了。点 generate,Generating done!
C:\tesseract-4.1.1\build下已经生成了tesseract.sln。
6、 用 VS2015 打开tesseract.sln,设置好编译选项后先生成 libtesseract,出现以下错误信息:
查找 allheaders.h,位于C:\leptonica-1.78.0\src下,将C:\leptonica-1.78.0\src加入项目的包含目录即可。
7、 再次生成,提示“错误C1083 无法打开包括文件: endianness.h”,经查找,endianness.h保存在C:\leptonica-1.78.0\build\src 下,该文件夹下面只有config_auto.h、endianness.h两个头文件,因为刚才已经把C:\leptonica-1.78.0\src加入了包含目录,这次不再另添加包含目录了,将两个头文件直接复制到C:\leptonica-1.78.0\src下。
8、 再次生成,提示“错误 LNK1181 无法打开输入文件 pvt.cppan.demo.gif.lib”,因为前面编译leptonica时生成的lib文件名为C:\storage\lib\020a56a6\Release\pvt.cppan.demo.gif-5.1.4.lib,所以导致这里无法打开输入文件,在VS中点击项目的 VC++目录->库目录->编辑,将C:\storage\lib\020a56a6\Release\加入到库搜索目录中:
9、 点项目的 链接->输入->依赖附加项->编辑,将pvt.cppan.demo.gif.lib、pvt.cppan.demo.jpeg.lib、pvt.cppan.demo.png.lib、pvt.cppan.demo.tiff.lib、pvt.cppan.demo.webmproject.webp.lib、pvt.cppan.demo.openjpeg.openjp2.lib几个项目逐一加入leptonica编译结果的版本号:
再次生成,顺利生成
C:/tesseract-4.1.1/build/Release/tesseract41.lib
C:/tesseract-4.1.1/build/Release/tesseract41.exp
C:\tesseract-4.1.1\build\bin\Release\tesseract41.dll
10、编译生成tesseract,会遇到以上步骤7、8、9的问题,照上面的方法即可解决。也可以跳过第8步,在第9步中加入库文件的全路径也可以。
五、改进与提高
1、编译完 tesseract.exe 后,突然心血来潮,想把全部的 TrainTools 编译出来,编译时又遇到了上面步骤 8、9 的问题,需要手工对附加依赖项加入版本号,每编译一个 traintool 都要修改 6 处,一共 10 多个工具呢!有没有一劳永逸的方法呢?猜测是因为在编译 leptonica 时生成的lib文件名为C:\storage\lib\020a56a6\Release\pvt.cppan.demo.gif-5.1.4.lib,而在 tesseract 项目中需要导入的库为 pvt.cppan.demo.gif.lib,导致二者不一致,那么只要在编译 leptonica 时生成的 pvt.cppan.demo.gif-5.1.4.lib 不带版本号,就可以与 tesseract 无缝结合了。
在 leptonica 的文件夹中搜索包含 “pvt.cppan.demo.gif” 的文件,在 C:\leptonica-1.78.0\.cppan\CMakeLists.txt 中找到了线索:
if (CPPAN_USE_CACHE) # pvt.cppan.demo.webmproject.webp-1.0.0 cppan_include("C:/storage/obj/33/8b/7ef3/generate.cmake") # pvt.cppan.demo.jpeg-9.2.0 cppan_include("C:/storage/obj/97/2a/155a/generate.cmake") # pvt.cppan.demo.gif-5.1.4 cppan_include("C:/storage/obj/d6/de/c13d/generate.cmake") # pvt.cppan.demo.tiff-4.0.9 cppan_include("C:/storage/obj/1f/16/f783/generate.cmake") # pvt.cppan.demo.png-1.6.35 cppan_include("C:/storage/obj/44/f1/4690/generate.cmake") # pvt.cppan.demo.openjpeg.openjp2-2.3.0 cppan_include("C:/storage/obj/71/a6/8bbe/generate.cmake") else() # pvt.cppan.demo.webmproject.webp-1.0.0 cppan_include("C:/storage/src/33/8b/7ef3/include.cmake") # pvt.cppan.demo.jpeg-9.2.0 cppan_include("C:/storage/src/97/2a/155a/include.cmake") # pvt.cppan.demo.gif-5.1.4 cppan_include("C:/storage/src/d6/de/c13d/include.cmake") # pvt.cppan.demo.tiff-4.0.9 cppan_include("C:/storage/src/1f/16/f783/include.cmake") # pvt.cppan.demo.png-1.6.35 cppan_include("C:/storage/src/44/f1/4690/include.cmake") # pvt.cppan.demo.openjpeg.openjp2-2.3.0 cppan_include("C:/storage/src/71/a6/8bbe/include.cmake") endif()
原来 gif、png 这些 leptonica 的依赖库的配置在 c:\storage\src 下,到 c:\storage\src 中搜索包含 “pvt.cppan.demo.gif” 的文件,找到了 C:\storage\src\d6\de\c13d\CMakeLists.txt,其中包含以下代码:
if (CPPAN_SHORT_LOCAL_NAMES) set_target_properties(${this} PROPERTIES OUTPUT_NAME gif-5.1.4) else() set_target_properties(${this} PROPERTIES OUTPUT_NAME pvt.cppan.demo.gif-5.1.4) // 去掉“-5.1.4”后,只生成 pvt.cppan.demo.gif.lib endif()
试了一下,只要将 OUTPUT_NAME 中的版本号去掉,编译时生成的 lib 就是没有版本号了。
在编译 leptonica 时, 在执行完 cppan 命令,下载好全部依赖库的源代码后,先不要执行 cmake,到c:\storage\src 下搜索 “CMakeLists.txt”,一共找到 10 个,在每个文件中查找 “OUTPUT_NAME”,将 OUTPUT_NAME 后面的版本号去掉,然后再执行 cmake,这样生成的解决方案编译后就会得到不带版本号的 lib 文件了,编译 tesseract 时的步骤 8、9 就可以免去了。
2、在编译 TrainTools 时还遇到一个问题:就是每编译一个项目,就要设置包含目录和库目录,能否设置成全局属性,不再一一设置呢?后来找到了方法:在 VS 中打开 视图->其他窗口->属性管理器,在任一项目下找到 Microsoft.Cpp.Win32.user 打开,
对其设置包含目录和库目录后,就是全局性质的设置了,其它项目就不用再逐一设置了。
六、小结
以上记录的是解决问题的过程,实际在编译时可以把步骤再优化一些,简要记录如下:
- cppan 下载 leptonica 依赖库的源代码
- 在 c:\storage\src 下搜索 CMakeLists.txt(一共10个),将其中 OUTPUT_NAME 后面的版本号去掉
- cmake 生成 leptonica 解决方案,VS 编译之
- 将 C:\leptonica-1.78.0\build\src 中的 config_auto.h、endianness.h 复制到 C:\leptonica-1.78.0\src 中,将 C:\leptonica-1.78.0\build\exports\cppan.cmake 复制到 C:\leptonica-1.78.0\build
- 在 cmake-gui 中设置 leptonica 路径为 C:\leptonica-1.78.0\build\ ,替换 icu32.zip,生成 tesseract 解决方案
- VS 打开 tesseract 解决方案,全局包含目录添加 C:\leptonica-1.78.0\src ,全局库目录添加 C:\storage\lib\020a56a6\Release,然后就可以逐一编译了
七、后记
这种编译方式的优点在于,tesseract 所依赖的其它库使用 cppan 和 cmake 自动下载源代码,生成解决方案,全程自动化;而 tesseract 使用手工编译,如果需要改动其源代码,可以随时重新编译它,比较灵活。将自己编译的全过程记录下来,希望对大家有所帮助。
下载 traineddata 的页面是 https://tesseract-ocr.github.io/tessdoc/Data-Files,不知道为什么下载不下来。
BTW:
我使用 tesseract 对下面的验证码图片
进行识别时遇到了很诡异的问题,本以为这个图片很清晰,而且没有做变形处理,tesseract 应该可以轻松识别。可是 tesseract 将其识别为 ZING。开始我以为是 tesseract 使用词库对识别结果做了纠正,可是在源代码中禁用词库后,结果仍然是 ZING。
将原图放大之后观察,4个字母之间的间隔是1个像素,在 PhotoShop 中将字符间距拉至2像素,tesseract 识别为 Z2NG;将字符间距拉到3像素,又识别为 ZING;当间距拉大到4像素以上时,就完全可以正确识别了。
使用 Tesseract 的multilang_debug_level 参数分别对间距为2像素、3像素的图片测试,结果如下:
猜想与字符间距有关