我用 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或者具有视觉能力的大模型

目录
相关文章
|
人工智能
基于qwen2和qwenvl的自动批改作业应用!
针对作业批改中常见的问题,如低质量作业、大量简单作业耗时、需初筛异常作业等,开发了一款自动批改作业的应用。该应用通过备份作业文件、获取文档内容、利用AI生成评语,并保存关键信息与日志,简化了教师的工作流程,提高了效率。应用设计简洁,易于扩展,支持图片转文字处理,适合教育场景使用。
4089 1
基于qwen2和qwenvl的自动批改作业应用!
|
机器学习/深度学习 人工智能 算法
基于Python的图像预处理完整指南
基于Python的图像预处理完整指南
|
9月前
从刷题中抽象出来的二分法思维模型
本文总结了二分法的核心理解与应用技巧,探讨了其适用条件与逻辑构建方法。通过明确单调性与边界性质,帮助读者从“凭感觉写”进阶到“有依据设计”,提升对查找、边界与插入位置等问题的掌控力。
231 1
|
10月前
|
人工智能 自然语言处理 安全
💻 Codex 来了:OpenAI 推出多任务软件工程 AI 代理,开发者工作方式将被重塑?
Codex 是 OpenAI 推出的一款云端智能开发代理,基于优化后的 Codex-1 模型,能够执行从代码编写、Bug 修复到 PR 提交的完整工程任务。通过 ChatGPT 的界面,用户可向 Codex 分配任务,它将在独立沙盒中运行并返回结果。Codex 支持多任务异步处理,遵循项目规范(AGENTS.md),并生成日志与测试报告以确保透明性。作为“AI 参与式开发”的里程碑,Codex 不仅提升效率,还可能重塑开发者角色,使他们从具体编码转向指导 AI 完成任务,推动软件工程进入意图驱动的新时代。
1002 16
|
7月前
|
算法
今天的刷题记录:螺旋矩阵、区间和、开发商购买土地
本篇介绍了三个经典算法问题:螺旋矩阵通过控制边界按圈遍历;区间和利用前缀和优化求和;开发商买地则采用二维前缀和思想,枚举最优切割方式。三题均注重优化思路与边界处理。
106 0
|
JavaScript 前端开发
js时间戳转日期时间
js时间戳转日期时间
587 76
|
10月前
|
人工智能 前端开发 JavaScript
打造了一个未来感十足的图书管理 App 个人页面
打造了一个未来感十足的图书管理 App 个人页面
274 25
|
9月前
|
TensorFlow 算法框架/工具 Docker
手写中文识别模型复现踩坑日记
最近复现了手写中文识别项目 jjcheer/ocrcn_tf2,使用 TensorFlow 2。过程中踩了不少坑:从 Unicode 解码错误、tfrecord 与 label 不对齐,到最后换 Python 3.8 才解决的环境问题。总结教训:用虚拟环境、按项目配版本、写 requirements.txt、多看 issues。复现不易,且行且珍惜。
122 1
|
Kubernetes Cloud Native Linux
如何使用 Containerfile/Dockerfile 构建 .net 镜像?
构建轻量级的 .NET Core 镜像通常涉及到几个关键步骤,主要是选择正确的基础镜像、使用多阶段构建、优化文件结构以及清理不必要的文件。.NET 8 在云原生方面的支持有了显著的增强,这些改进旨在提高性能、减少资源消耗、简化部署流程以及提升应用程序的可观察性和可维护性。
1267 5
如何使用 Containerfile/Dockerfile 构建 .net 镜像?
|
存储 NoSQL 定位技术
如何在Redis中快速推算两地之间的距离?——Geo篇
Redis 3.2 引入Geo类型,支持地理位置数据存储和计算,如距离和范围查询。使用`GEOADD`将城市经纬度添加至`zset`中,通过`GEOPOS`获取坐标,`GEODIST`计算距离,`GEORADIUS`查找指定范围内的城市。Redis的Geo功能适用于快速的地理位置服务,如附近搜索和配送范围分析。利用`ZSET`操作可增删位置数据,简化地理空间应用开发。
454 0

热门文章

最新文章