在文档图像处理领域,分类、文档归档、光学字符识别(OCR)和光学标记识别(OMR)是一些常见的任务。尽管这些技术在文档扫描和处理中占有重要地位,但OMR常因设置表单的复杂性和准确检测表单上哪些字段被填写的难度而被误解和低估。创建和处理OMR表单可能会非常耗时,本文将探讨如何通过自动化检测、分类和处理来减轻这些问题。
大多数表单包含少量的OMR字段,如性别和婚姻状况,这些字段处理起来相对容易。然而,当表单主要由多项选择题组成时,创建和处理这些表单的难度显著增加,因为一页上可以包含大量的字段。此外,复选框、圆点等OMR字段的尺寸较小,可能导致过度敏感,从而产生更多的误判。
为了缓解上述常见问题,将详细探讨如何开发一个OMR表单识别应用。LEADTOOLS是一个获奖的图像处理软件开发工具包(SDK),它包含了创建高质量解决方案所需的所有工具,结合了节省时间的API和最先进的识别准确性及速度。
表单识别应用的第一步是构建主表单。这些主表单或空白表单模板有两个主要目的:首先,用于识别扫描文档的类型;其次,字段指示表单上将识别和提取数据的区域。
FormPages formPages = currentMasterForm.ReadFields();
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);
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);
}
OCR引擎的AutoZone方法用于获取每个区域的位置,但命名这些区域的方法有很多。这个简单的例子为区域提供了一个基础名称,但可以通过检查FormField.Bounds属性来扩展这个逻辑,以更智能地命名区域,确定哪些区域在同一行或列中。此外,可以使用主表单编辑器演示或手动编辑存储字段数据的XML文件。
大多数扫描文档处理系统必须处理不止一种类型的表单。一个可行但效率低下的解决方案可能是为每种需要处理的表单使用不同的应用程序、按钮或对话框。这确实可以自动化数据处理,但需要手动告知应用程序使用哪个表单模板来处理扫描图像。一个更优的解决方案是表单可以自动被识别或分类,然后根据这些发现进行处理。LEADTOOLS提供了可靠和灵活的表单识别能力,包括徽标、明暗区域、OCR、条形码等多种形式的分类数据。
List ocrEngines = new List();
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字段的填充方式仍会有所不同。LEADTOOLS在OMR准确性方面表现出色,可以区分填充和未填充的框,无论填充样式如何。
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];
}
}
}
}
自然,有很多方法可以命名字段并将答案与数据源相关联。在应用程序的初始阶段进行一些规划,可以围绕任何主表单和数据源设计OMR表单识别解决方案,以实现可靠、灵活且最重要的是准确的解决方案。
可以下载包含上述功能的完整功能演示。要运行此示例,需要以下内容:
将附加的ZIP项目解压缩到LEADTOOLS C#示例目录(例如C:\LEADTOOLS 18\Examples\DotNet\CS)。