答题卡图像识别项目

  • 2019 年 10 月 28 日
  • 筆記

市面上开源代码主要缺点

  • 代码里面都有选项距离等等相关硬参数,从而导致摄像头扫描或照片识别效率低下
  • 答题卡太简单,易于识别,但是实际使用中不可能有如此简单的答题卡,比如用HoughCircle检测圆形选项框,选项一多,直接坑爹
  • 答题卡太复杂,在答题卡上加了一堆定位图形,比如答题卡是3列20排,定位图形足足有23个,累死编制答题卡的人

所以,本项目基本上是市面上答题卡识别准确率最高的开源代码

整个流程如下,详细请看代码注释

  • 打开摄像头扫描答题卡,看,是这个挫样
  • 把这个比较挫的图片进行二值化腐蚀膨胀边缘检测,变成了这样,还是很挫
  • 计算轮廓,并且看最大轮廓是否具有4个顶点,如果有的话,就OK了
  • 纠偏,把斜的图片变正,看上去终于不挫了
  • 调整图片的亮度,方便二值化
  • 通过二值化膨胀腐蚀再二值化,获得涂写的区域
  • 通过二值化膨胀腐蚀,获得所有的选项框加题号区域
  • 依据面积大小和其他条件提取合适的轮廓,与涂写区域重叠
  • 依据轮廓左上角坐标从上而下排序轮廓,若1排有3题,每题4个选项,则认为前5个轮廓是第1题,其中第1个轮廓是题号,第6-10个轮廓是第2题,其中第6个轮廓是题号。
  • 根据提取的轮廓的左上角坐标和长宽,计算轮廓区域内的白点个数,白点个数低于某个阈值,初步认为是选择了该选项。

一、需求分析

一、以接口的方式开发此需求:

1:接收图片

以上传的方式把图片发送到接口。

2:识别图片

接口接收到图片后,进行图像识别。

3:返回数据

返回识别后的JSON格式数据。

二、答题卡图片识别的具体要求:

图片是通过手机、相机、扫描仪等设备拍照而来,其中手机、相机拍出的照片会出现像素低、图像不正、聚焦不清楚等问题;

1:图片只要是人眼能看清楚的即可完成识别; 2:800万像素以上的手机拍的照片能进行识别; 3:聚焦不清楚时也可以进行识别;

4:不符合要求的图片可以不识别,一旦识别,正确率必须保证100%。

三、其他要求:

1:此项目验收需要提供答题卡识别的所有源代码、接口说明文档。

2:接口需支持单张图片上传识别以及多张图片的上传识别。

3:接口使用的开发语言及开发工具不限。

四、需求分析:

这是一个典型的“机器视觉”应用。其中,答题卡的样式可以是由自己来设置的,图片的获取方式提到了可以是“手机拍照、相机拍照”这种比较方便的方式;本例的一个特殊的要求是:你可以识别不出来,但是你不能识别错误,这是项目的特殊要求

五、需求分析:

普通的答题卡是这样的:

用于机器识别的答题卡是这样的,最明显的区别在于在边界处提供了用于标定的黑边。由于这里的答题卡是可以自己来设计的,就应该设计得最适合识别:

经过我修改的答题卡是这样的,主要是用圆点进行边界标定,因为在旋转和缩放的情况下,圆点都有更好的性能:

二、市场分析

答题卡已经出现好多年了,而且教育机构也是容易出现壁垒的领域。经过简单调查,制式的答题机应该是这种样子的,这种答题机采用的应该特殊的成像技术,比如红外之类的,否则也不需要做成这种样子:

其价格在数千元到万元左右,淘宝上也有人做出了机器识别的例子:

采用普通摄像头和特定的支架,销售情况不好。

但是,图像确是多种多样的。

形式多样。值得关注的一点是,这些能够通过baidu直接搜索得到的答题卡在设计上和本文提供的答题开有两点比较大的不同,一个是在取消了比如圆点这样的标定点,二个是在横版面上采用了“点画”的方式进行标定

这样能够得到的结果还是使得答题卡更加的简洁,美观。

对于这个市场,我认为在网络和即时聊天工具更加发达的今天,答题卡作为一种非常正式的考试方法,还是有其市场的(比如高考中考,短时间内还不会出现直接采用移动设备进行答卷);但是专门去做一套这样的设备,市场已经基本饱和,而且教育市场的壁垒应该很高,不是很容易就能够进入的。但是,对于在日常非正式考试中需要答题卡相关设备,而不希望担负一套昂贵的专业系统的人或单位来所,如果能够以一种比较低廉的价格,并且已一种比较方便操作的方式(比如直接利用手机,或普通相机)进行实现,应该是有一定的市场的。

三、技术实现

本例的技术难度不是很大,非常关键的一点是由于卡片是可以由自己来设计的。而且图像的获取也比较容易被优化。这里以最前面的图片进行设计分析,其他的例子情况可以以此类推;并且公布核心代码。

1)仿照实际的情况,对原始图片进行相关处理。在实际拍摄的时候,可能会出现“缩放”、“透视变化”等影响最终实际结果的情况:

变小

透视变化

同时透视和缩放

2)编写获取锚点(就是圆点)的函数. FetchAnchorPoints函数的主要过程是将输入的图片划分为四个部分,并且分别找到其中的圆点。参数中mattmp是模板图片,也就是哪个小圆的图片。

获得的结果

3)采用warpPerspective进行透视变换.

这一步得到的校正图像:

4)对原始图像进行裁剪

找到的结果用圆点标注出来

这里下面一排第一个圆点没找到,这是原始模板图像在设计的时候出现的问题,因为这里只是说明原理,我就没有修改。

7)架设照相机,获取实际图片

做到这一步,下面就是要获得实际的图片并进行识别了。我采用的方法是将答题卡用打印机打印出来,然后用相机拍摄下来,注意一下光照,效果如下:

照片还是比较模糊的,识别后达到预期效果。注意模板识别之前首先需要把图片缩放一下,否则效果不会太好。

照片还是比较模糊的,识别后达到预期效果。注意模板识别之前首先需要把图片缩放一下,否则效果不会太好。

Mat matsrc = imread("C:/answercard/r4.jpg",0); resize(matsrc,matsrc,Size(600,500)); FetchAnchorPoints(matsrc,mattmp,anchor01,anchor02,anchor03,anchor04);

效果如此。

采用2b铅笔进行填卡,效果如下

进行阈值分析后,效果很差

可以发现,采用2b铅笔,如果采用图像识别的方法的话,光照的影响还是非常大的。

接着改用黑色铅笔(钢笔也可以)

则特征明显

8)对获取的结果进行计算。也就是图片到数据的一个量化的过程。

具体来说,就是将这样的图像

量化成为选择结果,思路也是非常直接的,就是对比最右侧的标尺值和实际获得的值。在编写具体代码的时候,可能还要加上一定的修正,并且要尽可能保证这个修正是鲁棒的。

今天,随着机器视觉算法的不断发展、移动通信设备的不断发展,解决这种问题有了新的思路和新的市场空间。