OpenCV实现答题卡自动打分!

目录

1,主要原理以及函数介绍

全部代码,以

2 , 实现过程

3,结果展示


1,主要原理以及函数介绍

ap = argparse.ArgumentParser()

创建一个ArgumentParser对象,并将其赋值给变量ap。这个对象可以接受我们的脚本的命令行参数,从而实现根据命令行参数执行不同的操作。

ap.add_argument("-i", "--image", required=True,help="path to the input image")

添加一个命令行参数-i/--image,并指定它是必需的,用户必须提供一个图像路径作为输入。

args = vars(ap.parse_args())

解析命令行参数并将它们存储在args字典中

ANSWER_KEY = {0: 1, 1: 4, 2: 0, 3: 3, 4: 1}

定义一个字典,其中包含每道题目的正确答案。键是问题的索引、值是正确答案的编号

def order_points(pts):

定义函数order_points,用于按照指定顺序找到四个坐标点

def four_point_transform(image, pts):

定义函数four_point_transform,用于执行透视变换。

透视变换是一种在图像处理领域中常用的变换方式,它可以将一个平面上的图像投影到一个新的视平面上。透视变换通常用于纠正图像中的透视畸变,例如将斜着拍摄的照片转换为正常的平面视图。在透视变换中,图像中的平行线可能会变成不平行线,而原本不平行的线可能会变成平行线。函数four_point_transform就是利用四个特定的点来确定透视变换矩阵,并对输入的图像进行透视变换。

def sort_contours(cnts, method="left-to-right"):

定义函数sort_contours,用于对轮廓进行排序

def cv_show(name,img):

定义函数cv_show,用于显示图像。

image = cv2.imread(args["image"]):

读取输入的图像,并将其存储在变量image中

contours_img = image.copy():

复制图像,用于在图像上绘制轮廓

cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1]

查找图像中的轮廓,使用外部轮廓检查模式(RETR_EXTERNAL)只检测外部轮廓,使用简单的轮廓逼近算法(CHAIN_APPROX_SIMPLE)来减少点数。返回值是一个元组,其中第二个元素表示轮廓列表

cv2.drawContours(contours_img,cnts,-1,(0,0,255),3)

将找到的轮廓绘制在图像上,颜色为红色

docCnt = None

初始化docCnt变量,用于存储找到的四个坐标点

if len(cnts) > 0:

如果找到了轮廓,则执行以下操作

cnts = sorted(cnts, key=cv2.contourArea, reverse=True)

对轮廓根据其面积大小进行排序,从大到小排列

peri = cv2.arcLength(c, True)     计算轮廓周长

approx = cv2.approxPolyDP(c, 0.02 * peri, True)

使用迭代逼近算法获取轮廓的近似形状。如果近似的轮廓拥有四个顶点,则将其作为找到的四个坐标点。

if len(approx) == 4:  如果找到了四个坐标点,则将它们保存到docCnt变量中,并跳出循环。

warped = four_point_transform(gray, docCnt.reshape(4, 2))

对图像进行透视变换,将找到的四个坐标点映射到新的矩阵中

thresh = cv2.threshold(warped, 0, 255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]

对变换后的图像进行二值化处理,使用Otsu's自适应阈值处理算法来获取最优阈值。返回值是一个元组,其中第二个元素是处理后的图像。

hresh_Contours = thresh.copy()

复制处理后的图像,用于在上面绘制轮廓

cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[1]

查找处理后图像中的轮廓,并使用RETR_EXTERNAL和CHAIN_APPROX_SIMPLE参数。

cv2.drawContours(thresh_Contours,cnts,-1,(0,0,255),3)

将找到的轮廓绘制在二值化图像上

cv_show('thresh_Contours',thresh_Contours)

调用cv_show函数,显示绘制轮廓后的图像

questionCnts = []:初始化questionCnts列表。

for c in cnts::遍历所有轮廓:

(x, y, w, h) = cv2.boundingRect(c):获取表示轮廓区域位置和大小的矩形。

ar = w / float(h):计算矩形的宽高比。

if w >= 20 and h >= 20 and ar >= 0.9 and ar <= 1.1::如果矩形满足指定的条件,则将其添加到questionCnts列表中。

questionCnts = sort_contours(questionCnts,method="top-to-bottom")[0]:对questionCnts列表中的轮廓按照从上到下的顺序进行排序。for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):对每一行问题进行处理。cnts = sort_contours(questionCnts[i:i + 5])[0]:对每个问题中的五个选项进行排序。bubbled = None:初始化变量bubbled,用于保存所选答案。for (j, c) in enumerate(cnts)::遍历每个选项。mask = np.zeros(thresh.shape, dtype="uint8") :创建一个全黑图像,大小与thresh相同。cv2.drawContours(mask, [c], -1, 255, -1):绘制选项的轮廓。mask = cv2.bitwise_and(thresh, thresh, mask=mask):将二值化图像thresh与mask相乘,只保留交集部分。total = cv2.countNonZero(mask):计算非零像素的数目,用于判断是否选择了这个选项。if bubbled is None or total > bubbled[0]::如果之前没有选择过或者当前选择的像素数更多,则更新选择。bubbled = (total, j):将当前选择的像素数以及选项索引保存到bubbled变量中。color = (0, 0, 255):初始化颜色为红色。k = ANSWER_KEY[q]:获取当前问题的正确答案。if k == bubbled[1]::如果当前选项是正确的,则将颜色设置为绿色,并增加正确计数器。color = (0, 255, 0)
correct += 1cv2.drawContours(warped, [cnts[k]], -1, color, 3):将选项的轮廓绘制在变换后的图像上,颜色为正确或错误的颜色。score = (correct / 5.0) * 100:计算得分。print("[INFO] score: {:.2f}%".format(score)):输出得分。cv2.putText(warped, "{:.2f}%".format(score), (10, 30),cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2):在变换后的图像上绘制得分。cv2.imshow("Original", image):显示原始图像。cv2.imshow("Exam", warped):显示处理结果。cv2.waitKey(0):等待用户按下任意键。

全部代码,以

2 , 实现过程

  1. 导入所需的库和模块:首先导入numpy、argparse、imutils和cv2等库,用于进行科学计算、命令行参数解析、图像处理和机器视觉任务。

  2. 解析命令行参数:使用argparse库创建ArgumentParser对象,并添加一个命令行参数-i/--image,要求用户提供一个输入图像的路径。然后使用ap.parse_args()方法解析命令行参数,并将结果存储在args字典中。

  3. 定义正确答案字典:创建一个字典,其中包含每道题目的正确答案编号。

  4. 函数定义:定义了四个函数,分别用于找到四个坐标点、执行透视变换、对轮廓进行排序以及显示图像。

  5. 读取输入图像:使用cv2.imread()函数读取输入的图像,并将其存储在变量image中。

  6. 图像预处理:将图像转换为灰度图像,然后应用高斯模糊以平滑边缘并减少噪声。接下来使用Canny算法进行边缘检测,得到二值化的边缘图像。

  7. 查找轮廓:使用cv2.findContours()函数查找图像中的轮廓,并使用外部轮廓检查模式(RETR_EXTERNAL)只检测外部轮廓,使用简单的轮廓逼近算法(CHAIN_APPROX_SIMPLE)来减少点数。获取到的轮廓存储在cnts变量中。

  8. 找到答题卡区域:遍历轮廓,计算轮廓周长和近似形状,并通过一系列条件判断找到包含答题卡的轮廓。将找到的四个坐标点保存到docCnt变量中。

  9. 执行透视变换:使用four_point_transform()函数对图像进行透视变换,将找到的四个坐标点映射到新的矩阵中。

  10. 对变换后的图像进行二值化处理:使用Otsu's自适应阈值处理算法对图像进行二值化处理,得到二值化的图像。

  11. 查找轮廓:使用cv2.findContours()函数再次查找处理后图像中的轮廓,并使用RETR_EXTERNAL和CHAIN_APPROX_SIMPLE参数。

  12. 处理每个问题的选项:遍历每个问题所在的行,对该行中的五个选项进行处理。首先对选项进行排序,然后使用遍历的方式计算每个选项中非零像素的数量,根据数量确定是否选择了该选项,同时记录最多选择的选项和其索引。

  13. 计算得分:根据正确的选项数量和总题数计算得分,同时输出得分。

  14. 显示结果:在变换后的图像上绘制得分,并显示原始图像和处理结果。

  15. 等待用户按下任意键结束程序。

3,结果展示

高斯滤波后结果

边缘检测结果

图像轮廓检测结果:

透视变换结果:

二值化处理结果:

mask,只保留交集部分

遍历每一个结果,计算非零像素的数目,用于判断是否选择了这个选项

计算的得分并显示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/103638.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

gitbook使用

文章目录 前言一、安裝Node.js&#xff1a;二、安裝GitBook&#xff1a;編輯和創建內容&#xff1a;安装typora 前言 ubuntu20.04系统 一、安裝Node.js&#xff1a; 打開終端機&#xff08;Terminal&#xff09;。 使用以下命令來安裝Node.js和npm&#xff08;Node.js的包管…

Vulnhub系列靶机---Raven: 2

文章目录 信息收集主机发现端口扫描目录扫描用户枚举 漏洞发现漏洞利用UDF脚本MySQL提权SUID提权 靶机文档&#xff1a;Raven: 2 下载地址&#xff1a;Download (Mirror) 信息收集 靶机MAC地址&#xff1a;00:0C:29:15:7F:17 主机发现 sudo nmap -sn 192.168.8.0/24sudo arp…

攻防世界题目练习——Web引导模式(二)

题目目录 1. Web_php_unserialize2. supersqli3. web24. NewsCenter5. Web_python_template_injection6. catcat-new 1. Web_php_unserialize 题目源码&#xff1a; <?php class Demo { private $file index.php;public function __construct($file) { $this->file …

FPGA project : flash_read

实验目标&#xff1a; flash的普通读指令&#xff0c;在指定地址开始读。可以更改地址与读的数据个数。 先发送读指令扇区地址页地址字节地址。 然后读数据。再把读到的串行数据转化为8bit的数据&#xff0c;存入fifo。 然后读出FIFO中数据&#xff0c;通过uart_tx模块发送…

Redis分布式锁最牛逼的实现(Java 版,最牛逼的实现方式)

写在前面的话 分布式锁一般有三种实现方式&#xff1a;1. 数据库乐观锁&#xff1b;2. 基于Redis的分布式锁&#xff1b;3. 基于ZooKeeper的分布式锁。 本篇博客将介绍第二种方式&#xff0c;基于Redis实现分布式锁。 为什么需要分布式锁&#xff1f; 在单机环境下编写多线…

【使用 TensorFlow 2】03/3 创建自定义损失函数

一、说明 TensorFlow 2发布已经接近5年时间&#xff0c;不仅继承了Keras快速上手和易于使用的特性&#xff0c;同时还扩展了原有Keras所不支持的分布式训练的特性。3大设计原则&#xff1a;简化概念&#xff0c;海纳百川&#xff0c;构建生态.这是本系列的第三部分&#xff0c;…

Python数据挖掘项目实战——自动售货机销售数据分析

摘要&#xff1a;本案例将主要结合自动售货机的实际情况&#xff0c;对销售的历史数据进行处理&#xff0c;利用pyecharts库、Matplotlib库进行可视化分析&#xff0c;并对未来4周商品的销售额进行预测&#xff0c;从而为企业制定相应的自动售货机市场需求分析及销售建议提供参…

2、vscode c++ 项目配置调试及运行

文章目录 1、项目布局2、多项目管理2.1 先是一个总的CMakeLists.txt2.2 每个项目2.3 多版本OPENCV 3、调试和运行 接上一篇文章&#xff0c;vscode和cmake的c环境配置好以后&#xff0c;我们要写项目&#xff0c;再写对应的CMakeLists.txt 1、项目布局 . ├── bin ├── bu…

jmeter实现webservice接口测试

其实可以用jmeter两种sampler进行webservice的测试&#xff1a; 1、SOAP/XML-RPC Request(但是在jmeter3.2以后版本中已经取消了这个取样器) 2、HTTP请求 下面分别介绍两种方式 一、首先需要使用soupUI工具抓取webservice接口的部分需要的信息。 1、新建项目 2、新建成功的…

怎么修改linux的root@后面的名称

文章目录 场景.登录服务器,root后面的名称是随机的,想自定义名称建议,直接使用命令执行需要重启机子 场景.登录服务器,root后面的名称是随机的,想自定义名称 建议,直接使用命令执行 hostnamectl set-hostname rdd-test重新连接即可生效,实际也是修改了/etc/hostname名称 需要…

十三、前端开发知识快速入门

目录 一、HTML概述和基本结构1.1 概述1.2 基本结构1.3 html文档类型1.4 html注释 二、HTML常用标签2.1 块标签2.2 行内标签2.3 字符实体2.4 图片标签2.5 链接标签2.6 列表标签2.7 表单2.8 表格 三、页面布局四、CSS样式4.1 基本语法和页面引用4.2 文本样式设置4.3 颜色表示法4.…

中国陆地生态系统服务价值空间分布数据集

简介&#xff1a; 中国陆地生态系统服务价值空间分布产品是以全国陆地生态系统类型遥感分类为基础&#xff0c;生态系统类型包括&#xff1a;旱地、农田、针叶林、针阔混交林、阔叶林、灌木林、草原、灌草丛、草甸、湿地、荒漠、裸地、水系、冰川积雪、人工表面&#xff08;包…

B端产品需求分析的思路和方法 4大方面

需求分析对产品成功和客户满意度至关重要&#xff0c;它帮助团队深入了解用户需求&#xff0c;优化用户体验&#xff0c;减少开发中的需求变更&#xff0c;降低开发风险。如果缺乏产品分析&#xff0c;容易造成产品定位不准确&#xff0c;用户体验不佳&#xff0c;不能满足用户…

迷你Ceph集群搭建(超低配设备)

我的博客原文链接&#xff1a;https://blog.gcc.ac.cn/post/2023/%E8%BF%B7%E4%BD%A0ceph%E9%9B%86%E7%BE%A4%E6%90%AD%E5%BB%BA/ 环境 机器列表&#xff1a; IP角色说明10.0.0.15osdARMv7&#xff0c;512M内存&#xff0c;32G存储&#xff0c;百兆网口10.0.0.16clientARM64…

【C语言】atoi函数的模拟

atoi对于初学者来说大概率是一个陌生的函数 但不要害怕&#xff0c;我们可以通过各种网站去查询 例如&#xff1a; cplusplus就是一个很好的查询网站 目录 函数介绍模拟实现需要注意的点 函数介绍 我们发现这是一个将字符串转换为整形数字的函数 例如&#xff1a; int main()…

C++类和对象(下)

目录 一、初始化列表 二、单参构造参数和explicit关键字 三、匿名对象 四、static成员 五、友元 六、内部类 一、初始化列表 之前我们在构造函数中写得还不错&#xff0c;也没发现什么问题&#xff0c;为什么C还有搞一个初始化列表呢&#xff1f; 如下这段代码&#x…

FPGA project : sobel

实验目标&#xff1a; sobel算法&#xff0c;处理100X100灰度图像&#xff1a;野火logo 边缘检测&#xff1a; 边缘检测&#xff0c;针对的是灰度图像&#xff0c;顾名思义&#xff0c;检测图像的边缘&#xff0c;是针对图像像素点的一种计算&#xff0c;目的是标识数字图像…

vue3学习(二)--- ref和reactive

文章目录 ref1.1 ref将基础类型和对象类型数据转为响应式1.2 ref()获取id元素1.3 isRef reactive1.1 reactive()将引用类型数据转为响应式数据&#xff0c;基本类型无效1.2 ref和reactive的联系 toRef 和 toRefs1.1 如果原始对象是非响应式的就不会更新视图 数据是会变的 ref …

点燃市场热情,让产品风靡全球——实用推广策略大揭秘!

文章目录 一、实用推广策略的重要性1. 提高产品知名度和认可度2. 拓展产品市场和用户群体3. 增强企业品牌形象和市场竞争力 二、实用推广策略的种类1. 社交媒体推广2. 定向推广3. 口碑营销4. 内容推广 三、实用推广策略的实施步骤1. 研究目标用户和市场需求&#xff0c;明确产品…

大数据NoSQL数据库HBase集群部署

目录 1. 简介 2. 安装 1. HBase依赖Zookeeper、JDK、Hadoop&#xff08;HDFS&#xff09;&#xff0c;请确保已经完成前面 2. 【node1执行】下载HBase安装包 3. 【node1执行】&#xff0c;修改配置文件&#xff0c;修改conf/hbase-env.sh文件 4. 【node1执行】&#xf…