我用 Python 写了一个自动裁剪答题卡区域的小工具(附代码)

简介: 本文分享了一种通过 OpenCV 自动裁剪答题卡中答题区域的方法。核心思路是利用答题区域四周的黑色角块进行定位:先通过自适应阈值增强对比度,再用 `cv2.findContours()` 找轮廓,并计算每个轮廓的“紧凑度”(面积 / 周长)筛选出接近方块的角块。最终根据四个角块的边界矩形裁剪出答题区。代码实现详细,适合初学者参考,同时提供了参数调整建议以适配不同图像条件。

在做图像处理项目的时候,我遇到一个实际问题:怎么从一张拍下来的答题卡中,自动裁剪出答题区域?

答题区域其实很好识别 —— 通常被四个黑色小角块框住了。所以我写了一个简单的 OpenCV 脚本,试图通过这四个角块来定位并裁剪答题区域。

过程踩了点坑,但最终搞定了。以下是完整代码和我的思路,欢迎参考,也欢迎指正!

实现思路
我的目标是提取这类图像中的答题区:

利用自适应阈值,增强对比度;

通过 cv2.findContours() 找轮廓;

计算每个轮廓的面积和周长,用 面积 / 周长 计算“紧凑度”;

只保留紧凑度合理、形状接近方块的轮廓;

找到四个角块后,用它们的边界矩形裁剪出答题区。

代码如下

import cv2
import numpy as np
from typing import Optional

def extract_answer_area(image_path: str) -> Optional[np.ndarray]:
    """
    从图像中提取答题区域(通过四个黑色定位角块定位)
    使用紧凑度筛选角块
    """
    image = cv2.imread(image_path)
    if image is None:
        print(f"图像读取失败: {image_path}")
        return None

    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (5, 5), 0)
    thresh = cv2.adaptiveThreshold(
        blurred, 255,
        cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
        cv2.THRESH_BINARY_INV, 11, 2
    )

    contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    rects = []
    for cnt in contours:
        area = float(cv2.contourArea(cnt))
        length = float(cv2.arcLength(cnt, True))
        if area <= 0 or length <= 0:
            continue
        compactness = area / length  # 紧凑度

        # 只选紧凑度在合理范围内的轮廓,值越大表示越“实心”、越接近方块
        if 5.5 < compactness < 7.5:
            print(compactness)
            approx = cv2.approxPolyDP(cnt, 0.02 * length, True)
            if len(approx) == 4:
                x, y, w, h = cv2.boundingRect(cnt)
                rects.append((x, y, w, h))

    print(f"共找到满足条件的角块数量: {len(rects)}")


    if len(rects) >= 4:
        xs = [x for (x, y, w, h) in rects] + [x + w for (x, y, w, h) in rects]
        ys = [y for (x, y, w, h) in rects] + [y + h for (x, y, w, h) in rects]
        x_min, x_max = min(xs), max(xs)
        y_min, y_max = min(ys), max(ys)

        cropped = image[y_min:y_max, x_min:x_max]
        return cropped
    else:
        print("未能识别到4个黑色角块请检查图像质量或参数。")
        return None


result = extract_answer_area(r"C:\Users\26950\Desktop\enghish1.jpg")

if result is not None:
    cv2.imwrite("answer_area_cropped.jpg", result)
    print("答题区已保存到 answer_area_cropped.jpg")
else:
    print("答题区提取失败")

切割前enghish1.jpg

切割后:answer_area_cropped.jpg

关于“紧凑度”这个指标
我用的是 紧凑度 = 面积 / 周长,这个值可以用来排除线条、框线等细长的干扰物。

我观察到在我的图像中,角块的紧凑度大概集中在 5.5 到 7.5 左右,当然这可能和图像尺寸、拍摄角度有关。

如果你发现自己的图识别不到角块,可以:

打印出所有轮廓的 面积 / 周长 看看;

调整这两个阈值;

也可以加上其他筛选,比如面积范围、是否是矩形等。

补充说明
之后可以把答题卡上的题目按照题型分类后来批改,可以尝试使用ocr或者具有视觉能力的大模型

目录
相关文章
|
2月前
|
人工智能 自然语言处理 安全
💻 Codex 来了:OpenAI 推出多任务软件工程 AI 代理,开发者工作方式将被重塑?
Codex 是 OpenAI 推出的一款云端智能开发代理,基于优化后的 Codex-1 模型,能够执行从代码编写、Bug 修复到 PR 提交的完整工程任务。通过 ChatGPT 的界面,用户可向 Codex 分配任务,它将在独立沙盒中运行并返回结果。Codex 支持多任务异步处理,遵循项目规范(AGENTS.md),并生成日志与测试报告以确保透明性。作为“AI 参与式开发”的里程碑,Codex 不仅提升效率,还可能重塑开发者角色,使他们从具体编码转向指导 AI 完成任务,推动软件工程进入意图驱动的新时代。
188 16
|
17天前
|
物联网 开发工具
【HarmonyOS】鸿蒙应用蓝牙功能实现 (二)
【HarmonyOS】鸿蒙应用蓝牙功能实现 (二)
70 9
【HarmonyOS】鸿蒙应用蓝牙功能实现 (二)
|
2月前
|
存储 人工智能 Kubernetes
AI 场景深度优化!K8s 集群 OSSFS 2.0 存储卷全面升级,高效访问 OSS 数据
阿里云对象存储OSS是一款海量、安全、低成本、高可靠的云存储服务,是用户在云上存储的高性价比选择…
|
28天前
|
JavaScript 前端开发 API
Node.js中发起HTTP请求的五种方式
以上五种方式,尽管只是冰山一角,但已经足以让编写Node.js HTTP请求的你,在连接世界的舞台上演奏出华丽的乐章。从原生的 `http`到现代的 `fetch`,每种方式都有独特的风格和表现力,让你的代码随着项目的节奏自由地舞动。
181 65
|
1月前
|
自然语言处理 API 开发工具
端午出游高定:通义灵码+高德 MCP 10 分钟定制出游攻略
本文介绍了如何使用通义灵码编程智能体与高德 MCP 2.0 制作北京端午3天旅行攻略页面。首先需下载通义灵码 AI IDE 并获取高德申请的 key,接着通过添加 MCP 服务生成 travel_tips.html 文件,最终在手机端查看已发布上线的攻略。此外还详细说明了利用通义灵码打造专属 MCP 服务的过程,包括开发计划、代码编写、部署及连接服务等步骤,并提供了自由探索的方向及相关资料链接。
500 98
|
1月前
|
人工智能 IDE 开发工具
|
1月前
|
人工智能 Cloud Native 数据管理
邀您参加 KubeCon China 2025 分论坛 | 阿里云 AI 基础设施技术沙龙
KubeCon + CloudNativeCon China 2025 将于6月10-11日在香港合和酒店举办,由CNCF与Linux基金会联合主办。阿里云开发者将在大会上分享多个技术议题,涵盖AI模型分发、Argo工作流、Fluid数据管理等领域。大会前还有阿里云AI基础设施技术沙龙,聚焦AI基础设施及云原生技术实战经验。欢迎扫码报名参与!
284 65
|
1月前
|
人工智能 供应链 安全
实现企业级 MCP 服务统一管理和智能检索的实践
本文将深入剖析 MCP Server 的五种主流架构模式,并结合 Nacos 服务治理框架,为企业级 MCP 部署提供实用指南。
615 63