我们经常使用表单识别和处理解决各种各样的任务,包括分类、文档归档、OCR识别和光学标记(OMR)识别。基于OMR表单创建的时间稍长和准确检测扫描文档中OMR字段的比较困难,使得OMR在文档图像中经常被误解且没有被充分利用。创建和处理OMR表单非常耗时,此白皮书将讨论如何通过自动检测、分类和处理缓解这些问题。
大多数表单使用少量的OMR字段捕捉信息,如性别和婚姻状况。这几乎没什么困难,因为处理的字段非常少。另一方面,创建和处理多项选择题为主体的表单非常困难,因为大量的字段会出现在一个页面里。此外,复选框、气泡和其他尺寸很小类型的OMR字段,造成了潜在的问题,会导致更多的错误结果。
下面,我们将为您详细讲解如何使用LEADTOOLS创建一个OMR表单识别应用程序来缓解这两个常见问题。这个备受殊荣的图像SDK包含了所有必须的工具,将省时、程序员友好的API与最精准的识别率结合,最终解决方案的质量将达到一个无与伦比的水平。
使用LEADTOOLS OCR在主表单中添加OMR字段
表单识别应用程序的第一步是创建主表单。这些主表单或空白的表单模板有两个主要作用。第一,使用它们确定扫描文档表单的类型。第二,字段表明了表单中数据识别和提取的区域。对许多系统来说,创建一个基于OMR的表单非常繁琐,因为它包含了很多重复的选择框。手动绘制每一个字段非常耗时。值得庆幸的是,LEADTOOLS的IOcrEngine.AutoZone方法可以自动检测所有OMR字段。在页面中找到每个区域后,你可以在集合中循环,为每一个OMR区域添加一个新的OMR字段。
FormPages formPages = currentMasterForm.ReadFields();// 创建 OCR 引擎
using (IOcrEngine ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.Advantage, false)){ocrEngine.Startup(null, null, null, null);ocrEngine.SettingManager.SetEnumValue("Recognition.Zoning.Options", "Detect Text,Detect Graphics, Use Text Extractor, Detect Checkbox");
using (IOcrDocument ocrDocument = ocrEngine.DocumentManager.CreateDocument())
{// 自动分区
ocrDocument.Pages.AddPages(rasterImageViewer1.Image, 1, 1, null);
ocrDocument.Pages.AutoZone(OcrZoneParser.Leadtools, OcrZoneFillMethod.Omr,LogicalUnit.Pixel, 0, 0, null);
// 为每一个OMR区域添加一个表单列表
FormField newField;IOcrZoneCollection zones = ocrDocument.Pages[0].Zones;for (int i = 0; i < zones.Count; i++){if (zones[i].FillMethod == OcrZoneFillMethod.Omr)
{newField = new OmrFormField();
newField.Bounds = zones[i].Bounds;newField.Name = string.Format("OMR Field {0}", i);formPages[oldSelectedPageIndex].Add(newField);}}}currentMasterForm.WriteFields(formPages);}
图1:OMR字段检测后的主表单
OCR引擎的AutoZone方法获取每一个区域的位置,但是有很多方法命名它们。这个简单的例子为所有区域起了一个基本名称,但可以检查FormField.Bounds属性决定哪些区域在相同的行或列,通过此方法扩展这个逻辑,更智能的命名区域。此外,你还可以使用主表单编辑器示例或手动编辑存储字段数据的XML文件。
使用LEADTOOLS表单识别和处理
大多数扫描文档处理系统必须能够处理多种表单类型。一个可行的低效率解决方案可能针对不同类型的表单使用不同的应用程序、按钮或对框。这可以实现自动化的数据处理,但并非全自动,它需要手动通知应用程序使用哪个表单模板处理扫描图像。最佳的解决方案是自动识别或分类表单,然后基于这些发现处理。LEADTOOLS提供了可靠灵活的大量分类数据的表单识别能力,包括logo、黑白区域、OCR、条码等。
// 为机器上的每一个处理器创建一个OCR引擎。允许在识别和处理过程中优先使用线程。
ocrEngines = new List<IOcrEngine>();
for (int i = 0; i < Environment.ProcessorCount; i++){ocrEngines.Add(OcrEngineManager.CreateEngine(OcrEngineType.Advantage, false));
ocrEngines[i].Startup(formsCodec, null, String.Empty, String.Empty);
}// 将资源库指向包含已有主表单的文件夹
formsRepository = new DiskMasterFormsRepository(formsCodec, masterFormsFolder);
autoEngine = new AutoFormsEngine(formsRepository, ocrEngines, null,AutoFormsRecognitionManager.Default | AutoFormsRecognitionManager.Ocr, 30, 80, true);
string[] formsToRecognize = Directory.GetFiles(filledFormsFolder);
progressBar1.Maximum = formsToRecognize.Length;for (int i = 0; i < formsToRecognize.Length; i++){// 识别(分类)表单
lblStatus.Text = string.Format("Recognizing form {0} of {1}", i + 1,formsToRecognize.Length);AutoFormsRunResult runResult = autoEngine.Run(formsToRecognize[i], null);
if (runResult != null){// 识别成功
lblStatus.Text = string.Format("Processing form {0} of {1}", i + 1,formsToRecognize.Length);ProcessResults(runResult);}progressBar1.Value++;}
从完整的OMR表单中提取答案
一旦表格识别成功,就可以处理字段,从填好的文档中提取OMR数据。选择OMR解决方案的一个重要考虑因素是如果准确处理填写风格的差异。尽管在填写表单时有严格的规定,但是每个人填写OMR字段的方法都各不相同。
图2:填写OMR字段的差异
如果你还记得图1,你会发现字段以问题编号和列编号命名,中间用连字符分隔。有了这样的命名模式,我们就可以轻松确定每列中填写了哪个复选框,然后将它添加到我们的数据源中。
int nNewRowIndex = dataGridView1.Rows.Add();
foreach (FormPage formPage in runResult.FormFields){foreach (FormField field in formPage){if (field.Result.GetType() == typeof(OmrFormFieldResult)){// 填写复选框了吗?
if ((field.Result as OmrFormFieldResult).Text == "1"){// 获取这个复选框的问题编号和值(列标号)
string[] strQuestionValue = field.Name.Split('-');
dataGridView1.Rows[nNewRowIndex].Cells[string.Format("col{0}",strQuestionValue[0])].Value = strQuestionValue[1];}}}}
图3:完整识别的结果
当然有很多方法可以命名字段并将答案与你的数据源关联。在应用程序的开始阶段你可以小小的计划一下,使用LEADTOOLS根据任意的主表单和数据源设计你自己的OMR表单识别解决方案,这个解决方案可靠、灵活且准确。
获取支持
关于其他产品的更多信息,请访问我们的官方网站,
欢迎下载免费的全功能评估版SDK,全功能试用版中有这个例子的全部源代码。
同时欢迎您使用评估版期间的免费技术支持。