OpenCV从入门到精通实战(四)——答题卡识别判卷系统

基于OpenCV的答题卡识别系统,其主要功能是自动读取并评分答题卡上的选择题答案。系统通过图像处理和计算机视觉技术,自动化地完成了从读取图像到输出成绩的整个流程。下面是该系统的主要步骤和实现细节的概述:

1. 导入必要的库

系统首先导入了numpy、argparse、imutils和cv2等Python库。这些库提供了处理图像、解析命令行参数等功能。

python 复制代码
# 导入工具包
import numpy as np
import argparse
import imutils
import cv2

2. 参数设置

使用argparse库来处理命令行输入参数,允许用户指定输入图像的路径。

python 复制代码
# 设置参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", default="images/test_01.png",
                help="path to the input image")
args = vars(ap.parse_args())

3. 定义答案键

系统中定义了一个答案键(ANSWER_KEY),这是一个字典,用于存储每个问题的正确答案选项

python 复制代码
# 正确答案
ANSWER_KEY = {0: 1, 1: 4, 2: 0, 3: 3, 4: 1}

以下是针对每个主要步骤的对应代码片段,以及如何实现在上述答题卡识别系统中的功能:

4. 图像预处理

python 复制代码
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(blurred, 75, 200)

实现细节:

  • cv2.imread:加载图像。
  • cv2.cvtColor:将图像从BGR颜色空间转换为灰度。
  • cv2.GaussianBlur:应用高斯模糊,减少噪声。
  • cv2.Canny:执行Canny边缘检测。

5. 轮廓检测

python 复制代码
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
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

实现细节:

  • cv2.findContours:查找边缘。
  • sorted:按轮廓面积大小排序。
  • cv2.approxPolyDP:轮廓近似,寻找角点。

6. 透视变换

python 复制代码
paper = four_point_transform(image, docCnt.reshape(4, 2))
warped = four_point_transform(gray, docCnt.reshape(4, 2))

实现细节:

  • 使用自定义函数four_point_transform来执行透视变换,以得到答题卡的顶视图。

7. 应用阈值

python 复制代码
thresh = cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]

实现细节:

  • cv2.threshold:通过Otsu方法自动确定最优阈值并二值化图像。

8. 轮廓再次检测

python 复制代码
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)

实现细节:

  • 再次检测二值化图像中的轮廓。

9. 筛选与排序

python 复制代码
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 = contours.sort_contours(questionCnts, method="top-to-bottom")[0]

实现细节:

  • 筛选形状近似于圆的轮廓,并按从上到下排序。

10. 评分逻辑

python 复制代码
correct = 0
for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):
    cnts = contours.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)
        mask = cv2.bitwise_and(thresh, thresh, mask=mask)
        total = cv2.countNonZero(mask)

        if bubbled is None or total > bubbled[0]:
            bubbled = (total, j)

    if bubbled[1] == ANSWER_KEY[q]:
        correct += 1

实现细节:

  • 遍历每个问题的答题区域,通过填涂密度判断学生选择,通过计算填涂区域的像素密度来判断学生的的选项。然后将这个选择与答案键中的正确选项进行比较,统计出正确的答案数量。

11. 结果展示

python 复制代码
score = (correct / float(len(ANSWER_KEY))) * 100
print("总分: {:.2f}%".format(score))
cv2.imshow("Original", image)
cv2.imshow("Exam", paper)
cv2.waitKey(0)

实现细节:

  • 计算出得分百分比,并输出。
  • cv2.imshow:展示原始图像和处理后的图像,以便检查标记的正确与错误的答案。

源码下载:答题卡识别判卷系统

相关推荐
风巽·剑染春水1 分钟前
【扩散模型原理】(七)Diffusion Models and Optimal Transport(3)
人工智能·生成模型·diffusion·扩散模型·最优传输
火山引擎开发者社区2 分钟前
模型没兜底、账算不清、Key 散落各处,Agent 怎么上生产?
人工智能
hhb_6182 分钟前
智联AI办公微服务技术全解析
人工智能·微服务·架构
richard_yuu6 分钟前
OpenCV 实战第 15 篇:G-API 图计算,工业流水线的 CPU/GPU 混合执行
人工智能·opencv·计算机视觉
骑着蜗牛撵大象3279 分钟前
Spring AI + Qwen3.8 周报助手:从事项采集到人工确认卡的闭环实战
人工智能·spring·elasticsearch·自动化·大模型应用·qwen3.8·rag溯源
看浪的路人10 分钟前
第6讲:Agent 安全体系——Prompt 注入防御、工具调用审计与输出合规
人工智能·算法
DogDaoDao12 分钟前
当视频理解撞上大语言模型:一篇 37 页综述的全景拆解
人工智能·语言模型·音视频·知识图谱·视频
一次旅行12 分钟前
2026.10.16 AI产业深度解读|AI独角兽估值遇冷;Meta重磅开放权重模型;硬件产能向AI算力倾斜
人工智能
paopaokaka_luck13 分钟前
民宿管理系统 (AI民宿总结、协同过滤推荐算法、WebSocket 在线咨询、ECharts 经营分析、房态与结算联动、 民宿预订业务闭环)
java·人工智能·spring boot·websocket·数据分析·echarts·推荐算法