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文库...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...
k8s从入门到放弃之HPA控制器
k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率(或其他自定义指标)来调整这些对象的规模,从而帮助应用程序在负…...
macOS 终端智能代理检测
🧠 终端智能代理检测:自动判断是否需要设置代理访问 GitHub 在开发中,使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新,例如: fatal: unable to access https://github.com/ohmyzsh/oh…...
