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 相关文章推荐
Python使用Scrapy爬虫框架全站爬取图片并保存本地的实现代码
Mar 04 Python
tensorflow 1.0用CNN进行图像分类
Apr 15 Python
python3.6.3安装图文教程 TensorFlow安装配置方法
Jun 24 Python
详解python中的线程与线程池
May 10 Python
如何使用Python实现自动化水军评论
Jun 26 Python
如何使用Python自动控制windows桌面
Jul 11 Python
python的mysql数据库建立表与插入数据操作示例
Sep 30 Python
如何分离django中的媒体、静态文件和网页
Nov 12 Python
python GUI库图形界面开发之PyQt5多行文本框控件QTextEdit详细使用方法实例
Feb 28 Python
python使用Thread的setDaemon启动后台线程教程
Apr 25 Python
Pytorch高阶OP操作where,gather原理
Apr 30 Python
python实现图片九宫格分割的示例
Apr 25 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小技巧之JS和CSS优化工具Minify的使用方法
2014/05/19 PHP
PHP浮点数精度问题汇总
2015/05/13 PHP
ThinkPHP防止重复提交表单的方法实例分析
2018/05/10 PHP
Laravel框架自定义公共函数的引入操作示例
2019/04/16 PHP
PHP $O00OO0=urldecode &amp; eval 解密,记一次商业源码的去后门
2020/09/13 PHP
JS location几个方法小姐
2008/07/09 Javascript
Javascript中的isNaN函数使用说明
2011/11/10 Javascript
js对象内部访问this修饰的成员函数示例
2014/04/27 Javascript
jQuery实现Div拖动+键盘控制综合效果的方法
2015/03/10 Javascript
javascript解决小数的加减乘除精度丢失的方案
2016/05/31 Javascript
关于JavaScript 原型链的一点个人理解
2016/07/31 Javascript
AngularJS基础 ng-hide 指令用法及示例代码
2016/08/01 Javascript
AngularJs bootstrap搭载前台框架——准备工作
2016/09/01 Javascript
浅谈jQuery双事件多重加载的问题
2016/10/05 Javascript
BootStrap Validator对于隐藏域验证和程序赋值即时验证的问题浅析
2016/12/01 Javascript
jQuery加密密码到cookie的实现代码
2017/04/18 jQuery
详谈Angular 2+ 的表单(一)之模板驱动型表单
2017/04/25 Javascript
vue监听scroll的坑的解决方法
2017/09/07 Javascript
详解使用Visual Studio Code对Node.js进行断点调试
2017/09/14 Javascript
Redux 和 Mobx的选择问题:让你不再困惑!
2017/09/18 Javascript
浅谈angular4实际项目搭建总结
2017/12/01 Javascript
vue+springmvc导出excel数据的实现代码
2018/06/27 Javascript
echarts同一页面中四个图表切换的js数据交互方法示例
2018/07/03 Javascript
解决layer弹出层msg的文字不显示的问题
2019/09/11 Javascript
js实现小星星游戏
2020/03/23 Javascript
使用python的chardet库获得文件编码并修改编码
2014/01/22 Python
Python中字典的setdefault()方法教程
2017/02/07 Python
python使用正则表达式替换匹配成功的组并输出替换的次数
2017/11/22 Python
快速了解Python开发中的cookie及简单代码示例
2018/01/17 Python
python实现低通滤波器代码
2020/02/26 Python
Django的ListView超详细用法(含分页paginate)
2020/05/21 Python
Three Graces London官网:英国奢侈品牌
2021/03/18 全球购物
Java里面Pass by value和Pass by Reference是什么意思
2016/05/02 面试题
优秀高中生事迹材料
2014/02/11 职场文书
四年级作文之说明文作文
2019/10/14 职场文书
mysql 生成连续日期及变量赋值
2022/03/20 MySQL