You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python的OpenCV获取图片最大矩形及付款单数据区域精确边界框

嘿,针对你这个基于CNN的付款单数据识别项目,先搞定最大矩形(付款单区域)检测的需求,我来分享一套适配白色背景扫描件的OpenCV实现方案👇

用OpenCV定位付款单最大矩形区域

核心思路

因为你的扫描件背景是纯白色,付款单本身要么有明显边框,要么和背景存在对比度差异,所以我们可以通过轮廓检测+多边形近似的思路来精准定位:先预处理图像突出前景,再筛选出四边形轮廓,最后取面积最大的那个作为付款单区域。

具体步骤&代码实现

1. 图像预处理:突出付款单前景

首先把彩色图转灰度,然后做反二值化(让白色背景变黑,付款单区域变亮),再通过开运算降噪,去掉扫描产生的小噪点:

import cv2
import numpy as np

# 读取扫描的付款单图像
img = cv2.imread('payment_slip_scan.jpg')
# 转灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 反二值化:适配白色背景,把背景转为黑色,付款单转为白色
_, thresh = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)

# 开运算降噪:先腐蚀再膨胀,消除小噪点
kernel = np.ones((5, 5), np.uint8)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)

2. 检测轮廓并筛选最大矩形轮廓

接下来提取所有外部轮廓,对每个轮廓做多边形近似,筛选出4个顶点的轮廓(也就是矩形/四边形),然后计算面积保留最大的那个:

# 提取外部轮廓(只保留最外层,忽略内部小轮廓)
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

max_area = 0
target_rect = None

for cnt in contours:
    # 计算轮廓周长,用于多边形近似的精度控制
    perimeter = cv2.arcLength(cnt, True)
    # 多边形近似:epsilon取周长的0.02倍,可根据实际情况微调
    approx = cv2.approxPolyDP(cnt, 0.02 * perimeter, True)
    
    # 筛选出4个顶点的轮廓(符合矩形的特征)
    if len(approx) == 4:
        current_area = cv2.contourArea(cnt)
        # 更新最大面积的矩形
        if current_area > max_area:
            max_area = current_area
            target_rect = approx

3. 获取精确Bounding Box并提取区域

拿到目标矩形后,你可以直接获取外接矩形,或者如果付款单是倾斜的,做透视变换把它转正,方便后续CNN识别:

if target_rect is not None:
    # 获取外接矩形的坐标(x,y)和宽高(w,h)
    x, y, w, h = cv2.boundingRect(target_rect)
    # 可视化标记bounding box(可选)
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 3)
    
    # 直接提取付款单区域
    extracted_slip = img[y:y+h, x:x+w]
    cv2.imwrite('extracted_payment_slip.jpg', extracted_slip)
    
    # 处理倾斜付款单:透视变换转正
    # 先对顶点排序,确保顺序是左上、右上、右下、左下
    pts = target_rect.reshape(4, 2)
    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)]
    
    # 定义目标图像的尺寸
    width = int(np.linalg.norm(rect[1] - rect[0]))
    height = int(np.linalg.norm(rect[2] - rect[1]))
    dst = np.array([[0, 0], [width-1, 0], [width-1, height-1], [0, height-1]], dtype="float32")
    
    # 计算透视变换矩阵并应用
    M = cv2.getPerspectiveTransform(rect, dst)
    warped_slip = cv2.warpPerspective(img, M, (width, height))
    cv2.imwrite('warped_payment_slip.jpg', warped_slip)

# 显示检测结果
cv2.imshow('Detected Payment Slip', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

实用调整技巧

  • 二值化阈值:如果付款单和背景对比度低,把240调低(比如230),让付款单区域更清晰地被识别。
  • 多边形近似精度:如果轮廓顶点识别不准,微调0.02这个系数——0.01更严格,0.03更宽松。
  • 降噪核大小:扫描件噪点多的话,把(5,5)调大到(7,7),增强降噪效果。

处理完这一步,你就能得到精准的付款单区域,接下来就可以把这个区域的图像喂给你的CNN模型做数据识别啦~

内容的提问来源于stack exchange,提问作者Josip Mrđen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:32:48