在教育领域,答题卡(Optical Mark Recognition, OMR)是一种常见的评估工具,用于标准化考试和问卷调查。传统的OMR系统需要专用的阅读机和扫描仪来识别答题卡上的信息。然而,随着技术的发展,现在可以通过智能手机相机和计算机软件来实现这一功能,从而节省了购买昂贵设备的需要。本文将介绍一种新的OMR引擎,它能够使用3MP及以上的自动对焦手机相机来读取答题卡。
在寻找一个合适的OMR引擎时,发现市场上现有的解决方案并不能满足需求。因此,决定自己开发一个。在传统的学校和大学中,通常会使用专业的机器来读取答题卡。目标是消除购买OMR阅读机的需要,甚至是扫描仪。通过使用3MP手机相机拍摄的照片,就可以通过这个引擎来读取答题卡。在初始阶段,已经创建了自己的答题卡类型,可以被读取。
图像处理部分使用了AForge.Net的图像处理器(下载中包含的库)。这种方法的核心在于,它能够从扫描的图像中识别出答题卡的边界。这是通过寻找答题卡上的四个交叉圆形符号来实现的,这些符号定义了纸张的边界,从而估计出裁剪、缩放和倾斜纸张的信息。
Q1: 这个引擎可以与其他OMR答题卡一起使用吗? 很多人反复提出了相同的问题:“可以使用其他OMR答题卡与这个引擎一起使用吗?”答案是“不可以”。原因是因为用于提取纸张图像的算法ExtractPaperFromFlattened()。它通过在扫描图像中找到四个交叉圆形符号来识别出纸张。如果没有这些符号,就无法检测到纸张。
Q2: 可以创建自己的OMR答题卡吗? 在V1版本中,不能。至少在没有帮助的情况下,除非是一个超级极客。在V2版本中,可以。
在添加了所有引用(AForge和OMR)之后,可以使用最简单的方法重载来从相机/扫描仪图像中提取OMR封装的答题卡。原始图像必须包含一个清晰的支持答题卡格式的视图(可打印的PDF包含在下载中)。例如:
C#
Bitmap unf = new Bitmap(panel1.BackgroundImage);
OpticalReader reader = new OpticalReader();
panel1.BackgroundImage = (System.Drawing.Image)reader.ExtractOMRSheet(unf, "sheets.xml", OMREnums.OMRSheet.A550);
一旦答题卡被提取出来,就可以使用以下方法进行处理:
OpticalReader rr = new OpticalReader();
MessageBox.Show(rr.getRegNumOfSheet(panel1.BackgroundImage, OMREnums.OMRSheet.A550, "sheets.xml", false).ToString());
检测答题卡的过程涉及到检测答题卡的角。在打印的文档中,角被特定的二进制图像标记。检测它们,就检测到了答题卡。首先,需要使用正确的对比度、填充、阈值和反转过滤器来平整图片。作为起点,原始图像在没有对比度、亮度或填充校正的情况下被反转。给定一个阈值,图像然后被转换为二进制。这个图像被称为“平整图像”,是通过使用"OMR.OpticalReader.flatten"方法获得的。
一旦图像被平整出来,就开始进行块检测。在第一阶段,从最小块大小开始检测所有大小和类型的块(这确保移除了噪声颗粒块)。首先检测到左边,然后检测到答题卡的右边。在第一阶段过滤器中,通过检查它们的大小与相机/扫描仪图像的大小比例来过滤掉错误大小的块。在第二个过滤器中,过滤掉放置在图像错误一侧的块。在第三个过滤器中,过滤掉具有疯狂错误长宽比的块(确保检测并拒绝由答题卡上的弯曲/线条产生的块)。作为对块的最后一个过滤器,所有块都与镜像角图像进行比较(镜像是因为在第一步中反转了图像)。过滤掉的块再次被验证,它们确实是四个,并且放置在答题卡的正确位置上。同时,左右边缘的长度变化不大。
经过验证的块代表了图像坐标系统中答题卡角的真实位置。可以通过这些点从未平整的图像中裁剪出图像,并包装成一个完美的矩形图像,称为OMR答题卡。如果上述所有过滤器只产生四个角块,那么过程就会继续,否则将对同一个函数进行递归调用,使用相同的参数,但使用改变的对比度校正,可能会得到更好的结果值。
查看"OMR.OpticalReader.ExtractOMRSheet"方法中的代码,并逐行注释。
主要的图像处理在于图像提取部分。现在下一个阶段是读取OMR答题卡。通常OMR答题卡对一个问题有多个选择。所有相同问题的选项都打印在纸张的一侧,形成一个“块”。所有块的位置、大小和给出的选项数量都足够保存到XML文件中。位置是根据坐标系统记录的,通常是.NET中遵循的,即左上角为O(0,0)(x,y)+ive x轴向右,+ive y轴向下。
要读取答题卡中的特定块(在第一部分中提取的答题卡),可以调用OMR.OpticalReader.getScoreOfSheet。这个方法反复执行上述程序,读取答题卡上所有4个大答案块上的所有线条。
当一个多项选择块从文档中切出来时,是时候读取选定的选择。对于读取,块被划分为与其中存在的选项数量相等的部分。然后,图像根据块的平均颜色被转换为二进制。这就是将白纸转换为纯白,将超过一半的墨水填充像素转换为纯黑的方式。记录每个块的黑色像素计数。
将最暗的块与其它块进行比较,如果两个子块之间存在显著差异,较暗的一个被记录为“标记”。根据标记选择的数量,可以决定哪个选项被选中。