opencv-答题卡识别判卷

#导入工具包
import numpy as np
import argparse
import imutils
import cv2

# 设置参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
	help="path to the input image")
args = vars(ap.parse_args())

# 正确答案
ANSWER_KEY = {0: 1, 1: 4, 2: 0, 3: 3, 4: 1}

def order_points(pts):
	# 一共4个坐标点
	rect = np.zeros((4, 2), dtype = "float32")

	# 按顺序找到对应坐标0123分别是 左上,右上,右下,左下
	# 计算左上,右下
	s = pts.sum(axis = 1)
	rect[0] = pts[np.argmin(s)]
	rect[2] = pts[np.argmax(s)]

	# 计算右上和左下
	diff = np.diff(pts, axis = 1)
	rect[1] = pts[np.argmin(diff)]
	rect[3] = pts[np.argmax(diff)]

	return rect

def four_point_transform(image, pts):
	# 获取输入坐标点
	rect = order_points(pts)
	(tl, tr, br, bl) = rect

	# 计算输入的w和h值
	widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
	widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
	maxWidth = max(int(widthA), int(widthB))

	heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
	heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
	maxHeight = max(int(heightA), int(heightB))

	# 变换后对应坐标位置
	dst = np.array([
		[0, 0],
		[maxWidth - 1, 0],
		[maxWidth - 1, maxHeight - 1],
		[0, maxHeight - 1]], dtype = "float32")

	# 计算变换矩阵
	M = cv2.getPerspectiveTransform(rect, dst)
	warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))

	# 返回变换后结果
	return warped
def sort_contours(cnts, method="left-to-right"):
    reverse = False
    i = 0
    if method == "right-to-left" or method == "bottom-to-top":
        reverse = True
    if method == "top-to-bottom" or method == "bottom-to-top":
        i = 1
    boundingBoxes = [cv2.boundingRect(c) for c in cnts]
    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
                                        key=lambda b: b[1][i], reverse=reverse))
    return cnts, boundingBoxes
def cv_show(name,img):
        cv2.imshow(name, img)
        cv2.waitKey(0)
        cv2.destroyAllWindows()  

# 预处理
image = cv2.imread(args["image"])
contours_img = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
cv_show('blurred',blurred)
edged = cv2.Canny(blurred, 75, 200)
cv_show('edged',edged)

# 轮廓检测
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[0]
cv2.drawContours(contours_img,cnts,-1,(0,0,255),3) 
cv_show('contours_img',contours_img)
docCnt = None

# 确保检测到了
if len(cnts) > 0:
	# 根据轮廓大小进行排序
	cnts = sorted(cnts, key=cv2.contourArea, reverse=True)

	# 遍历每一个轮廓
	for c in cnts:
		# 近似
		peri = cv2.arcLength(c, True)
		approx = cv2.approxPolyDP(c, 0.02 * peri, True)

		# 准备做透视变换
		if len(approx) == 4:
			docCnt = approx
			break

# 执行透视变换

warped = four_point_transform(gray, docCnt.reshape(4, 2))
cv_show('warped',warped)
# Otsu's 阈值处理
thresh = cv2.threshold(warped, 0, 255,
	cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] 
cv_show('thresh',thresh)
thresh_Contours = thresh.copy()
# 找到每一个圆圈轮廓
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
	cv2.CHAIN_APPROX_SIMPLE)[0]
cv2.drawContours(thresh_Contours,cnts,-1,(0,0,255),3) 
cv_show('thresh_Contours',thresh_Contours)
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.append(c)

# 按照从上到下进行排序
questionCnts = sort_contours(questionCnts,
	method="top-to-bottom")[0]
correct = 0

# 每排有5个选项
for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):
	# 排序
	cnts = sort_contours(questionCnts[i:i + 5])[0]
	bubbled = None

	# 遍历每一个结果
	for (j, c) in enumerate(cnts):
		# 使用mask来判断结果
		mask = np.zeros(thresh.shape, dtype="uint8")
		cv2.drawContours(mask, [c], -1, 255, -1) #-1表示填充
		cv_show('mask',mask)
		# 通过计算非零点数量来算是否选择这个答案
		mask = cv2.bitwise_and(thresh, thresh, mask=mask)
		total = cv2.countNonZero(mask)

		# 通过阈值判断
		if bubbled is None or total > bubbled[0]:
			bubbled = (total, j)

	# 对比正确答案
	color = (0, 0, 255)
	k = ANSWER_KEY[q]

	# 判断正确
	if k == bubbled[1]:
		color = (0, 255, 0)
		correct += 1

	# 绘图
	cv2.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)

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【动手学深度学习】--18.图像增广

文章目录 图像增广1.常用的图像增广方法1.1翻转和裁剪1.2改变颜色1.3结合多种图像增广方法 2.使用图像增广进行训练3.训练 图像增广 官方笔记&#xff1a;图像增广 学习视频&#xff1a;数据增广【动手学深度学习v2】 图像增广在对训练图像进行一系列的随机变化之后&#xff…

实验八 网卡驱动移植

【实验目的】 掌握 Linux 内核配置的基本方法&#xff0c;完成对网卡驱动、NFS 等相关功能的配置 【实验环境】 ubuntu 14.04 发行版FS4412 实验平台交叉编译工具&#xff1a;arm-none-linux-gnueabi- 【注意事项】 实验步骤中以“$”开头的命令表示在 ubuntu 环境下执行&…

21.2 CSS 三大特性与页面布局

1. 开发者工具修改样式 使用开发者工具修改样式, 操作步骤如下: * 1. 打开开发者工具: 在浏览器中右键点击页面, 然后选择检查或者使用快捷键(一般是 F12 或者 CtrlShiftI)来打开开发者工具.* 2. 打开样式编辑器: 在开发者工具中, 找到选项卡或面板, 一般是Elements或者Elemen…

最新AI系统ChatGPT程序源码/微信公众号/H5端+搭建部署教程+完整知识库

一、前言 SparkAi系统是基于国外很火的ChatGPT进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。 那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧&#xff01…

不系安全带抓拍自动识别

不系安全带抓拍自动识别系统通过yolo系列算法框架模型利用高清摄像头&#xff0c;不系安全带抓拍自动识别算法对高空作业场景进行监控&#xff0c;当检测到人员未佩戴安全带时会自动抓拍并进行告警记录。YOLO系列算法是一类典型的one-stage目标检测算法&#xff0c;其利用ancho…

一生一芯8——在github上添加ssh key

为在github上下载代码框架&#xff0c;这里在github上使用ssh key进行远程连接&#xff0c;方便代码拉取 参照博客https://blog.csdn.net/losthief/article/details/131502734 本机 系统ubuntu22.04 git 版本2.34.1 本人是第一次配置&#xff0c;没有遇到奇奇怪怪的错误&…

Faster RCNN网络数据流总结

前言 在学习Faster RCNN时&#xff0c;看了许多别人写的博客。看了以后&#xff0c;对Faster RCNN整理有了一个大概的了解&#xff0c;但是对训练时网络内部的数据流还不是很清楚&#xff0c;所以在结合这个版本的faster rcnn代码情况下&#xff0c;对网络数据流进行总结。以便…

TiDB 源码编译之 TiProxy 篇

作者&#xff1a; ShawnYan 原文来源&#xff1a; https://tidb.net/blog/3d57f54d TiProxy 简介 TiProxy 是一个基于 Apache 2.0 协议开源的、轻量级的 TiDB 数据库代理&#xff0c;基于 Go 语言编写&#xff0c;支持 MySQL 协议。 TiProxy 支持负载均衡&#xff0c;接收来…

【SpringCloud技术专题】「Gateway网关系列」(2)微服务网关服务的Gateway功能配置指南分析

Spring Cloud Gateway简介 Spring Cloud Gateway是Spring Cloud体系的第二代网关组件&#xff0c;基于Spring 5.0的新特性WebFlux进行开发&#xff0c;底层网络通信框架使用的是Netty&#xff0c;所以其吞吐量高、性能强劲&#xff0c;未来将会取代第一代的网关组件Zuul。Spri…

opencv-gpu版本编译(添加java支持,可选)实现硬解码

目录 opencv gpu版本编译&#xff0c;实现硬解码&#xff0c;加速rtsp视频流读取1、准备文件2、复制 NVCUVID 头文件到 cuda 安装目录 include3、安装相关依赖4、 执行cmake5、编译安装6、测试 opencv gpu版本编译&#xff0c;实现硬解码&#xff0c;加速rtsp视频流读取 前置条…

为什么使用Nacos而不是Eureka(Nacos和Eureka的区别)

文章目录 前言一、Eureka是什么&#xff1f;二、Nacos是什么&#xff1f;三、Nacos和Eureka的区别3.1 支持的CAP3.2连接方式3.3 服务异常剔除3.4 操作实例方式 总结 前言 为什么如今微服务注册中心用Nacos相对比用Eureka的多了&#xff1f;本文章将介绍他们之间的区别和优缺点…

2023前端面试笔记 —— CSS3

系列文章目录 内容链接2023前端面试笔记HTML52023前端面试笔记CSS3 文章目录 系列文章目录前言一、CSS选择器的优先级二、通过 CSS 的哪些方式可以实现隐藏页面上的元素三、px、em、rem之间有什么区别&#xff1f;四、让元素水平居中的方法有哪些五、在 CSS 中有哪些定位方式六…

windows11系统重装步骤及优化技巧

目录 目录 本文目的 Windows11介绍 Windows下载 和win10对比 重装步骤 系统设置调整 系统备份还原 C盘减肥&#xff0c;空间优化技巧 Java开发工具 本文目的 说明windows11的系统重装步骤&#xff0c;大部分步骤也适用于其他windows版本。常用软件的安装与介绍。系统…

Jmeter 如何才能做好接口测试?

现在对测试人员的要求越来越高&#xff0c;不仅仅要做好功能测试&#xff0c;对接口测试的需求也越来越多&#xff01; 所以也越来越多的同学问&#xff0c;怎样才能做好接口测试&#xff1f; 要真正的做好接口测试&#xff0c;并且弄懂如何测试接口&#xff0c;需要从如下几…

HarmonyOS/OpenHarmony应用开发-ArkTS语言渲染控制LazyForEach数据懒加载

LazyForEach从提供的数据源中按需迭代数据&#xff0c;并在每次迭代过程中创建相应的组件。当LazyForEach在滚动容器中使用了&#xff0c;框架会根据滚动容器可视区域按需创建组件&#xff0c;当组件划出可视区域外时&#xff0c;框架会进行组件销毁回收以降低内存占用。一、接…

Oracle-rolling upgrade升级19c

前言: 本文主要描述Oracle11g升19c rolling upgrade升级测试&#xff0c;通过逻辑DGautoupgrade方式实现rolling upgrade&#xff0c;从而达到在较少停机时间内完成Oracle11g升级到19c的目标 升级介绍&#xff1a; 升级技术: rolling upgrade轮询升级&#xff0c;通过采用跨版…

手把手教你用 ANSYS workbench

ANSYS Workbench ANSYS Workbench是一款基于有限元分析&#xff08;FEA&#xff09;的工程仿真软件。其基本概念包括&#xff1a; 工作区&#xff08;Workspace&#xff09;&#xff1a;工程仿真模块都在此区域内&#xff0c;包括几何建模、网格划分、边界条件设置、分析求解等…

【leetcode 力扣刷题】链表基础知识 基础操作

链表基础知识 基础操作 链表基础操作链表基础知识插入节点删除节点查找节点 707. 设计链表实现&#xff1a;单向链表&#xff1a;实现&#xff1a;双向链表 链表基础操作 链表基础知识 在数据结构的学习过程中&#xff0c;我们知道线性表【一种数据组织、在内存中存储的形式】…

django的简易的图书管理系统jsp书店进销存源代码MySQL

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 django的简易的图书管理系统 系统有1权限&#xff1a…

Redis的基本操作

文章目录 1.Redis简介2.Redis的常用数据类型3.Redis的常用命令1.字符串操作命令2.哈希操作命令3.列表操作命令4.集合操作命令5.有序集合操作命令6.通用操作命令 4.Springboot配置Redis1.导入SpringDataRedis的Maven坐标2.配置Redis的数据源3.编写配置类&#xff0c;创还能Redis…