python学习 - 使用OpenCV库(cv2)和imutils库实现辅助答题卡判别

测试数据见文章顶部位置资源!!!

使用了OpenCV库(cv2)和imutils库。代码的主要目的是处理图像中的问题,如识别图像中的文字,并对其进行分析和排序。
辅助答题卡判别

# -*- coding:utf-8 -*-
from imutils.perspective import four_point_transform
# 图像处理函数,对OpenCV的简化
from imutils import contours
# 支持大量的维度数组与矩阵运算
import numpy as np
# OpenCV库(cv2)
import cv2 as cv
# https://github.com/qindongliang/answer_sheet_scan
ANSWER_KEY_SCORE = {0: 1, 1: 4, 2: 0, 3: 3, 4: 1}ANSWER_KEY = {0: "A", 1: "B", 2: "C", 3: "D", 4: "E"}# 加载一个图片到opencv中
img = cv.imread('test01.jpg')cv.imshow("orgin", img)# 转化成灰度图片
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)cv.imshow("gray", gray)gaussian_bulr = cv.GaussianBlur(gray, (5, 5), 0)  # 高斯模糊cv.imshow("gaussian", gaussian_bulr)edged = cv.Canny(gaussian_bulr, 75, 200)  # 边缘检测,灰度值小于2参这个值的会被丢弃,大于3参这个值会被当成边缘,在中间的部分,自动检测cv.imshow("edged", edged)# 寻找轮廓
image, cts, hierarchy = cv.findContours(edged.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)# 给轮廓加标记,便于我们在原图里面观察,注意必须是原图才能画出红色,灰度图是没有颜色的
# cv.drawContours(img, cts, -1, (0,0,255), 3)# 按面积大小对所有的轮廓排序
list = sorted(cts, key=cv.contourArea, reverse=True)print("寻找轮廓的个数:", len(cts))
cv.imshow("draw_contours", img)# 正确题的个数
correct_count = 0for c in list:# 周长,第1个参数是轮廓,第二个参数代表是否是闭环的图形peri = 0.01 * cv.arcLength(c, True)# 获取多边形的所有定点,如果是四个定点,就代表是矩形approx = cv.approxPolyDP(c, peri, True)# 打印定点个数print("顶点个数:", len(approx))if len(approx) == 4:  # 矩形# 透视变换提取原图内容部分ox_sheet = four_point_transform(img, approx.reshape(4, 2))# 透视变换提取灰度图内容部分tx_sheet = four_point_transform(gray, approx.reshape(4, 2))cv.imshow("ox", ox_sheet)cv.imshow("tx", tx_sheet)# 使用ostu二值化算法对灰度图做一个二值化处理ret, thresh2 = cv.threshold(tx_sheet, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)cv.imshow("ostu", thresh2)# 继续寻找轮廓r_image, r_cnt, r_hierarchy = cv.findContours(thresh2.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)print("找到轮廓个数:", len(r_cnt))# 使用红色标记所有的轮廓# cv.drawContours(ox_sheet,r_cnt,-1,(0,0,255),2)# 把所有找到的轮廓,给标记出来questionCnts = []for cxx in r_cnt:# 通过矩形,标记每一个指定的轮廓x, y, w, h = cv.boundingRect(cxx)ar = w / float(h)if w >= 20 and h >= 20 and ar >= 0.9 and ar <= 1.1:# 使用红色标记,满足指定条件的图形# cv.rectangle(ox_sheet, (x, y), (x + w, y + h), (0, 0, 255), 2)# 把每个选项,保存下来questionCnts.append(cxx)cv.imshow("ox_1", ox_sheet)# 按坐标从上到下排序questionCnts = contours.sort_contours(questionCnts, method="top-to-bottom")[0]# 使用np函数,按5个元素,生成一个集合for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):# 获取按从左到右的排序后的5个元素cnts = contours.sort_contours(questionCnts[i:i + 5])[0]bubble_rows = []# 遍历每一个选项for (j, c) in enumerate(cnts):# 生成一个大小与透视图一样的全黑背景图布mask = np.zeros(tx_sheet.shape, dtype="uint8")# 将指定的轮廓+白色的填充写到画板上,255代表亮度值,亮度=255的时候,颜色是白色,等于0的时候是黑色cv.drawContours(mask, [c], -1, 255, -1)# 做两个图片做位运算,把每个选项独自显示到画布上,为了统计非0像素值使用,这部分像素最大的其实就是答案mask = cv.bitwise_and(thresh2, thresh2, mask=mask)# cv.imshow("c" + str(i), mask)# 获取每个答案的像素值total = cv.countNonZero(mask)# 存到一个数组里面,tuple里面的参数分别是,像素大小和答案的序号值# print(total,j)bubble_rows.append((total, j))bubble_rows = sorted(bubble_rows, key=lambda x: x[0], reverse=True)# 选择的答案序号choice_num = bubble_rows[0][1]print("答案:{} 数据: {}".format(ANSWER_KEY.get(choice_num), bubble_rows))fill_color = None# 如果做对就加1if ANSWER_KEY_SCORE.get(q) == choice_num:fill_color = (0, 255, 0)  # 正确 绿色correct_count = correct_count + 1else:fill_color = (0, 0, 255)  # 错误 红色cv.drawContours(ox_sheet, cnts[choice_num], -1, fill_color, 2)cv.imshow("answer_flagged", ox_sheet)text1 = "total: " + str(len(ANSWER_KEY)) + ""text2 = "right: " + str(correct_count)text3 = "score: " + str(correct_count * 1.0 / len(ANSWER_KEY) * 100) + ""font = cv.FONT_HERSHEY_SIMPLEXcv.putText(ox_sheet, text1 + "  " + text2 + "  " + text3, (10, 30), font, 0.5, (0, 0, 255), 2)cv.imshow("score", ox_sheet)breakcv.waitKey(0)
# -*- coding:utf-8 -*-
from imutils.perspective import four_point_transform
from imutils import contours
import numpy as np
import cv2 as cv# 加载原图,可在项目imgs/example02目录下找到
img = cv.imread("test01.jpg")# cv.resizeWindow("enhanced", 240, 280);
# 打印原图
cv.imshow("orgin", img)# 灰度化
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)# 打印灰度图
cv.imshow("gray", gray)# 高斯滤波,清除一些杂点
blur = cv.GaussianBlur(gray, (3, 3), 0)# 自适应二值化算法
thresh2 = cv.adaptiveThreshold(blur, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY_INV, 131, 4)# 打印二值化后的图
cv.imshow("thresh2", thresh2)# 寻找轮廓
image, cts, hierarchy = cv.findContours(thresh2, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)# 打印找到的轮廓
print("轮廓数:", len(cts))# 对拷贝的原图进行轮廓标记
contour_flagged = cv.drawContours(img.copy(), cts, -1, (0, 0, 255), 3)
# 打印轮廓图
cv.imshow("contours_flagged", contour_flagged)
# 按像素面积降序排序
list = sorted(cts, key=cv.contourArea, reverse=True)# 遍历轮廓
for ct in list:# 周长,第1个参数是轮廓,第二个参数代表是否是闭环的图形peri = 0.01 * cv.arcLength(ct, True)# 获取多边形的所有定点,如果是四个定点,就代表是矩形approx = cv.approxPolyDP(ct, peri, True)# 只考虑矩形if len(approx) == 4:# 从原图中提取所需的矫正图片ox = four_point_transform(img, approx.reshape(4, 2))# 从原图中提取所需的矫正图片tx = four_point_transform(gray, approx.reshape(4, 2))# 打印矫正后的灰度图cv.imshow("tx", tx)# 对矫正图进行高斯模糊blur = cv.GaussianBlur(tx, (3, 3), 0)# 对矫正图做自适应二值化thresh2 = cv.adaptiveThreshold(blur, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY_INV, 131, 4)# 打印矫正后的二值化图cv.imshow("tx_thresh2", thresh2)# 获取轮廓r_image, r_cts, r_hierarchy = cv.findContours(thresh2, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)# 打印得到轮廓数量print("第二层轮廓数:", len(r_cts))# 用于存储答案的python list变量question_list = []for r_ct in r_cts:# 转为矩形,分别获取 x,y坐标,及矩形的宽和高x, y, w, h = cv.boundingRect(r_ct)# 过滤掉不符合答案坐标和长宽的选项if x > 2 and y > 2 and w > 20 and h > 20:# cv.drawContours(ox, r_ct, -1, (0, 0, 255), 1)question_list.append(r_ct)print("答案总数:", len(question_list))# 按坐标从上到下排序questionCnts = contours.sort_contours(question_list, method="top-to-bottom")[0]#  使用np函数,按5个元素,生成一个集合for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):# 每一个行5个答案,从左到右排序cnts = contours.sort_contours(questionCnts[i:i + 5])[0]# 存储一行题里面的每个答案ans_list = []for (j, cc) in enumerate(cnts):# 生成全黑画布mask = np.zeros(thresh2.shape, dtype="uint8")# 将每一个答案按轮廓写上去,并将填充颜色设置成白色tpp = cv.drawContours(mask, [cc], -1, 255, -1)# 两个图片做位运算mask = cv.bitwise_and(thresh2, thresh2, mask=mask)# 统计每个答案的像素total = cv.countNonZero(mask)# 添加到集合里面ans_list.append((total, j))# 按像素大小排序ans_list = sorted(ans_list, key=lambda x: x[0], reverse=True)max_ans_num = ans_list[0][1]max_ans_size = ans_list[0][0]print("答案序号:", max_ans_num, "列表:", ans_list)# 给选中答案,标记成红色cv.drawContours(ox, cnts[max_ans_num], -1, (0, 0, 255), 2)cv.imshow("answer_flagged", ox)# 最大的轮廓就是我们想要的,之后的就可以结束循环了break# 阻塞等待窗体关闭
cv.waitKey(0)

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

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

相关文章

python实现邮箱轰炸机

最近在学计算机网络看到套接字的练习 于是应用SMTP协议写了个发送邮箱的玩玩 可以发一大堆垃圾邮件给对方 其中参考了 关于发邮件报错535 Error&#xff1a;authentication failed解决方法http://t.csdnimg.cn/Bc0Dq 已经查询如何获取网易邮箱客户端授权码 base64编码 i…

Mybatis05-一对多和多对一处理

多对一和一对多 多对一 多对一的理解&#xff1a; 多个学生对应一个老师 如果对于学生这边&#xff0c;就是一个多对一的现象&#xff0c;即从学生这边关联一个老师&#xff01; 结果映射&#xff08;resultMap&#xff09;&#xff1a; association 一个复杂类型的关联&…

在线Logo背景去除:pixian.ai

文章目录 简介特色 简介 pixian.ai是一款智能图片背景去除工具&#xff0c;进入网页后&#xff0c;会非常醒目地提示你准备【Free】还是【Paid】&#xff0c;这点就非常好&#xff0c;不向有一些网站&#xff0c;主打免费使用&#xff0c;但时不时弹出“免费注册”&#xff0c…

【微信小程序】连接蓝牙设备

1、检查小程序是否授权蓝牙功能 initBluetooth() {const that thiswx.getSetting({success: (res) > {if (res.authSetting.hasOwnProperty(scope.bluetooth)) {//scope.bluetooth属性存在&#xff0c;且为falseif (!res.authSetting[scope.bluetooth]) {wx.showModal({tit…

Python 连接 MySQL 及 SQL增删改查(主要使用sqlalchemy)

目录 一、环境 二、MySQL的连接和使用 2.1方式一&#xff1a;sql为主 2.1.1创建连接 2.1.2 表结构 2.1.3 新增数据 ​编辑 2.1.4 查看数据 ​编辑 2.1.5 修改数据 2.1.6 删除数据 2.2方式二&#xff1a;orm对象关系映射 2.2.1 mysql连接 2.2.2 创建表 2.2.3 新增…

windows 安装pnpm

安装Node.js&#xff1a; 确保系统上已安装Node.js。pnpm需要Node.js来运行。如果尚未安装Node.js&#xff0c;请从其官方网站下载并安装适用于Windows的最新版本。 安装pnpm&#xff1a; 打开命令行工具&#xff08;如CMD、PowerShell或Git Bash&#xff09;。使用npm&…

解锁机器学习的无限可能:深入探究scikit-learn的强大功能

解锁机器学习的无限可能&#xff1a;深入探究scikit-learn的强大功能 第一部分&#xff1a;背景和功能介绍 在数据科学和机器学习领域&#xff0c;scikit-learn&#xff08;简称sklearn&#xff09;是一个广泛使用的Python库。它提供了简单高效的工具用于数据挖掘和数据分析&a…

【Python短期内快速掌握学习人工智能知识能力】:从零到入门的NLP学习秘籍

⭐️我叫忆_恒心&#xff0c;一名喜欢书写博客的研究生&#x1f468;‍&#x1f393;。 如果觉得本文能帮到您&#xff0c;麻烦点个赞&#x1f44d;呗&#xff01; 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧&#xff0c;喜欢的小伙伴给个三连支…

Echarts 在折线图的指定位置绘制一个图标展示

文章目录 需求分析需求 在线段交汇处用一个六边形图标展示 分析 可以使用 markPoint 和 symbol 属性来实现。这是一个更简单和更标准的方法来添加标记点在运行下述代码后,你将在浏览器中看到一个折线图,其中在 [3, 35] (即图表中第四个数据点 Thu 的 y 值为 35 的位置)处…

Java反射Reflect机制详解

文章目录 引言反射的基本概念反射基本原理反射应用场景反射基本使用获取类的Class对象获取构造方法并实例化对象获取和调用方法获取和修改字段反射工具类 反射源码解读获取Class对象的源码调用方法的源码 反射优缺点优点缺点 为什么需要反射总结 引言 Java反射是Java语言中的一…

【干货】视频文件抽帧(opencv和ffmpeg方式对比)

1 废话不多说&#xff0c;直接上代码 opencv方式 import time import subprocess import cv2, os from math import ceildef extract_frames_opencv(video_path, output_folder, frame_rate1):"""使用 OpenCV 从视频中抽取每秒指定帧数的帧,并保存到指定文件夹…

linux系统使用达梦数据库

在Linux系统中使用达梦数据库&#xff0c;首先需要确保已经正确安装了达梦数据库软件。以下是一个基本的使用示例&#xff0c;假设您已经安装了达梦数据库并且配置好了相关环境变量。 连接到数据库&#xff1a; 使用 dsql 命令连接到数据库 dsql -h hostname -u username -p…

宝贝,带上WebAssembly,换个姿势来优化你的前端应用

在你没崛起之前,脸是用来丢的 大家好,我是柒八九。一个专注于前端开发技术/Rust及AI应用知识分享的Coder 此篇文章所涉及到的技术有 WebAssemblyRustWeb Worker(comlink)wasm-packPhotonffmpeg.wasm脚手架生成前端项目因为,行文字数所限,有些概念可能会一带而过亦或者提供对…

BOM是什么东西

BOM&#xff08;Byte Order Mark&#xff0c;字节顺序标记&#xff09;是一个Unicode字符&#xff0c;通常出现在文本文件的开头。它的作用包括以下几个方面&#xff1a; 1. 指示文件的编码方式 BOM可以帮助软件识别文本文件使用的字符编码。不同的编码方式可能会使用不同的B…

经济与安全兼顾:茶饮店购买可燃气体报警器的价格考量

可燃气体报警器在如今的社会中扮演着至关重要的角色。它们用于检测环境中的可燃气体浓度&#xff0c;及早发现潜在的火灾隐患&#xff0c;保护人们的生命和财产安全。 在这篇文章中&#xff0c;佰德将介绍可燃气体报警器的安装、检定以及价格&#xff0c;通过实际案例和数据&a…

PCL 生成空间椭圆点云

目录 一、算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 设椭圆在 X O Y XOY XOY平面上,参数方程为:

怎么保障TikTok直播网络稳定?

TikTok&#xff0c;这个近年来风靡全球的社交媒体平台&#xff0c;已成为电商引流的新方向&#xff0c;尤其是其直播功能。然而&#xff0c;对于打算进军TikTok直播领域的商家和主播而言&#xff0c;确保网络稳定无疑是首要任务。那么&#xff0c;TikTok直播专线究竟是什么呢&a…

牛啊后续:如何一行C#代码实现解析类型的Summary注释(可用于数据字典快速生成)...

前言&#xff1a;下午有小伙伴要求&#xff0c;让我继续做个解析实体类注释信息的内容。所以我也顺便加入进来。以下开始正文实战操作&#xff1a; 项目需要勾选输出api文档文件。这样就可以让所有实体类的summary信息被写入到输出目录下。如果有多个xml文件也没关系&#xff0…

小程序 UI 风格美不胜收

小程序 UI 风格美不胜收 小程序 UI 风格美不胜收

PostgreSQL的视图pg_stat_replication

PostgreSQL的视图pg_stat_replication pg_stat_replication 是 PostgreSQL 提供的一个系统视图&#xff0c;用于显示主服务器上当前正在进行的复制会话的信息。它可以帮助数据库管理员监控和管理主从复制的状态&#xff0c;确保数据的正确同步和高可靠性。 pg_stat_replicati…