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 , 实现过程
-
导入所需的库和模块:首先导入numpy、argparse、imutils和cv2等库,用于进行科学计算、命令行参数解析、图像处理和机器视觉任务。
-
解析命令行参数:使用argparse库创建ArgumentParser对象,并添加一个命令行参数-i/--image,要求用户提供一个输入图像的路径。然后使用ap.parse_args()方法解析命令行参数,并将结果存储在args字典中。
-
定义正确答案字典:创建一个字典,其中包含每道题目的正确答案编号。
-
函数定义:定义了四个函数,分别用于找到四个坐标点、执行透视变换、对轮廓进行排序以及显示图像。
-
读取输入图像:使用cv2.imread()函数读取输入的图像,并将其存储在变量image中。
-
图像预处理:将图像转换为灰度图像,然后应用高斯模糊以平滑边缘并减少噪声。接下来使用Canny算法进行边缘检测,得到二值化的边缘图像。
-
查找轮廓:使用cv2.findContours()函数查找图像中的轮廓,并使用外部轮廓检查模式(RETR_EXTERNAL)只检测外部轮廓,使用简单的轮廓逼近算法(CHAIN_APPROX_SIMPLE)来减少点数。获取到的轮廓存储在cnts变量中。
-
找到答题卡区域:遍历轮廓,计算轮廓周长和近似形状,并通过一系列条件判断找到包含答题卡的轮廓。将找到的四个坐标点保存到docCnt变量中。
-
执行透视变换:使用four_point_transform()函数对图像进行透视变换,将找到的四个坐标点映射到新的矩阵中。
-
对变换后的图像进行二值化处理:使用Otsu's自适应阈值处理算法对图像进行二值化处理,得到二值化的图像。
-
查找轮廓:使用cv2.findContours()函数再次查找处理后图像中的轮廓,并使用RETR_EXTERNAL和CHAIN_APPROX_SIMPLE参数。
-
处理每个问题的选项:遍历每个问题所在的行,对该行中的五个选项进行处理。首先对选项进行排序,然后使用遍历的方式计算每个选项中非零像素的数量,根据数量确定是否选择了该选项,同时记录最多选择的选项和其索引。
-
计算得分:根据正确的选项数量和总题数计算得分,同时输出得分。
-
显示结果:在变换后的图像上绘制得分,并显示原始图像和处理结果。
-
等待用户按下任意键结束程序。
3,结果展示
高斯滤波后结果

边缘检测结果

图像轮廓检测结果:

透视变换结果:

二值化处理结果:

mask,只保留交集部分

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



计算的得分并显示

相关文章:
OpenCV实现答题卡自动打分!
目录 1,主要原理以及函数介绍 全部代码,以 2 , 实现过程 3,结果展示 1,主要原理以及函数介绍 ap argparse.ArgumentParser() 创建一个ArgumentParser对象,并将其赋值给变量ap。这个对象可以接受我们的脚…...
Python编程必备:掌握列表遍历的6种神级技巧!
更多资料获取 📚 个人网站:涛哥聊Python 遍历列表是Python中最常见的任务之一,因为列表是一种非常常用的数据结构,它用于存储一组项目。 在编程中,经常需要对这些项目进行操作,例如查找特定元素ÿ…...
nodejs+vue校园失物招领平台
失物人可以在该平台中发布自己的拾物信息,本毕业设计题目将设计与实现一个基于校园的非商业行为的网上校园失物招领平台。并给出自己附加的各项条件, 失物招领管理系统主要分为两个部分,涉及前台和后台,然后由失主通过校园失物招…...
leetcode做题笔记171. Excel 表列序号
给你一个字符串 columnTitle ,表示 Excel 表格中的列名称。返回 该列名称对应的列序号 。 例如: A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 ... 示例 1: 输入: columnTitle "A" 输出: 1示例 2: 输入: colu…...
SW曲面实体导出工程图
...
Docker的私有仓库部署——Harbor
Harbor 简介 一、什么是Harbor Harbor 是 VMware 公司开源的企业级 Docker Registry 项目, 其目标是帮助用户迅速搭建一个企业级的 Docker Registry 服务。 Harbor以 Docker 公司开源的 Registry 为基础, 提供了图形管理 UI 、基于角色的访问控制(Role…...
JavaScript反爬虫技巧详细攻略
在互联网时代,网站采取了各种手段来防止被爬虫抓取数据,其中最常见的就是JavaScript反爬虫技巧。本文将揭示一些常用的JavaScript反爬虫技巧,并提供一些实际操作建议,帮助您保护自己的爬虫免受检测和封禁。 1、为什么网站使用Java…...
C++基础入门学习笔记
问题1:什么是 C 中的多态?如何实现多态? 回答1:C 中的多态是指同一种类型的实体,可以在不同的情况下表现出不同的行为。实现多态的方式有两种:虚函数和模板函数。虚函数是在基类中声明为虚函数的函数&…...
手机cpu架构查看及armeabi、armeabi-v7a、arm64-v8a及x86等说明
一、如何查看cpu加购 winR,输入cmd 填下指令如下 adb shell getprop ro.product.cpu.abi 二、架构描述 1.armeabiv-v7a: 第7代及以上的 ARM 处理器。2011年15月以后的生产的大部分Android设备都使用它. 2.arm64-v8a: 第8代、64位ARM处理器,很少设备&a…...
node-sass报错,node16运行node14的项目
原来项目是node14的版本,现在用node16运行npm i 会报以下错误 node-sass4.14.1 postinstall: node scripts/build.js npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the node-sass4.14.1 postinstall script. npm ERR! This is probably not a problem with …...
在Linux中掌握不同的命令,让创建文件变得易如反掌
在Linux中创建一个新文件很简单,但也有一些令人惊讶和灵巧的技术。在本教程中,学习如何从Linux终端创建文件。 先决条件 访问命令行/终端窗口(Ctrl-Alt-F2或Ctrl-Alt-T) 具有sudo权限的用户帐户(对于某些文件/目录是可选的) 从命令行创建新的Linux文件 Linux的设计…...
iOS 14 YYAnimatedImageView加载图片失败处理
升级到iOS14,之前使用的YYimage框架全部不能正常显示图片,当然动态图正常显示,静态图无法显示; 原因是:14.0 系统调用了下面方法,YYAnimatedImageView没有正确处理 -(void)displayLayer:(CALayer )layer; 1 可以用以下…...
兴趣社如何搭建一个兴趣社区?
社交产品的本质是帮助用户提升社交的质量与效率,而兴趣则是找到本质的捷径。用户对兴趣社区的使用主要是围绕兴趣爱好,社交属性以及粉丝活动三个方向。对感兴趣的话题,用户天然有更强的分享讨论欲,更期待与人社交互动。“越垂直的…...
腾讯wifi码推广如何代理?方法详解!
腾讯wifi码推广是一种利用微信扫码连接商家wifi的方式,用户看完广告后就可以免费上网,而推广者则可以获得广告收益。 那么怎样代理腾讯wifi码推广呢? 答案是腾讯官方没有这个项目,那是怎么回事呢,腾讯wifi码正确的名称…...
linux下读取socket相关的系统调用总结
recv 函数原型 /* Read N bytes into BUF from socket FD.Returns the number read or -1 for errors.This function is a cancellation point and therefore not marked with__THROW. */ extern ssize_t recv (int __fd, void *__buf, size_t __n, int __flags); 所属文件…...
kafka生产者发送消息报错 Bootstrap broker localhost:9092 (id: -1 rack: null) disconnected
报这个错误是因为kafka里的配置要修改下 在config目录下 server.properties配置文件 这下发送消息就不会一直等待,就可以发送成功了...
内存文件初始化
要在内存中初始化一个SQLite数据库文件,可以使用SQLite提供的特殊URI格式进行连接。以下是一种常见的方法: #include <sqlite3.h>int main() {sqlite3* db;// 在内存中创建或打开数据库文件int ret sqlite3_open(":memory:", &db)…...
【`opencv_core` 和 `opencv_imgcodecs` 是 OpenCV(开源计算机视觉库)的两个主要模块】
opencv_core 和 opencv_imgcodecs 是 OpenCV(开源计算机视觉库)的两个主要模块。下面简要描述这两个模块的主要功能: opencv_core: 这是 OpenCV 的核心模块,为其他 OpenCV 模块提供了基础的数据结构和函数。它包含了基本的数据类型…...
系统架构师备考倒计时24天(每日知识点)
模块独立性的度量 聚合:衡量模块内部各元素结合的紧密程度偶然聚合:模块完成的动作之间没有任何关系,或者仅仅是一种非常松散的关系。逻辑聚合:模块内部的各个组成在逻辑上具有相似的处理动作,但功能用途上彼此无关。…...
多无人机编队集群飞行
matlab2016b可直接运行 多无人机集群编队飞行(8架无人机)资源-CSDN文库...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...
算术操作符与类型转换:从基础到精通
目录 前言:从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符:、-、*、/、% 赋值操作符:和复合赋值 单⽬操作符:、--、、- 前言:从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...
