opencv 提取表格

该文章介绍了使用OpenCV库进行表格轮廓检测的方法,包括图像预处理、Canny边缘检测、轮廓筛选、最小外接矩形以及透视变换等步骤,以识别和切割图像中的表格。代码示例展示了如何处理单个和多个表格,并提供了GitHub项目链接用于进一步研究。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原理

轮廓检测:寻找连续的像素闭合区域,通过轮廓大小和形状判断是否为单个单元格或者整个表格区域。

结构

表格由横线、纵线构成,线与线交叉形成单元格

效果

在这里插入图片描述

步骤

1、读取图像

img = cv2.imread(imagePath)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

2、识别表格轮廓(canny算法)

canny = cv2.Canny(gray, 200, 255)
# 只要最外层轮廓
_, contours, HIERARCHY = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)   
# 去除大小不合适的轮廓
candidate_table = [cnt for cnt in contours if cv2.contourArea(cnt) > = gray.shape[0] * gray.shape[1] * 0.01 ]
 

3、对表格顶点排序


def get_sorted_rect(rect):
    '''
    获取矩阵排序的四个坐标,方便透视变换使用
    rect包含坐标点为负数时,left_rect包含三个 right_rect包含1个坐标点,或者反之
    @param rect:
    @return:按照左上 右上 右下 左下排列返回

    '''
    try:
        mid_x = (max([x[1] for x in rect]) - min([x[1] for x in rect])) * 0.5 + min([x[1] for x in rect])  # 中间点坐标
        left_rect = [x for x in rect if x[1] < mid_x]
        left_rect.sort(key=lambda x: (x[0], x[1]))
        right_rect = [x for x in rect if x[1] > mid_x]
        right_rect.sort(key=lambda x: (x[0], x[1]))
        sorted_rect = left_rect[0], left_rect[1], right_rect[1], right_rect[0]  # 左上 右上 右下 左下
    except:
        # np.array_equal(order_points(rect), sorted_rect):
        sorted_rect = order_points(rect)

    return sorted_rect


for i in range(len(candidate_table)):
    cnt = candidate_table[i]
    area = cv2.contourArea(cnt)

    # 找到最小的矩形,该矩形可能有方向
    rect = cv2.minAreaRect(cnt)
      # box是四个点的坐标
    box = cv2.boxPoints(rect)  # boxPoints返回四个点顺序:右下→左下→左上→右上(实际上不定
    box = np.int0(box)
    sorted_box = get_sorted_rect(box)  # 左上 右上 右下 左下
    result = [sorted_box[2], sorted_box[3], sorted_box[0], sorted_box[1]]  # 右下 左下 左上 右上

    result = [x.tolist() for x in result]
    table.append(result)

4、切割表格


def get_standard_table_image(gray, table):
    '''
    获取表格图片
    Args:
        gray:
        table:

    Returns:

    '''

    sorted_rect = get_sorted_rect(table)
    gray_z = perTran(gray, sorted_rect)
    binary_z = cv2.adaptiveThreshold(~gray_z, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                     cv2.THRESH_BINARY, 15, -5)

    return gray_z, binary_z


def perTran(image, rect):
    '''
    做透视变换
    image 图像
    rect  四个顶点位置:左上 右上 右下 左下
    '''

    tl, tr, br, bl = rect  # 左下 右下  左上 右上 || topleft topright 左上 右上 右下 左下
    # 计算宽度
    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')
    # 变换矩阵
    rect = np.array(rect, dtype=np.float32)
    dst = np.array(dst, dtype=np.float32)
    M = cv2.getPerspectiveTransform(rect, dst)
    # 透视变换
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
    return warped




def get_muti_tables_images( gray, tables):
    '''
    获取多个table结果


    @param gray: 灰度图
    @param table:表格四个点坐标

    @return:返回解析结果
    '''
    gray_z_list = []
    binary_z_list = [] 
    for index,table in enumerate(tables):
        gray_z, binary_z = get_standard_table_image(gray, table)
        gray_z_list.append(gray_z)
        binary_z_list.append(binary_z)

    return gray_z_list,binary_z_list

get_muti_tables_images( gray, tables):

完整代码

见github项目:https://github.com/dirac472/tableOCR

优化

待补充无框线表格的识别

### 解决 Electron 中 CSP Violation 'connect-src self' 的方法 在 Electron 应用中,`Content-Security-Policy`(CSP)用于增强应用的安全性,防止跨站脚本攻击(XSS)。当遇到 `connect-src 'self'` 导致的违规问题时,可以通过调整 `<meta>` 标签中的 CSP 配置来解决问题。 以下是针对此问题的具体解决方案: #### 修改 CSP 配置 默认情况下,`connect-src 'self'` 表示仅允许同源连接。如果需要访问其他域上的资源,则需扩展 `connect-src` 指令以包含目标域名。例如,在 HTML 文件的 `<head>` 标签下添加如下代码: ```html <meta http-equiv="Content-Security-Policy" content=" default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' https://example.com; "> ``` - **`default-src 'self'`**: 设置全局加载策略,默认只允许加载同源资源[^2]。 - **`style-src 'self' 'unsafe-inline'`**: 允许加载同源样式文件以及行内样式[^2]。 - **`img-src 'self' data:`**: 图片可以从同源地址加载,也可以通过 Data URI 嵌入[^2]。 - **`connect-src 'self' https://example.com`**: 允许向同源服务器发起网络请求,并额外支持向 `https://example.com` 发起请求[^1]。 #### 动态修改 CSP 策略 如果无法提前预知所有可能的目标域名,可以在运行时动态更新 CSP 策略。例如,使用 JavaScript 修改 `<meta>` 标签的内容: ```javascript document.addEventListener('DOMContentLoaded', () => { const meta = document.querySelector('meta[http-equiv="Content-Security-Policy"]'); if (meta) { let currentPolicy = meta.content || ''; // 添加新的 connect-src 权限 const newConnectSrc = "connect-src 'self' https://api.example.com"; if (!currentPolicy.includes(newConnectSrc)) { meta.content += ` ${newConnectSrc}`; } } else { // 如果不存在 CSP meta 标签则创建一个新的 const cspMeta = document.createElement('meta'); cspMeta.httpEquiv = 'Content-Security-Policy'; cspMeta.content = "default-src 'self'; connect-src 'self' https://api.example.com;"; document.head.appendChild(cspMeta); } }); ``` 这段代码会在 DOM 完全加载后检查并更新现有的 CSP 策略,确保新增加的 `connect-src` 不会被遗漏[^1]。 #### 使用 Electron 主进程自定义 WebPreferences 除了前端配置外,还可以通过 Electron 的主进程中设置更灵活的选项。例如,启用 Node.js 集成的同时禁用远程模块,从而减少潜在风险: ```javascript const { BrowserWindow } = require('electron'); let win = new BrowserWindow({ webPreferences: { nodeIntegration: true, contextIsolation: false, // 可选,取决于安全性需求 additionalArguments: ['--disable-web-security'], // 调试用途,生产环境不建议开启 sandbox: true, // 启用沙箱模式提高安全性 }, }); win.loadURL('file://' + __dirname + '/index.html'); ``` 需要注意的是,虽然可以临时关闭部分安全功能以便调试,但在正式发布前应重新评估这些更改带来的安全隐患[^3]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值