[转老马的文章]MODI中的OCR模块
作者:马健
邮箱:stronghorse_mj@hotmail.com发布:2012.07.02
更新:
2012.07.09
补充非简体中文版内容
自从基于MODI的DjVuToy、FreePic2Pdf、Pdg2Pic发布后,很多人就在问同一个问题:能不能在不装Office 2003/2007或SharePoint Designer 2007的情况下,让基于MODI的软件正常OCR?毕竟对于简体中文来说,就算只装SharePoint Designer 2007中的MODI,也要近650 MB,装Office 2007的MODI则更夸张,要近1 GB。
想解决这个问题,需要从MODI中OCR模块的来历说起。在《用MODI OCR 21种语言》一文中已经说过,MODI其实只是封装了ScanSoft API,而google(注意我说的是google,不是baidu)一下关键词“ScanSoft API”,可以发现两个网页:
http://www.corrupteddatarecovery.com/Products/ScanSoft-API.asp
http://www.corrupteddatarecovery.com/Products/Asian-OCR-for-ScanSoft-API.asp
从这两个帖子及其他一些相关信息推断,ScanSoft API封装了清华文通以支持亚洲语言,而MODI又在ScanSoft API上封装出MODI接口,并在此基础上提供MODI应用(MSPVIEW.EXE),整个层次结构应该如下图所示:
—————— MSPVIEW.EXE
应用层 ┃
—————— MODI接口
接口层 ┃
ScanSoft API
┏━━━━━┻━━━━━┓
┃ ScanSoft API亚洲语言支持(清华文通)
—————— ┃ ┃
数据层 西欧11国、东欧3国、 亚洲语言文件
俄、希、土语言文件 (简、繁、日、朝)
从上图看,如果只想调用MODI接口,不需要应用层的支持,可以有以下选择:
- 直接调用ScanSoft API。这个比较有难度,至少我到目前为止还找不到相关文档。
- 还是调用MODI接口,至少这个的文档是公开的。
所以上面的问题就转换成了:能否抽取出支持MODI接口的最小集合,实现OCR接口功能?
身为资深技术人员,对于这种问题的回答当然不能胡言乱语,而应该以实验为基础:
1、搞一个干净的XP SP3虚拟机,再复制一份,姑且命名为“虚拟机A”、“虚拟机B”。
2、在虚拟机A中安装InstallRite 2.5,用它监视安装SharePoint Designer 2007中的MODI。
3、安装完成后,用InstallRite导出安装后新的注册表,命名为aaa.reg。
4、将虚拟机A中的两个文件夹
C:\Program Files\Common Files\Microsoft Shared\MODI
C:\Program Files\Common Files\Microsoft Shared\OFFICE12
复制到虚拟机B,并将aaa.reg导入虚拟机B。毕竟MODI接口是COM接口,与注册表无关的COM接口是不存在的。
5、运行DjVuToy、FreePic2Pdf或Pdg2Pic,可以验证在虚拟机B中能够用第三方软件正常OCR,只不过每OCR一页都要自动安装一次文件,似乎注册表中掺入了垃圾。
以上可行性实验清楚表明:
1、在不安装Office或SharePoint Designer的情况下,可以通过复制相关文件和注册表项,为第三方软件提供OCR支持。
2、对于简体中文来说,单独安装Office 2007中的MODI需要约1 GB硬盘空间,单独安装SharePoint Designer 2007中的MODI则需约650 MB,而上面两个文件夹加起来也只有约76 MB,何况中间还有水分可挤,空间的节省还是很可观的,所以这笔买卖做得过。
无聊但又必不可少的理论扯完了,下面开始进入实战:哪些文件和注册表项才是必不可少的?
先说文件。上面两个URL中的内容,其实已经说明了接口层中ScanSoft API所需的文件,剩下需要解决的就是MODI接口部分的文件。
在第三方软件中调用MODI接口的初始化代码为:
IDocument doc;
doc.CreateDispatch(_T("MODI.Document"));
在注册表中搜索字符串“MODI.Document”,可以知道此COM对象对应的DLL是MODI安装文件夹下的MDIVWCTL.DLL。再看一眼VC++的Debug窗口,可以知道在调用此DLL后,还接着调用了同文件夹下的MSPGIMME.DLL、MSPCORE.DLL,及OFFICE12文件夹下的MSO.DLL等。从文件属性看,这些文件都是微软鼓捣出来的,因此可以认为是接口层中MODI接口部分的东西。
从VC++的Debug窗口输出信息看,除了上述DLL文件外,OCR过程中还加载了MODI安装文件夹下的XOCR3.PSP、THOCR.PSP、XFILE.PSP。这3个文件虽然扩展名是PSP,但其实是DLL文件,从文件属性看属于ScanSoft API的范畴,可以看作是对上面两个URL中内容的补充。
另外VC++的Debug窗口中还记录到OCR过程调用了OFFICE12文件夹下的OGL.DLL、MSORES.DLL、2052\MSOINTL.DLL,但在后来的回归性测试中证明,在对注册表项进行简化后,这几个文件没有也没关系。
结合上面分析,及《用MODI OCR 21种语言》中的相关信息,可知要OCR简体中文、英语,至少需要的文件如下表所示,加一起也就约30 MB。其中“说明”部分的英文是从DLL文件的文件属性中复制过来的,中文是我自己加的;数据层的数据文件是用文件监视器抓取的。
层次 | 文件名 | 说明 | |
接口层 | MODI | MDIVWCTL.DLL | Microsoft Office Document Imaging Viewer Control |
MSPCORE.DLL | Microsoft® Office Document Imaging Object Library | ||
MSPGIMME.DLL | Microsoft® Gimme library | ||
OFFICE12\MSO.DLL | 2007 Microsoft Office component | ||
ScanSpft API |
BINDER.DLL | XDoc Binder module for the ScanSoft SDK | |
PSOM.DLL | Component Management Module for PefectScan API | ||
XIMAGE3B.DLL | Image Processing Module for the ScanSoft SDK | ||
XPAGE3C.DLL | Page Management Module for ScanSoft SDK | ||
XOCR3.PSP | OCR Module for ScanSoft SDK | ||
XFILE.PSP | Asian OCR Module for ScanSoft SDK | ||
THOCR.PSP | Asian OCR Module for ScanSoft SDK | ||
ScanSoft API亚洲 语言 |
FORM.DLL | Table Recognition for Asian OCR | |
REVERSE.DLL | Reverse Video Detection for Asian OCR | ||
THOCRAPI.DLL | Asian OCR API | ||
TWCUTCHR.DLL | Character Segmentation for Asian OCR | ||
TWCUTLIN.DLL | Line Segmentation for Asian OCR | ||
TWLAY32.DLL | Layout Analysis for Asian OCR | ||
TWORIENT.DLL | Orientataion Detection for Asian OCR | ||
TWRECC.DLL | Chinese Recognition for Asian OCR | ||
TWRECE.DLL | English Recognition for Asian OCR | ||
TWRECS.DLL | Punctuation Recognition for Asian OCR | ||
TWSTRUCT.DLL | Document Structure Processing for Asian OCR | ||
数据层 | 英文 | LATIN1.SHP | 西欧11国(含英文)通用特征库 |
CharSetTable.chr | 字符编码转换表,文本文件 | ||
ENGLISH.LNG | 英文语言文件 | ||
简体中文 | ENGDIC.DAT | 清华文通的英文字典文件,貌似它也支持中、英文 | |
ENGIDX.DAT | 清华文通的英文索引 | ||
JFONT.DAT | |||
LOOKUP.DAT | |||
OCRHC.DAT | |||
OCRVC.DAT | |||
TWGB32.DLL | Simplified Chinese code Conversion | ||
SCCODE.UNI | |||
SCPRINT.DAT | |||
SCPRINT2.DAT | |||
SCSERHT.DAT | |||
SCTREE.DAT | |||
TW_GU.DAT | |||
TW_UG.DAT |
如果还想增加对其他语言的OCR能力,可以参阅《用MODI OCR 21种语言》,增加相关语言对应的文件。
另外在上表中,在PSOM.DLL文件描述中出现了一个新的名字:PefectScan API。google了一下,找到其官网http://perfectscan.com/,从介绍上看是做图像处理的:
PerfectScan is an image processing program that automatically analyzes an image, then makes adjustments to that image rendering a black and white image that contains all viewable data as if it were a gray scale scan, only at 15% of the size of a gray scale image.
看来MODI还真是一个大杂烩。不过PefectScan官网上的一句话,感觉道尽了程序员的悲凉:
We built the software after 10 years of hard work, now all we have to do is build the website...OOPS!!
言归正传。搞定文件后,还需要搞定注册表项才行。与MODI相关的注册表项包括两个部分:COM相关与Office相关。
COM相关就是与MODI的COM组件相关的注册表项,这个直接用regsvr32导入即可:启动命令行,进入MODI安装文件夹,执行下面的命令:
regsvr32 MDIVWCTL.DLL
regsvr32 MSPCORE.DLL
即可完成MODI COM组件的注册。
但与Office相关的注册表项就没那么好搞定了。我曾经试过用注册表监视器对OCR过程进行监视,结果发现真相淹没在了细节的海洋里。最终不得不采用了一个笨办法:专门写了一套测试软件,在前面的可行性实验中搭建的虚拟机B里猛跑,逐一尝试删除从aaa.reg中导入的注册表项,每删除一项就检查一下对OCR会不会造成影响。最终试出来约20个注册表项是必不可少的,其中近一半与前面用regsvr32注册COM组件时自动插入的注册表项重复。
最终经过手工调整后,确认在上面表格所列文件及COM注册基础上,再增加下列注册表项即可正常用第三方软件在简体中文环境下OCR简体中文、英文:
[HKEY_CLASSES_ROOT\Installer\Components\61BA386016BD0C340BBEAC273D84FD5F]
"2052"=hex(7):76,00,55,00,70,00,41,00,56,00,53,00,2e,00,7d,00,58,00,25,00,21,\
00,21,00,21,00,21,00,21,00,4d,00,4b,00,4b,00,53,00,6b,00,4f,00,43,00,52,00,\
5f,00,32,00,30,00,35,00,32,00,3c,00,00,00,00,00
[HKEY_CLASSES_ROOT\Installer\Features\00002109F10040800000000000F01FEC]
"OCR_2052"=""
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\00002109F10040800000000000F01FEC\Features]
"OCR_2052"="%mEMae,7q9*DXdU@EPi="
[HKEY_CLASSES_ROOT\Installer\Products\00002109710000000000000000F01FEC]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\3F745FF6A76FF2F4797DB74FC7B3FD8B]
"00002109710000000000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\MODI\\12.0\\XPAGE3C.DLL"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\4080B9FA1A0BBF34FB7813E87159FC64]
"00002109F10040800000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\MODI\\12.0\\SCCODE.UNI"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\48AD0082D02B3D24C9A56FA50728CCAB]
"00002109710000000000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\MODI\\12.0\\MSPCORE.DLL"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\D94C8360B8BB1DC41B1950E0F8237563]
"00002109710000000000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\OFFICE12\\MSO.DLL"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\00002109710000000000000000F01FEC\InstallProperties]
"WindowsInstaller"=dword:00000001
前三项的语言编码2052对应简体中文,但只要文件不缺,OCR中文、英文或其他语言都没有问题。不过在面对其他国家的用户时,解释采用简体中文的语言编码还是有点费劲,所以仍然需要继续尝试其他语言编码。
把两个虚拟机复原,重复上面可行性实验步骤:在虚拟机A中监视安装英文版SharePoint Designer 2007(安装后支持英、法、西班牙语),导出安装后的注册表和文件到虚拟机B,用同一套测试软件进行检查,出来的是不是与英文语言编码1033相关的注册表项呢?错,大错特错,跑出来不能删的是与法语(语言编码1036)相关的注册表项:
[HKEY_CLASSES_ROOT\Installer\Components\61BA386016BD0C340BBEAC273D84FD5F]
"1036"=hex(7):76,00,55,00,70,00,41,00,56,00,57,00,3f,00,57,00,41,00,24,00,21,\
00,21,00,21,00,21,00,21,00,4d,00,4b,00,4b,00,53,00,6b,00,4f,00,43,00,52,00,\
5f,00,31,00,30,00,33,00,36,00,3c,00,00,00,00,00
[HKEY_CLASSES_ROOT\Installer\Features\00002109F100C0400000000000F01FEC]
"OCR_1036"=""
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\00002109F100C0400000000000F01FEC\Features]
"OCR_1036"=")aEMae,7q9*DXdU@EPi="
[HKEY_CLASSES_ROOT\Installer\Products\00002109710000000000000000F01FEC]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\3F745FF6A76FF2F4797DB74FC7B3FD8B]
"00002109710000000000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\MODI\\12.0\\XPAGE3C.DLL"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\48AD0082D02B3D24C9A56FA50728CCAB]
"00002109710000000000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\MODI\\12.0\\MSPCORE.DLL"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\C040B9FA1A0BBF34FB7813E87159FC64]
"00002109F100C0400000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\MODI\\12.0\\FRENCH.LNG"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\D94C8360B8BB1DC41B1950E0F8237563]
"00002109710000000000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\OFFICE12\\MSO.DLL"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\00002109710000000000000000F01FEC\InstallProperties]
"WindowsInstaller"=dword:00000001
对比两个结果,可以看出:
- 与语言相关的注册表项共4项,其他注册表项都是相同的。
- 与语言相关的注册表项前3项直接用语言编码标识,第4项用语言文件标识,简体中文的文件是SCCODE.UNI,法语是FRENCH.LNG。
- 与语言相关的注册表项键值不是随便乱起的,是在产品基本键值(SharePoint Designer的基本键值是00002109710000000000000000F01FEC)的基础上,叠加相关语言编码(简体中文语言编码2052,十六进制0804,Intel表示为0408;法语语言编码1036,Intel表示为0C04)。敢这么玩GUID的我就见过这么一个,别人似乎都没这胆子。
- 不管采用什么语言,都可以只有一种语言,但这种语言不能是英语(语言编码1033)。
为了验证第4点,我从虚拟机A中手工导出英语相关注册表项,在虚拟机B中把与法语相关的注册表项全部换成英语的,结果OCR失败。与英语相关的4个注册表项为:
[HKEY_CLASSES_ROOT\Installer\Components\61BA386016BD0C340BBEAC273D84FD5F]
"1033"=hex(7):76,00,55,00,70,00,41,00,56,00,54,00,28,00,38,00,41,00,24,00,21,\
00,21,00,21,00,21,00,21,00,4d,00,4b,00,4b,00,53,00,6b,00,4f,00,43,00,52,00,\
5f,00,31,00,30,00,33,00,33,00,3e,00,26,00,61,00,45,00,4d,00,61,00,65,00,2c,\
00,37,00,71,00,39,00,2a,00,44,00,58,00,64,00,55,00,40,00,45,00,50,00,69,00,\
3d,00,00,00,00,00
[HKEY_CLASSES_ROOT\Installer\Features\00002109F10090400000000000F01FEC]
"OCR_1033"=""
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\00002109F10090400000000000F01FEC\Features]
"OCR_1033"="&aEMae,7q9*DXdU@EPi=OFu[`t.WO9zoh+x^{BHE"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\9040B9FA1A0BBF34FB7813E87159FC64]
"00002109F10090400000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\MODI\\12.0\\ENGLISH.LNG"
因此对于国内的用户,直接上简体中文的注册表项就好;对于国外的用户,如果对简体中文解释起来比较麻烦,就上法语或其他语言的注册表项吧 。但注意一次只能上一种语言,而且不能是英语。如果在上了一种语言的注册表项的基础上,再画蛇添足上英语的注册表项,会有问题:由于前面对文件和注册表项进行了精简,在OCR时MODI组件如果发现有英文的注册表项, 就会尝试恢复被精简的文件,造成OCR速度缓慢。
当然不论是哪一种语言,在导入x64 Windows时,都要注意x64下32位软件对应的Program Files文件夹多了一个后缀,改叫Program Files (x86)了。另外在理论上Program Files文件夹也是可以不在C盘上的,所以最保险的方法是通过环境变量CommonProgramFiles、CommonProgramFiles(x86),或SHGetFolderPath等SDK函数获取实际文件夹名称。
另外一个容易被问到的问题是:貌似导入的注册表项中包含了文件路径,那么能不能通过改注册表项的方法,改变MODI的安装路径,不装到CommonProgramFiles文件夹下?答案是:不行。事实上,InstallRite 2.5导出的aaa.reg文件中的原始注册表项里,路径名中是含有非法字符(问号)的,但并不影响使用,所以我怀疑文件夹是被写死在MODI代码里的。
总之,上面说的都是在没有安装Office 2003/2007的情况下的不得已方法,如果已经装了,不仅节省不了多少空间,而且可能会出现文件或注册表项的冲突。
(完)
[转老马的文章]MODI中的OCR模块的更多相关文章
- MODI中的OCR模块
作者:马健邮箱:stronghorse_mj@hotmail.com发布:2012.07.02更新:2012.07.09补充非简体中文版内容 自从基于MODI的DjVuToy.FreePic2Pdf. ...
- [转自老马的文章]用MODI OCR 21种语言
作者:马健邮箱:stronghorse_mj@hotmail.com发布:2007.12.08更新:2012.07.09按照<MODI中的OCR模块>一文相关内容进行修订2012.07.0 ...
- 【温暖】文龙回AICODER给老马送锦旗了
又是一个愉快的周末,AICODER第一批老学员文龙小伙伴.已经工作两个月,而且就业薪资12000+,文龙从之前月薪不足4000,一下子翻了三倍多的工资. 几个月的实习,让文龙掌握了大前端全栈的技术,在 ...
- 【vue】跟着老马学习vue-数据双向绑定
学习了node.js教程,只能说是有了一定的了解,之前也了解了webpack和es6的核心内容,也看过vue2.0的官网教程,并结合视频看过项目,但是理解和运用仍然存在很多问题,接下来的一段时间,跟着 ...
- [MVC]如何删除文章内容中的图片
1.实现代码 if (!string.IsNullOrWhiteSpace(entity.Content)) { var immgList = TextHelper.GetImgUrlList(ent ...
- 【第1期】腾讯云的1001种玩法征集,Ipad mini和Kindle 等你拿!(文章评审中)
版权声明:本文由阁主的小跟班原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/695994001482226944 来源:腾云 ...
- Unity开发游戏 flapybird 无广告老马版分享
Flapybird确实是一款非常好玩的游戏,但是上手难度比较大.经过老马模仿加工,把游戏难度降低,而且不加入任何广告. 特此分享.下载地址:http://files.cnblogs.com/fly_d ...
- dede织梦栏目页和文章页中获取当前栏目名称方法
一般情况下,在dede织梦系统中列表页.栏目页和文章页中获取当前所在栏目名称只需要代码:{dede:type}[field:typename]{/dede:type}即可,不需要定义ID,默认的就是当 ...
- 关于IT学习的老马私人订制服务
各位寒门学子好,老马的前端教程发布以来,受到好多同学的关注.老马辛勤付出也收货了很多好评.在这非常感谢大家. 最近一段时间来,老马已经完成了html.css.css项目.js基础.js高级.dom与特 ...
随机推荐
- 常用的I/O流类型
1.I/O流类型基础.(类中方法和子类查看java spring API) 抽象类java.io.InputStream:是所有字节输入流的父类,定义了以字节为基本单位读取数据的基本方法 抽象类jav ...
- bash
unix - Unlimited Bash History - Stack Overflowhttp://stackoverflow.com/questions/9457233/unlimited-b ...
- svn权限控制
http://blog.csdn.net/clever101/article/details/8159105 [groups] #核心层开发组成员 core_dev = lg,zjc #扩展层开发组成 ...
- 161122、BOM 操作写法示例
浏览器相关信息 // 浏览器信息 navigator.userAgent // Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/ ...
- tomcat启动startup.bat一闪而过 转
遇到很多次运行startup.bat后,一个窗口一闪而过的问题,但是从来没去纠正怎样修改配置才是正确的,现在从网上查阅的资料整理如下:tomcat在启动时,会读取环境变量的信息,需要一个CATALIN ...
- Linux程序存储结构与进程结构堆和栈的区别【转】
转自:http://www.hongkevip.com/caozuoxitong/Unix_Linux/24581.html 红客VIP(http://www.hongkevip.com):Linux ...
- oracle 数据泵 每天自动备份
@echo off echo 删除10天前的备分文件和日志 forfiles /p "e:\app\back" /m *.dmp /d -5 /c "cmd /c del ...
- ExtJS的MessageBox总结
自己写了个ExtJS的MsgBox的小模版,以后遇到需要使用提示的地方就拿过来改改,免得每次都重新写. /**MsgBox start**/ Ext.Msg.buttonText.yes = &quo ...
- Binary Tree Level Order Traversal II
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode ...
- Perl的基本语法<总结> (转载)
前言:这篇文章是花了我很多时间.费了我很多心血才完成的,虽然连我自己都觉得无法达到尽善尽美的境界,但希望能帮助大家入门,稍微了解到Perl 到底是个什么样的东西,Perl到底有那些强大的功能,那么这篇 ...