opencv 答题卡检测项目实现

news2024/11/27 16:53:46

在教育和考试领域,答题卡自动评分系统能够大大提高效率和准确性。本文将介绍如何使用OpenCV库实现一个简单的答题卡检测项目。这个项目包括读取图像、检测答题卡轮廓、透视变换、二值化处理、检测选择题答案,并最终计算得分。

导入库和定义常量

import cv2  
import numpy as np  
  
ANSWER_KEY = {0: 1, 1: 4, 2: 0, 3: 3, 4: 1}  # 假设的答题卡答案密钥

辅助函数

cv_show

这个函数用于显示图像,便于调试。

def cv_show(name, img):  
    cv2.imshow(name, img)  
    cv2.waitKey(0)
order_points

这个函数用于对四个点按照左上、右上、右下、左下的顺序进行排序。

def order_points(pts):  
    rect = np.zeros((4, 2), dtype='float32')  
    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
sort_contours

这个函数用于根据指定方法对轮廓进行排序。

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
four_point_transform

这个函数用于将透视扭曲的矩形变换成一个规则的矩形。

def four_point_transform(image, pts):  
    rect = order_points(pts)  
    (tl, tr, br, bl) = rect  
    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

主流程

读取图像和预处理
image = cv2.imread(r'./images/test_01.png')  
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)[1]  
cv2.drawContours(contours_img, cnts, -1, (0, 0, 255), 3)  
cv_show('contours_img', contours_img)  
docCnt = None  
  
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_t = four_point_transform(image, docCnt.reshape(4, 2))  
warped_new = warped_t.copy()  
cv_show('warped', warped_t)
检测选择题答案
thresh_Contours = thresh.copy()  
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1]  
warped_Contours = cv2.drawContours(warped_t, cnts, -1, (0, 255, 0), 1)  
cv_show('warped_Contours', warped_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  
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 = np.zeros(thresh.shape, dtype="uint8")  
        cv2.drawContours(mask, [c], -1, 255, -1)  
        thresh_mask_and = cv2.bitwise_and(thresh, thresh, mask=mask)  
        total = cv2.countNonZero(thresh_mask_and)  
        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_new, [cnts[k]], -1, color, 3)  
  
score = (correct / 5.0) * 100  
print("[INFO] score: {:.2f}%".format(score))  
cv2.putText(warped_new, "{:.2f}%".format(score), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2)  
cv2.imshow("Original", image)  
cv2.imshow("Exam", warped_new)  
cv2.waitKey(0)

代码实现效果:

总结

通过图像预处理、轮廓检测、透视变换、二值化处理、答案检测和评分计算,我们能够自动化地读取答题卡并计算得分。这种方法不仅提高了效率,还减少了人为错误。希望这个项目对你有所启发,并能够在你的实际应用中发挥作用。

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

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

相关文章

动态规划-路径问题——931.下降路径最小和

1.题目解析 题目来源&#xff1a;931.下降路径最小和——力扣 测试用例 2.算法原理 1.状态表示 我们可以开辟一个dp表&#xff0c;多开辟一行两列用来存储虚拟位置&#xff0c;dp[i][j]表示从第一行到该位置的最小路径和 2.状态转移方程 由于要找到最小路径和&#xff0c;并且由…

中间件镜像升级策略

进入集群 kubectl edit deployments paas-bmm-v1 -n kube-system 修改容器 abcsys.cn:5000/boc3.7/bmm-web-v4:latest-202410091355

【芯片知识】 | 浅谈NRK3502语音芯片IC的工作原理

随着科技的快速发展&#xff0c;语音技术逐渐渗透到我们生活的各个领域&#xff0c;如智能家居、车载导航、手机通讯等。作为语音技术的核心&#xff0c;语音芯片在其中发挥着重要作用。今天&#xff0c;我们将深入探讨NRK3502这款先进的语音芯片IC的工作原理&#xff0c;以及它…

动态规划-路径问题——174.地下城游戏

1.题目解析 题目来源&#xff1a;174.地下城游戏 测试用例 2.算法原理 1.状态表示 通常dp[i,j]可以表示终点也可以表示起点&#xff0c;在本题中如果表示为终点&#xff0c;即勇士到[i,j]位置所需要的最小生命值&#xff0c;但是由于后续位置的未知无法向后继续判断&#xff…

如何判断外包建站公司靠谱与否?2024外包网站设计公司哪家好top3

要知道一家网站建设公司靠不靠谱&#xff0c;看他们合作过哪些公司就能知道个大概。 如果服务对象有各行业的头肩部企业&#xff0c;那这家网站建设公司在专业性上肯定是有保障的。 但是&#xff0c;靠谱并不意味着适合自己。 靠谱的网站建设公司其实在技术上都大差不差&…

我用这四款翻译工具,轻松搞定英文在线翻译

作为一名喜欢搜罗各种办公软件的打工人&#xff0c;今天我要和大家聊聊一个我们工作中不可或缺的技能——英文翻译。首先&#xff0c;我们得承认&#xff0c;翻译工作有时候真的很让人头疼&#xff0c;尤其是当我们面对一堆专业术语和长篇大论时。但自从我发现了这些翻译神器&a…

Linux系统:apt-get update 和apt update区别

apt-get update 和apt update区别 ‌apt-get update和apt update的主要区别在于它们所属的命令集以及在现代Ubuntu系统中的使用推荐。‌ ‌所属命令集‌&#xff1a;apt-get update是apt-get命令的一部分&#xff0c;而apt update是apt命令的一部分。apt是apt-get的替代工具&am…

《Image Processing GNN: Breaking Rigidity in Super-Resolution》CVPR2024

摘要 这篇论文提出了一种名为Image Processing Graph Neural Networks (IPG) 的模型&#xff0c;旨在通过利用图的灵活性来突破超分辨率&#xff08;Super-Resolution, SR&#xff09;中的固有刚性问题。在现有的SR模型中&#xff0c;无论是基于卷积神经网络&#xff08;CNNs&…

新手小白想快速上手Mac的使用必看问题

相信不论是现在还是将来&#xff0c;肯定还是会有Mac小白的存在&#xff0c;对于大多数人来说&#xff0c;从小接触Windows的机会比较多&#xff0c;Windows的使用也是比较多&#xff0c;但是有些朋友在大学的时候想体验一下Mac的感觉&#xff0c;于是果断下单&#xff0c;又或…

[C语言] 函数详解:库函数与自定义函数

文章目录 函数的概念库函数和自定义函数库函数使用库函数示例常用库函数及头文件 自定义函数自定义函数的基本结构示例&#xff1a;实现两个数的求和函数自定义函数的好处 函数的返回值有返回值的函数无返回值的函数 函数的声明与调用声明函数在另一个文件中调用函数示例&#…

51单片机的智能小区安防系统【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块时钟模块温度传感器烟雾传感器CO传感器红外感应传感器IC卡蓝牙继电器按键、蜂鸣器、LED等模块构成。适用于智能小区安防、智能家居安防等相似项目。 可实现功能: 1、LCD1602实时显示北京时间、温度、烟雾浓度和CO浓…

Kylin系统安装VMwareTools工具

如下图所示&#xff0c;安装好Kylin系统之后&#xff0c;还未安装VMwareTools工具&#xff0c;导致系统画面无法填充虚拟机 正常安装了VMwareTools工具后的系统画面 所以&#xff0c;接下来我们介绍一下如何在Kylin系统下安装VMwareTools工具 首先&#xff0c;点击VMware工具栏…

Android常用布局

目录 布局文件中常见的属性 1. 基本布局属性 1&#xff09;android:layout_width 2&#xff09;android:layout_height 3&#xff09;android:layout_margin 4&#xff09;android:padding 2. 线性布局 (LinearLayout) 属性 1&#xff09;android:orientation 2&#xff09;and…

深度学习神经网络笔记--卷积神经网络

为什么要用卷积 捕捉特征&#xff0c;如文末的图&#xff09;不受位置影响&#xff08;左右&#xff0c;前后&#xff0c;上下&#xff09;可以参考下图&#xff1a;卷积操作 可移动的小窗口与图像数据逐元素相乘后相加小窗口是滤波器&#xff0c;卷积核&#xff0c;&#xff0…

毕业设计之—基于ManTra-Net的图像篡改检测方法研究与应用实现

1.摘要 随着互联网、社交媒体和简易图像操作工具的普及&#xff0c;图像篡改带来的问题日益严重。为了解决这一问题&#xff0c;研究者们利用深度卷积神经网络来检测图像篡改并定位篡改区域。为此我们训练了一个ManTra-Net模型&#xff0c;该模型以TensorFlow为后端&#xff0c…

什么是网络安全等级保护?企业如何建立安全系统?一篇带你快速了解→:

等保测评的定义与目的 等保测评旨在评估信息系统的安全性&#xff0c;并根据评估结果给予相应的安全等级。该等级反映了信息系统在保护国家安全、经济安全、社会公共利益以及个人合法权益方面的能力。通过等保测评&#xff0c;可以确保信息系统符合国家法律法规的要求&#xf…

DSP CMD文件使用

背景描述: 在CCS编译代码时出现如下警告 解决方法: 找到cmd文件(这里是用的系统自动生成的)&#xff0c;在Section部分找到对应的核 #ifdef CORE7.text > CORE7_L2_SRAM.stack > CORE7_L2_SRAM.bss > CORE7_L2_SRAM.cio &g…

(28)QPSK调制信号使用矩形脉冲成形的误符号率和误比特率MATLAB仿真

文章目录 前言一、系统模型说明二、MATLAB仿真代码三、MATLAB仿真结果四、仿真结果分析 前言 在QPSK通信系统仿真时&#xff0c;经常会加入调制信号的脉冲成形模块&#xff0c;本文将讨论在这种情况下信道的信噪比该如何设置&#xff0c;并给出MATLAB仿真代码&#xff0c;画出…

滑动窗口_⽔果成篮找到字符串中所有字⺟异位词

⽔果成篮 904. 水果成篮 - 力扣&#xff08;LeetCode&#xff09; 相当于求数字种类不超过2的最长字字符串 我们先看一看例4.从第一个元素开始最长字符串3331&#xff0c;下一次从第二个位置数吗&#xff1f;没必要&#xff0c;因为只有当字符串中数字种类变为1时&#xff0c;…

库的相关使用

1.1 库的概念 库是由.c文件编译生成的二进制文件。 库的内部就是各种函数的实现。 windows中库的格式&#xff1a; xxx.dll -- 动态库 xxx.lib -- 静态库 linux中库的格式&#xff1a; libxxx.a --- 静态库 libxxx.so --- 动态库 2.1 静态库的制作和使用 2.1.1 静态库的…