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文库...
实战指南:为spring boot项目快速配置最优jdk环境,助力应用高效部署
最近在准备一个Spring Boot项目时,发现JDK环境配置这个看似简单的环节其实藏着不少学问。特别是当项目需要兼顾开发效率和生产环境稳定性时,合理的JDK配置方案就显得尤为重要。今天就来分享下我的实战经验,以及如何利用工具快速搞定这些配置。…...
探索MediaPipe:从零开始构建实时计算机视觉应用的完整指南
探索MediaPipe:从零开始构建实时计算机视觉应用的完整指南 【免费下载链接】mediapipe Cross-platform, customizable ML solutions for live and streaming media. 项目地址: https://gitcode.com/GitHub_Trending/med/mediapipe MediaPipe是Google开源的一…...
Realistic Vision V5.1效果展示:这些惊艳的人像作品都是AI生成的
Realistic Vision V5.1效果展示:这些惊艳的人像作品都是AI生成的 1. 当AI画师遇上专业摄影师 你有没有见过这样的AI生成人像?皮肤纹理清晰到能看见毛细血管,发丝在阳光下呈现自然的半透明质感,眼神光的位置精准符合物理反射规律…...
实战演练:基于快马平台生成学生成绩排名系统,掌握排序算法应用
最近在做一个学生成绩管理系统的实战项目,其中排序功能是核心模块。通过这个项目,我深刻体会到排序算法在实际应用中的重要性。下面分享一下我的实现思路和经验总结。 学生类设计 首先需要定义一个学生类,包含学号、姓名、各科成绩和总成绩等…...
AI Agent工程师进阶指南:掌握核心技能,冲击高薪(P7-P8必备)!
本文详细介绍了AI Agent工程师的能力分层,从API调用工程师到系统设计工程师再到基础设施架构师,明确了不同层级的能力要求和市场现状。文章深入剖析了核心技术栈,包括向量数据库、RAG系统、Agent架构、Memory系统以及生产化工程等关键领域&am…...
Qwen3-VL-8B系统资源管理:监控与清理GPU显存和C盘空间
Qwen3-VL-8B系统资源管理:监控与清理GPU显存和C盘空间 长期运行像Qwen3-VL-8B这样的大模型服务,就像养了一头“数字大象”——它能力强大,但胃口也不小,尤其能吃GPU显存和硬盘空间。很多朋友刚开始部署时一切顺利,但跑…...
LabVIEW 2018+ 也能玩转OpenCV了?手把手教你用秣厉科技工具包实现摄像头人脸识别
LabVIEW与OpenCV的跨界融合:零代码实现工业级视觉检测方案 当图形化编程遇上计算机视觉,会碰撞出怎样的火花?对于习惯了LabVIEW数据流编程的工程师来说,OpenCV那些复杂的矩阵运算和算法实现往往令人望而生畏。而现在,…...
Linux环境下Python段错误全解析:从内存管理到线程安全的避坑手册
Linux环境下Python段错误全解析:从内存管理到线程安全的避坑手册 当你在深夜调试一个复杂的Python项目时,突然看到屏幕上跳出"Segmentation fault (core dumped)"的提示,那种感觉就像在高速公路上爆胎——明明代码逻辑看起来没问题…...
需要控制重复点击按钮的通用方法
如图所示 在需要控制重复点击的地方使用通用方法去控制 省时省力 比用传统的分页定时器更方便...
2026年全国青少年信息素养大赛算法应用主题赛(C++赛项初赛模拟卷3:文末附答案)
2026年全国青少年信息素养大赛算法应用主题赛(C赛项初赛模拟卷3:文末附答案) 一、单选题 在C中,以下哪个关键字用于定义一个整型变量? A. int B. float C. char D. double 一支商队从长安出发,每天行进80里…...
