前言
本人今年主要在负责猿题库 iOS 客户端的开发,本文旨在通过分享猿题库 iOS 客户端开发过程中的技术细节,达到总结和交流的目的。
这是本技术分享系列文章的第二篇。本文涉及的技术细节是:答题卡扫描算法。
问题描述
我们在调研用户需求的时候,发现有些用户很喜欢我们的猿题库产品,因为我们会根据用户对当前课程的知识点掌握情况,智能地给他出题。但是部分用户还是习惯在纸上做题,所以我们提供了试卷打印功能。
但是,用户如果在纸上答题,无法方便地将答案上传到我们的服务器上。如果我们没有了用户做题数据,就无法根据他的成绩,做针对性的推荐和分析。所以,我们想到一种办法: 用户像传统考试那样,将答题结果填涂在答题卡上,然后我们提供一种用手机摄像头采集填涂结果的答题卡扫描算法,方便用户上传答题数据。
上图是一个我们试验用的答题卡,通过手机摄像头获取,从中可以看到,该答题卡有以下问题:
- 由于手机摄像头无法完全正对答题卡,拍照角度有偏曲,答题卡在拍照后并不是完全的矩形。
- 用户填涂区域可能并不饱满和完整。
- 答题纸边缘可能有用户的草稿或其它干扰识别的信息。
技术解决方案
我们尝试了多种识别方案,最终采用的方案如下:
- 图象预处理,压缩图像大小,转彩色图像为灰度图像
- 识别答题卡区域
- 图象纠偏
- 答案区域识别
该方案及相关算法细节我们还在申请专利,由于专利还在申请过程中,所以我们这次仅展示上述主要步骤的示例图片。等专利完全申请结束后,我会在此将算法细节公开。
上述主要步骤的示例图如下:
原始图
识别答题卡区域
图象纠偏
答案区域识别
答案已标注在图片每个题号的右边位置:
算法质量
算法正确率和召回率
我们用收集来的 1000 套样本数据对算法进行评测,最终结果是:扫描题目准确率达到 99.67%,召回率达到 99.14%。主要识别失败的样本是:页面严重扭曲弯折的答题卡。我们也在一直改进算法,希望能够给用户提供更加精准的扫描结果。
算法执行时间
我们觉得让用户直接对着答题卡用拍摄的方式动态识别,比先拍一张照片再识别的方式更加方便。所以我们对答题卡识别算法的执行时间进行了一系列优化,最终保证每次识别时间小于 0.1 秒,这样的识别时间非常快,基本上用户把手机摄像头对准答题卡,扫描结果就出来了。
算法的调试和移植
由于我们整个技术团队都使用 Mac 电脑进行开发,所以我们对于算法的调试都是在 Mac 平台上完成的,我使用了开源的图象处理库 OpenCV,在搭建 OpenCV 环境时遇到一些问题,最终完成环境搭建后,我将相关的经验总结在博文 《在 MacOS 和 iOS 系统中使用 OpenCV》 中。
由于算法需要同时应用在 iOS 和 Android 平台,所以我主要用 C++ 语言实现算法。Xcode 可以很好地支持 Objective-C 语言和 C++ 语言混编,只需要将相关的源文件扩展名从 .m 改为 .mm 即可。而 Android 平台所采用的 Java 语言,也支持通过 JNI 的方式来调用 C++ 的代码。这样就可以方便地将识别算法移植到手机中了。
总结
本文介绍了猿题库 iOS 客户端采用的答题卡扫描算法的大致步骤,以及算法的质量和移植方案。