当前位置: 首页 > news >正文

OpenCV图像处理——(实战)答题卡识别试卷

总目录

图像处理总目录←点击这里

二十、答题卡识别试卷

20.1、预处理

灰度图

输出灰度图+高斯滤波去噪

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)

在这里插入图片描述

边缘检测

edged = cv2.Canny(blurred, 75, 200)

在这里插入图片描述

20.2、轮廓检测

找到原始图像中边框的四个矩形框的点

cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
cv2.drawContours(contours_img, cnts, -1, (0, 0, 255), 3)

在这里插入图片描述

20.3、透视变换

得到需要的图像范围

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

在这里插入图片描述

20.4、阈值处理

处理已经选择的题目

thresh = cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]

在这里插入图片描述

20.5、轮廓检测(小)

每一个圆圈的轮廓检测

(涂答题卡可能涂到外面)

cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
cv2.drawContours(thresh_Contours, cnts, -1, (0, 0, 255), 3)

在这里插入图片描述

20.6、筛选,排序,选项

筛选出符合条件的圆圈(通过宽高,宽高比例筛选)

将符合条件的进行排序(默认乱序)

  • 先从上到下找到所有行排序
  • 在从左到右对每一行排序
  • 根据像素点对比找到答案

# 遍历筛选
for c in cnts:
    # 计算比例和大小
    (x, y, w, h) = cv2.boundingRect(c)
    ar = w / float(h)

    # 根据实际情况指定标准
    if w >= 20 and h >= 20 and 0.9 <= ar <= 1.1:
        questionCnts.append(c)

# 排序
def sort_contours(cnts, method="left-to-right"):
    # ...
    boundingBoxes = [cv2.boundingRect(c) for c in cnts]
    return cnts, boundingBoxes

# 对所有行排序
questionCnts = sort_contours(questionCnts, method="top-to-bottom")[0]

# 循环,并找答案
for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):
	# 对每一行进行排序
	cnts = sort_contours(questionCnts[i:i + 5])[0]
	for (j, c) in enumerate(cnts):
		mask = np.zeros(thresh.shape, dtype="uint8")
		if bubbled is None or total > bubbled[0]:
    	# j为答案,total为像素点对比(选出最合适的)
    	bubbled = (total, j)
		# ... 

第一行跑完结果

由 12345与操作得出最后结果

在这里插入图片描述

20.7、结果

答案:BEADB

第4题选错

在这里插入图片描述

答案:BEADB

第1、2、4、5题选错
在这里插入图片描述
答案:BEADB

第1、4 题选错

在这里插入图片描述

答案:BEADB

第1、2、3、5题选错

在这里插入图片描述

答案:BEADB

正确

在这里插入图片描述

原图

# 正确答案 1 4 0 3 1  ------> B E A D B
ANSWER_KEY = {0: 1, 1: 4, 2: 0, 3: 3, 4: 1}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

相关文章:

  • 2022亚太数学杯数学建模竞赛A题(思路分析......)
  • 为了提前预测比赛结果,于是我用Python获取比赛球员数据进行分析,结果...
  • 机器学习之特征提取
  • 第 46 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(南京),签到题5题
  • 线代——求逆矩阵的快捷方法
  • 分布式存储之 etcd 的集群管理
  • std::unique_ptr(基础和仿写)
  • UG旋钮盖模具设计与加工
  • 【JAVA高级】——封装JDBC中的DaoUtils工具类(Object类型方法)
  • MYSQL事务原理分析
  • ORB-SLAM3算法学习—Frame构造—基于SAD滑窗的双目特征匹配
  • 【最佳实践】gorm 联表查询 joins
  • http请求走私漏洞原理,利用,检测,防护
  • simulink中比scope模块还好用的平替出图工具?
  • 微信小程序和H5之间互相跳转、互相传值
  • [PHP内核探索]PHP中的哈希表
  • ES6 学习笔记(一)let,const和解构赋值
  • JS笔记四:作用域、变量(函数)提升
  • js对象的深浅拷贝
  • Mocha测试初探
  • pdf文件如何在线转换为jpg图片
  • Spring-boot 启动时碰到的错误
  • Unix命令
  • VirtualBox 安装过程中出现 Running VMs found 错误的解决过程
  • Vue.js源码(2):初探List Rendering
  • vue从入门到进阶:计算属性computed与侦听器watch(三)
  • 从零开始在ubuntu上搭建node开发环境
  • 分享几个不错的工具
  • 观察者模式实现非直接耦合
  • 深入浏览器事件循环的本质
  • 我的zsh配置, 2019最新方案
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • 用jquery写贪吃蛇
  • 主流的CSS水平和垂直居中技术大全
  • 字符串匹配基础上
  • HanLP分词命名实体提取详解
  • 如何用纯 CSS 创作一个菱形 loader 动画
  • ​人工智能书单(数学基础篇)
  • #数学建模# 线性规划问题的Matlab求解
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (汇总)os模块以及shutil模块对文件的操作
  • (离散数学)逻辑连接词
  • (十一)JAVA springboot ssm b2b2c多用户商城系统源码:服务网关Zuul高级篇
  • (原)记一次CentOS7 磁盘空间大小异常的解决过程
  • (转)C#调用WebService 基础
  • (转)ObjectiveC 深浅拷贝学习
  • .[backups@airmail.cc].faust勒索病毒的最新威胁:如何恢复您的数据?
  • .L0CK3D来袭:如何保护您的数据免受致命攻击
  • .NET Entity FrameWork 总结 ,在项目中用处个人感觉不大。适合初级用用,不涉及到与数据库通信。
  • .Net Memory Profiler的使用举例
  • .net 流——流的类型体系简单介绍
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地定义和使用弱事件
  • .NET/C# 判断某个类是否是泛型类型或泛型接口的子类型
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试