Python答题卡识别并给出分数的实现代码


Posted in Python onJune 22, 2021

  哈喽大家好,这里是滑稽研究所。看过我们图像处理系列的朋友,应该知道识别答题卡那期文章。其中利用opencv框架,完美的实现了答题卡填涂区域的识别。在后台有小伙伴想要我完善一下判断选项对错并打分的功能,本期我们就来实现一下。
  那么我们来复习一下往期的代码原理。我们需要对图片素材进行灰度化处理、透视变换、轮廓检测、腐蚀膨胀处理、区域分割、边框计算、区域计算。实际上我们是通过像素面积的过滤、填涂区域优化和获取选项坐标来完成答题卡的识别的。
素材:

Python答题卡识别并给出分数的实现代码

  那么在获取到答题卡的填涂区域之后就好办了。我们首先分隔答题卡,去除干扰项,然后把不同的区域打上标签。我们的答题卡是自上而下排序的。那么我们获取到的填涂项的x坐标即横坐标就派上了用场。选项A~E一定是占据了五个不同的区域。我们已经为不同区域打上了标签。剩下的就是交给我们的if判断语句了。这时我们已经为填涂项赋上了实际的意义。即从像素坐标转换成了具有实际意义的选项。
  那y坐标就没有用了吗?非也。经过上面的处理我们只是得到了填涂区域对应的选项。但是我们还没有进行排序。大家知道无序的选项是没有意义的。而刚刚我们说了该答题卡的题号顺序是自上而下的。因为我们遍历选项时,是同时得到x、y坐标的,因此我们可以保证得到的坐标是配对的。
  其中横纵坐标分别填入两个list中,然后使用zip方法合并list。这时我们再按照每个list的第二个元素也就是纵坐标进行由小到大的排序,就可以得到正确的顺序。
  这时我们才真正获取到了需要的数据。即考生填涂的选项顺序,我们再新建一个list放正确的答案,与考生的答案进行对比,经计算得出考生的正确率,并给出分数。
  好,思路清晰,上代码!

import cv2
import numpy as np

path = './test_01.png'
img = cv2.imread(path)

imgGray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
imgBlur = cv2.GaussianBlur(imgGray,(3,3),1)
imgCanny = cv2.Canny(imgBlur,100,120)

cv2.imshow("O", imgCanny)

imgContour = img.copy()

cnts = cv2.findContours(imgCanny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
for cnt in cnts:
    area = cv2.contourArea(cnt)
    # 这个输出各个轮廓的面积
    #print(area)
#
if area >= 500:
    cv2.drawContours(imgContour, cnt, -1, (255, 0, 0), 3)
    peri = cv2.arcLength(cnt, True)
    # 找出轮廓的突变值
    approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
    # approx找到的是一个轮廓有几个突变值,有几个角就会有几个突变值
    # 返回的是一个list,输出他的长度,就可以知道到底有几个角
    #print(approx)
    a1,a2,a3,a4 = list(approx[0][0]),list(approx[1][0]),list(approx[2][0]),list(approx[3][0])

#cv2.imshow("Canny Image",imgContour)

mat1 = np.array([a1,a2,a3,a4],dtype=np.float32)

#透视变换
#计算矩形宽高
width = 402#int(((a4[0]-a1[0])+(a3[0]-a2[0]))/2)
height = 518#int(((a2[1]-a1[1])+(a3[1]-a4[1]))/2)

#计算还原后的坐标
new_a1 = [0,0]
new_a2 = [0,height]
new_a3 = [width,height]
new_a4 = [width,0]

mat2 = np.array([new_a1,new_a2,new_a3,new_a4],dtype=np.float32)
#计算变换矩阵
mat3 = cv2.getPerspectiveTransform(mat1,mat2)

#进行透视变换
res = cv2.warpPerspective(imgCanny,mat3,(width,height))
res1 = cv2.warpPerspective(img,mat3,(width,height))

imgxx = cv2.cvtColor(res1,cv2.COLOR_BGR2GRAY)
binary = cv2.threshold(imgxx,0,255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU )[1]
#变换完成
#cv2.imshow("Output",res1)

cntss = cv2.findContours(res, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
for cnt1 in cntss:
    area1 = cv2.contourArea(cnt1)
    # 这个输出各个轮廓的面积
    #print(area)
#
    if area1 >= 1500 and area1<=1700:
        #把圆的轮廓画成黑色
        cv2.drawContours(binary, cnt1, -1, (0, 0, 0), 10)

        kernel = np.ones((5, 5), np.uint8)
        imgDialation = cv2.dilate(binary, kernel, iterations=1)

cv2.imshow("Out", imgDialation)

cntsss = cv2.findContours(imgDialation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]

l1 = []
l2 = []
l3 = ['B','E','A','D','B']

for cnt2 in cntsss:
    area2 = cv2.contourArea(cnt2)
            #print(area)

    if area2 <= 1200 and 800<=area2:
                #cv2.drawContours(res1, cnt, -1, (0, 255, 0), 5)
                #轮廓长
        peri = cv2.arcLength(cnt2, True)
                # 找出轮廓的突变值
        approx1 = cv2.approxPolyDP(cnt2, 0.02 * peri, True)

        x, y, w, h = cv2.boundingRect(approx1)
                #外接矩形
        #print(x+w//2,y+h//2)

        m = x+w//2
        n = y+h//2
        l1.append(m)
        l2.append(n)
        #拼接两个一维列表,使x,y坐标配对。
        mix1 = list(zip(l1,l2))
        #按列表第二个元素升序,即按y值由小到大排列。
        #这是我们得到的答案为正确顺序。
        mix1.sort(key=lambda x: x[1])

        if 400>x>80 and 50<y<350:
            cv2.rectangle(res1, (x, y), (x + w, y + h), (0, 0, 255), 2)
            #圆心
            # (图像,x.y位置,半径,颜色,轮廓粗细)
            cv2.circle(res1, (x+w//2,y+h//2), 1, (255, 0, 0), 5)

l4 = []
for i in mix1:
    if 75 < i[0] < 130:
        print("A")
        l4.append('A')
    elif 130 < i[0] < 185:
        print("B")
        l4.append('B')
    elif 185 < i[0] < 240:
        print("C")
        l4.append('C')
    elif 240 < i[0] < 295:
        print("D")
        l4.append('D')
    elif 295 < i[0] < 350:
        print("E")
        l4.append('E')

print('正确答案:',l3)
print('考生答案',l4)


h = 0
for i in range(0, len(l3)):
    if l3[i] == l4[i]:
        h=h+1
print('得分:',str(h/5*100)+'分')

cv2.imshow("cc Image",res1)

cv2.imshow("dd Image",binary)

cv2.waitKey(0)

运行结果:

Python答题卡识别并给出分数的实现代码
Python答题卡识别并给出分数的实现代码

  以上为两个图片素材的运行结果,我们只放出其中一部分。剩余的素材大家自行实验。
  可以看到,程序成功的识别了考生填涂的答题卡,并给出了考生答案、正答案和考生最后的得分。
  综上功能实现,任务完成。大家学会了吗?

以上就是Python识别答题卡并给出分数的详细内容,更多关于Python识别答题卡的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
以windows service方式运行Python程序的方法
Jun 03 Python
python实现用户管理系统
Jan 10 Python
python实现监控某个服务 服务崩溃即发送邮件报告
Jun 21 Python
Python文件监听工具pyinotify与watchdog实例
Oct 15 Python
python得到一个excel的全部sheet标签值方法
Dec 10 Python
使用python3实现操作串口详解
Jan 01 Python
10 分钟快速入门 Python3的教程
Jan 29 Python
python 用for循环实现1~n求和的实例
Feb 01 Python
django admin.py 外键,反向查询的实例
Jul 26 Python
基于opencv实现简单画板功能
Aug 02 Python
python opencv通过4坐标剪裁图片
Jun 05 Python
python全面解析接口返回数据
Feb 12 Python
Python 中的单分派泛函数你真的了解吗
Jun 22 #Python
Python实现DBSCAN聚类算法并样例测试
python中sqllite插入numpy数组到数据库的实现方法
Jun 21 #Python
利用Python第三方库实现预测NBA比赛结果
Django实现drf搜索过滤和排序过滤
python生成可执行exe控制Microsip自动填写号码并拨打功能
详解Python自动化之文件自动化处理
Jun 21 #Python
You might like
在服务端进行目录建立、删除,文件上传、删除的过程的php代码
2008/09/10 PHP
PHP向socket服务器收发数据的方法
2015/01/24 PHP
php自定义函数实现二维数组排序功能
2016/07/20 PHP
详解Laravel设置多态关系模型别名的方式
2019/10/17 PHP
JQuery右键菜单插件ContextMenu使用指南
2014/12/19 Javascript
JavaScript获得url所有参数键值表的方法
2015/03/21 Javascript
jQuery实现html表格动态添加新行的方法
2015/05/28 Javascript
AngularJS 日期格式化详解
2015/12/23 Javascript
iscroll.js的上拉下拉刷新时无法回弹的解决方法
2016/02/18 Javascript
JavaScript Date对象详解
2016/03/01 Javascript
JavaScript事件详细讲解
2016/06/27 Javascript
Vuejs第九篇之组件作用域及props数据传递实例详解
2016/09/05 Javascript
使用 vue-i18n 切换中英文效果
2018/05/23 Javascript
vue路由守卫及路由守卫无限循环问题详析
2019/09/05 Javascript
JavaScript Canvas编写炫彩的网页时钟
2019/10/16 Javascript
对Python random模块打乱数组顺序的实例讲解
2018/11/08 Python
python实现推箱子游戏
2020/03/25 Python
Python使用MyQR制作专属动态彩色二维码功能
2019/06/04 Python
记录Python脚本的运行日志的方法
2019/06/05 Python
Python计算不规则图形面积算法实现解析
2019/11/22 Python
python 实现单通道转3通道
2019/12/03 Python
Python利用Pillow(PIL)库实现验证码图片的全过程
2020/10/04 Python
Python实现随机爬山算法
2021/01/29 Python
CSS3用@font-face实现自定义英文字体
2013/09/23 HTML / CSS
Woods官网:加拿大最古老、最受尊敬的户外品牌之一
2020/09/12 全球购物
材料加工硕士生求职信
2013/10/10 职场文书
应届生法律顾问求职信
2013/11/19 职场文书
三年级科学教学反思
2014/01/29 职场文书
《藤野先生》教学反思
2014/02/19 职场文书
国企干部对照检查材料
2014/08/22 职场文书
村长党的群众路线教育实践活动个人对照检查材料
2014/09/23 职场文书
党的群众路线教育实践活动调研报告
2014/11/03 职场文书
2014年学生资助工作总结
2014/12/18 职场文书
2015年上半年物业工作总结
2015/03/30 职场文书
学会掌握自己命运的十条黄金法则:
2019/08/08 职场文书
react 路由Link配置详解
2021/11/11 Javascript