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

news/2024/7/21 5:11:37 标签: 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}

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


http://www.niftyadmin.cn/n/11431.html

相关文章

Hudi Spark SQL Call Procedures学习总结(一)(查询统计表文件信息)

前言 学习总结Hudi Spark SQL Call Procedures&#xff0c;Call Procedures在官网被称作存储过程&#xff08;Stored Procedures&#xff09;&#xff0c;它是在Hudi 0.11.0版本由腾讯的ForwardXu大佬贡献的&#xff0c;它除了官网提到的几个Procedures外&#xff0c;还支持其…

重定向和转发的区别

重定向和转发的区别 在代码上 转发 // 第一步&#xff1a;获取请求转发器对象RequestDispatcher dispatcher request.getRequestDispatcher("/b");// 第二步&#xff1a;调用转发器的forward方法完成跳转/转发dispatcher.forward(request,response);// 第一步和第二…

KMP字符串匹配算法

引言 KMP算法的思想在于&#xff0c;让每一次匹配都尽可能使用先前匹配产生的信息(部分匹配表)。 KMP算法的难点在于&#xff0c;部分匹配表的构造也在尽可能使用之前构造过程中的信息&#xff08;动态规划&#xff1f;&#xff09;。 暴力 Vs KMP 暴力&#xff1a;失配&am…

【华为上机真题 2022】字符串比较

&#x1f388; 作者&#xff1a;Linux猿 &#x1f388; 简介&#xff1a;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;Linux、C/C、云计算、物联网、面试、刷题、算法尽管咨询我&#xff0c;关注我&#xff0c;有问题私聊&#xff01; &…

在github上部署静态页面

使用github-page部署静态页面 需求 假如你辛辛苦苦写好了一个静态网页&#xff0c;很想要炫耀一下&#xff0c;让大家都可以通过公网访问看到我的网页。但是不想太麻烦&#xff0c;买服务器&#xff0c;安装软件&#xff0c;部署环境&#xff0c;配置域名&#xff0c;备案&…

SAP PS 第八节 PS 常见问题处理-来源于SAP EPPM分享

SAP PS 常见问题处理1 配置类1.1 结果分析的几类方法1.1.1 关于CO表中价值类别和值类型区别1.1.2 关于结果分析取那个计划成本的问题1.1.3 实际成本大于计划成本的报错1.1.4 结果分析一些典型配置&#xff08;闲人提供&#xff09;1.1.5 结果分析1.2 计划成本1.3 结算时&#x…

maven学习:继承与聚合

4.1继承 ​ 做面向对象编程的人都会觉得这是一个没意义的问题&#xff0c;是的&#xff0c;继承就是避免重复&#xff0c;maven的继承也是这样&#xff0c;它还有一个好处就是让项目更加安全. 我们在项目开发的过程中&#xff0c;可能多个模块独立开发&#xff0c;但是多个模块…

【linux】linux实操篇之软件包管理

前言 关于这一快软件包管理知识点不多&#xff0c;我们主要认识一下rpm和yum这两个软件包管理工具&#xff0c;主要还是yum的使用&#xff01; rpm 包的管理 一种用于互联网下载包的打包及安装工具&#xff0c;它包含在某些 Linux 分发版中。它生成具有 .rpm 扩展名的文件。…