目录

1  项目介绍

2  代码分析

2.1  导入库

2.2  设置参数

2.3  设置正确答案

2.4  定义找到四个角点的函数

2.5  定义变换函数

2.6  定义 sort_contours()

2.7  定义展示函数 cv_show()

2.8  图像滤波

2.9  边缘检测

2.10  整体轮廓检测

2.11  处理轮廓

2.12  透视变换

2.13  二值处理

2.14  寻找轮廓并画出来

2.15  提取答题卡上的答案

2.16  对比正确答案

2.17  计算其余信息

3  新了解的方法


1  项目介绍

现在我有一张写好答案的答题卡并且我有一组答案

opencv答题卡检测批改 答题卡识别判卷_灰度图

为我们把正确的结果标出来,然后得出正确率

opencv答题卡检测批改 答题卡识别判卷_opencv_02

2  代码分析

2.1  导入库

opencv答题卡检测批改 答题卡识别判卷_python_03

2.2  设置参数

opencv答题卡检测批改 答题卡识别判卷_python_04

2.3  设置正确答案

第0行的答案的B,第1行的答案是E,第2行的答案是A,第3行的答案是D,第4行的答案是B

opencv答题卡检测批改 答题卡识别判卷_opencv_05

2.4  定义找到四个角点的函数

  • 我觉得这个并不是很科学,我在该专栏的 11.提取图像内容区域 做过更改,我们可以使用我改过的函数

opencv答题卡检测批改 答题卡识别判卷_透视变换_06

2.5  定义变换函数

在该专栏的 11.提取图像内容区域 有讲过,就不赘述了

opencv答题卡检测批改 答题卡识别判卷_python_07

2.6  定义 sort_contours()

这个是排序用的 在该专栏的 11.银行卡号识别 有讲过

opencv答题卡检测批改 答题卡识别判卷_opencv答题卡检测批改_08

2.7  定义展示函数 cv_show()

opencv答题卡检测批改 答题卡识别判卷_透视变换_09

2.8  图像滤波

读取图片后复制一张,然后将原图转为灰度图,之后对其进行布尔滤波,然后展示出来

opencv答题卡检测批改 答题卡识别判卷_透视变换_10

opencv答题卡检测批改 答题卡识别判卷_python_11

2.9  边缘检测

opencv答题卡检测批改 答题卡识别判卷_opencv答题卡检测批改_12

opencv答题卡检测批改 答题卡识别判卷_透视变换_13

2.10  整体轮廓检测

opencv答题卡检测批改 答题卡识别判卷_灰度图_14

opencv答题卡检测批改 答题卡识别判卷_opencv答题卡检测批改_15

2.11  处理轮廓

opencv答题卡检测批改 答题卡识别判卷_opencv_16

首先我们定义一个docCnt,这个变量用来存放我们轮廓的内容,之后如果我们检测到了轮廓就进入分支,进入分支后将轮廓按面积大小排序,之后遍历排序好的每一个轮廓对其进行轮廓近似(将每一个轮廓搞成多边形,大概是这样的),如果我近似后的结果多余四边形就将该轮廓近似后的结果赋值给docCnt()

opencv答题卡检测批改 答题卡识别判卷_python_17

我们下面看一下近似前与近似后的轮廓

  • 近似前

opencv答题卡检测批改 答题卡识别判卷_python_18

opencv答题卡检测批改 答题卡识别判卷_python_19

  • 近似后

opencv答题卡检测批改 答题卡识别判卷_opencv_20

opencv答题卡检测批改 答题卡识别判卷_opencv_21

可以看出来是差不多的,我们后面的遍历与近似是为了让代码也能更好的匹配别的图像

我们看一下docCnt的内容

opencv答题卡检测批改 答题卡识别判卷_opencv答题卡检测批改_22

opencv答题卡检测批改 答题卡识别判卷_透视变换_23

2.12  透视变换

刚刚我们得到的docCnt就是内容区域的轮廓,现在我们使用docCnt提取图像内容(进行透视变换),首先我么们把docCnt降一维变成(4,2),然后执行four_point_transform()提取图像内容

opencv答题卡检测批改 答题卡识别判卷_灰度图_24

opencv答题卡检测批改 答题卡识别判卷_python_25

2.13  二值处理

处理之后复制一张处理过的图片

opencv答题卡检测批改 答题卡识别判卷_opencv_26

opencv答题卡检测批改 答题卡识别判卷_灰度图_27

2.14  寻找轮廓并画出来

opencv答题卡检测批改 答题卡识别判卷_opencv_28

opencv答题卡检测批改 答题卡识别判卷_opencv答题卡检测批改_29

由于图像是二值化的图像所以我们看不出来是红色,我们现在把轮廓在image上画验证一下

opencv答题卡检测批改 答题卡识别判卷_opencv答题卡检测批改_30

opencv答题卡检测批改 答题卡识别判卷_灰度图_31

  • 这个只是验证灰度图上画轮廓不显示红色,在刚刚灰度图中画的轮廓不是上图红色的样子

2.15  提取答题卡上的答案

  • 如果答题卡涂成一个圆,我们也可以用霍夫变换来检测圆,但如果涂的不像是一个圆就没有办法检测出来了,下面这个图右边可以检测出来,左边这个检测不出来

opencv答题卡检测批改 答题卡识别判卷_opencv_32

首先我们创建一个空的列表用于存储 答题卡上答案 的轮廓

opencv答题卡检测批改 答题卡识别判卷_opencv答题卡检测批改_33

遍历图中的所有轮廓,对轮廓进行矩形近似,之后算出矩形的宽高比ar,之后进入判定,如果宽>=20,高>=20,宽高比在0.9-1.1之间,我们将轮廓加入questionCnts,这样我们就能筛选出来所有圈的轮廓了

opencv答题卡检测批改 答题卡识别判卷_透视变换_34

之后使用上面定义的sort_contours对轮廓进行从上到下排序

opencv答题卡检测批改 答题卡识别判卷_灰度图_35

我们现在看一下questionCnts,很长我就只截取头和尾了

opencv答题卡检测批改 答题卡识别判卷_灰度图_36

opencv答题卡检测批改 答题卡识别判卷_灰度图_37

opencv答题卡检测批改 答题卡识别判卷_python_38

然后定义correct用于记录正确的个数

opencv答题卡检测批改 答题卡识别判卷_透视变换_39

下面涉及到了np.arange()这个方法,我们举个例子

import numpy as np
a = np.arange(3)
print(a)
print(type(a))

a = np.arange(1,5)
print(a)
print(type(a))

a = np.arange(1,5,2)
print(a)
print(type(a))

opencv答题卡检测批改 答题卡识别判卷_opencv_40

上面是三种加入参数的方式

  • 直接写一个整形进去,这样就会生成一个内容为从0到n-1的numpy.ndarray
  • 写两个整形进去,这样会生成内容为从a到b的numpy.ndarray
  • 写三个整形进去,这样会生成内容为从a到b,步长为c的numpy.ndarray

回到我们的代码,我们此时做了一个循环

opencv答题卡检测批改 答题卡识别判卷_python_41

q是我们np.arange的结果从0到25,步长为5,q的取值范围为[0,5),i是enumerate给的序号,一共25个,所以i的取值范围为[0,25)

进入循环后,把每5个圆形轮廓归为一堆,并以默认的方法排序(从左到右)这样我们就得出了一行的圆形轮廓,然后将bubble置为none

opencv答题卡检测批改 答题卡识别判卷_python_42

然后我们再上面的循环中进入一个小循环,这个循环是遍历我们同一行的轮廓,我们先用enumerate()对同一行的轮廓进行标号

opencv答题卡检测批改 答题卡识别判卷_透视变换_43

之后我们创建全0(黑)掩膜,大小与图像内容大小图片相同,之后在mask上把轮廓画出来,第一个-1是全部都画出来(由于是遍历的,所以只有一个),第二个-1是填充,把轮廓内的值都置为255(白色),然后展示出来

一共展示25次,我们展示一下前几次的什么样子的

opencv答题卡检测批改 答题卡识别判卷_python_44

opencv答题卡检测批改 答题卡识别判卷_python_45

然后我们使用mask对图自身做与运算,这样可以把选中的答案筛选出来,涂过的会比没涂过的非0值更多,之后我们使用检测出非零值个数,如果多就覆盖掉,少就下一轮,这样我们就选出来了一行中涂过的答案轮廓

opencv答题卡检测批改 答题卡识别判卷_opencv答题卡检测批改_46

2.16  对比正确答案

之后我们小循环就结束了,然后定义一个红颜色,之后把正确答案赋值给k

opencv答题卡检测批改 答题卡识别判卷_opencv答题卡检测批改_47

  • ANSWER_KEY 我们之前定义过,是内容为正确答案的字典

如果判断正确,我们将颜色改为绿色,然后correct(正确数量)+1

opencv答题卡检测批改 答题卡识别判卷_灰度图_48

然后把该轮廓画出来

opencv答题卡检测批改 答题卡识别判卷_opencv_49

2.17  计算其余信息

score是答题卡的得分,对一个20分,然后终端显示出来,之后在图上画出来,然后展示原图与最终的结果进行对比

opencv答题卡检测批改 答题卡识别判卷_透视变换_50

由于我们搞的是灰度图,所以颜色就显示不出来了

opencv答题卡检测批改 答题卡识别判卷_灰度图_51

opencv答题卡检测批改 答题卡识别判卷_透视变换_52

如果我们要把颜色搞出来我们应该把图像的颜色通道变为3条,首先在大循环前复制,然后转换

opencv答题卡检测批改 答题卡识别判卷_opencv答题卡检测批改_53

然后在img上画

opencv答题卡检测批改 答题卡识别判卷_opencv答题卡检测批改_54

在img上写

opencv答题卡检测批改 答题卡识别判卷_opencv答题卡检测批改_55

展示img

opencv答题卡检测批改 答题卡识别判卷_python_56

opencv答题卡检测批改 答题卡识别判卷_透视变换_57

3  新了解的方法

np.arange() 生成内容为顺序整形的numpy.ndarray