python对图片中的表格拆分

背景:为了对图片中的表格进行ocr识别,如果直接识别效果较差,所以将表格拆分成小块一个个识别,然后再拼成表格即可。

拆分规则的表格:

import cv2
import numpy as np"""
事先大概确定表格的相邻横线和竖线间距(通过线切分)
本案例为60和20
"""def split_image(name, path):image = cv2.imread(name)# 二值化gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)binary = cv2.adaptiveThreshold(~gray, 255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 15, -10)# cv2.imwrite('cell.jpg', binary)rows, cols = binary.shapescale = 20# 识别横线kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (cols // scale, 1))eroded = cv2.erode(binary, kernel, iterations=1)dilatedcol = cv2.dilate(eroded, kernel, iterations=1)# cv2.imwrite('dilated1.jpg', dilatedcol)# 识别竖线kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, rows // scale))eroded = cv2.erode(binary, kernel, iterations=1)dilatedrow = cv2.dilate(eroded, kernel, iterations=1)# cv2.imwrite('dilated2.jpg', dilatedrow)# 标识交点bitwiseAnd = cv2.bitwise_and(dilatedcol, dilatedrow)# cv2.imwrite('bitwise.jpg', bitwiseAnd)# 标识表格merge = cv2.add(dilatedcol, dilatedrow)# cv2.imwrite('add.jpg', merge)# 识别黑白图中的白色点ys, xs = np.where(bitwiseAnd > 0)mylisty = []mylistx = []# 通过排序,获取跳变的x和y的值,说明是交点,否则交点会有好多像素值,我只取最后一点i = 0myxs = np.sort(xs)print('myxs', myxs)for i in range(len(myxs) - 1):if (myxs[i + 1] - myxs[i] > 60):mylistx.append(myxs[i])i = i + 1mylistx.append(myxs[i])print('纵向:', mylistx)print(len(mylistx))i = 0myys = np.sort(ys)print('myys', myys)for i in range(len(myys) - 1):if (myys[i + 1] - myys[i] > 20):mylisty.append(myys[i])i = i + 1mylisty.append(myys[i])print('横向', mylisty)print(len(mylisty))for i in range(0, len(mylisty)-1):height = mylisty[i+1] - mylisty[i]# print(height)if height > 100:index = ifor i in range(index, len(mylisty) - 1):for n in range(len(mylistx) - 1):# 缩小ROI范围,自定义浮动,让边缘切的更好一点ROI = image[mylisty[i]:mylisty[i + 1] - 7, mylistx[n]:mylistx[n + 1] - 10]  img_name = name.split('.')[0] + '_' + str(int(i) - index) + '_' + str(n) + '.jpg'img_path = path + '/' + img_namecv2.imwrite(img_path, ROI)if __name__ == '__main__':split_image('111.jpg', 'images')

不规则表格:(各种合并单元格)

经过以下几个步骤,将表格中的线和点全部找出,通过点切分
1.二值化

2.腐蚀膨胀(得到横线和竖线)

3.标识交点

4. 标识表格

示例代码:

import cv2
import os
import numpy as np# 参数调节 -- 默认
params_margin_x = 20 # x轴点相距达到一定的距离,才算两个有效点, 确定线的个数
params_margin_y = 20 # y轴点相距达到一定的距离,才算两个有效点, 确定线的个数
params_dot_margin = 3  # 和平均线的偏移量(对缝隙起作用,可去除点,也可变为独立一个点) 太大:被当成另一条直线上,太小:不把它当成一个独立的点
params_line_x = 10   # x上点个数的差值调节(线不均匀,有的粗有的细,甚至有的不连续)
params_line_y = 10   # y上点个数的差值调节(线不均匀,有的粗有的细,甚至有的不连续)def recognize_line_x(line_xs, line_ys, num, num1, num2):y_line_list = []for k in [-3, -2, -1, 0, 1, 2, 3]:for i in range(len(line_xs)):if line_xs[i] == num + k:if line_ys[i] >= num1 and line_ys[i] <= num2 and line_ys[i] not in y_line_list:y_line_list.append(line_ys[i])len_list = len(y_line_list)return len_listdef recognize_line_y(line_xs, line_ys, num, num1, num2):x_line_list = []for k in [-3, -2, -1, 0, 1, 2, 3]:for i in range(len(line_xs)):if line_ys[i] == num + k:if line_xs[i] >= num1 and line_xs[i] <= num2 and line_xs[i] not in x_line_list:x_line_list.append(line_xs[i])len_list = len(x_line_list)return len_listdef split_image(name, save_path):image = cv2.imread(name)# 二值化(自适应阈值二值化)"""dst = cv2.adaptiveThreshold(src, maxval, thresh_type, type, BlockSize, C)src: 输入图,只能输入单通道图像,通常来说为灰度图dst: 输出图maxval: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值thresh_type: 阈值的计算方法,包含以下2种类型:cv2.ADAPTIVE_THRESH_MEAN_C(通过平均方法取平均值); cv2.ADAPTIVE_THRESH_GAUSSIAN_C(通过高斯).type:二值化操作的类型,与固定阈值函数相同,包含以下5种类型: cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV; cv2.THRESH_TRUNC; cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV.BlockSize: 图片中分块的大小C :阈值计算方法中的常数项"""gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)binary = cv2.adaptiveThreshold(~gray, 255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 15, -10)cv2.imwrite('cell.jpg', binary)rows, cols = binary.shapeprint('rows',  rows)print('cols',  cols)# 原理:这个参数决定了 横线或者竖线的长度scale = 20  # 调节是否能精确识别点(粗、模糊 +   细、清晰  -)# 识别横线"""腐蚀是一种消除边界点,使边界向内部收缩的过程   可以用来消除小且无意义的物体.膨胀是将与物体接触的所有背景点合并到该物体中,使边界向外部扩张的过程   可以用来填补物体中的空洞.用 cols // scale x 1 的 kernel,扫描图像的每一个像素;用 kernel 与其覆盖的二值图像做 “与” 操作;如果都为1,结果图像的该像素为1;否则为0."""# 矩形kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25, 1)) # 用长为 cols//scale ,宽为1 的矩形扫描,能够得到横线eroded = cv2.erode(binary, kernel, iterations=1) # 腐蚀dilatedcol = cv2.dilate(eroded, kernel, iterations=1) # 膨胀cv2.imwrite('dilated1.jpg', dilatedcol)# 识别竖线kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 25)) # 用长为1, 宽为rows//scale 的矩形扫描,能够得到竖线eroded = cv2.erode(binary, kernel, iterations=1)dilatedrow = cv2.dilate(eroded, kernel, iterations=1)cv2.imwrite('dilated2.jpg', dilatedrow)# 标识交点bitwiseAnd = cv2.bitwise_and(dilatedcol, dilatedrow)cv2.imwrite('bitwise.jpg', bitwiseAnd)# 标识表格merge = cv2.add(dilatedcol, dilatedrow)cv2.imwrite('add.jpg', merge)# 识别表格中所有的线line_ys, line_xs = np.where(merge > 0)# 识别黑白图中的白色点ys, xs = np.where(bitwiseAnd > 0)  # 交点附近的坐标mylisty = []mylistx = []# 通过排序,获取跳变的x和y的值,说明是交点,否则交点会有好多像素值,我只取最后一点i = 0myxs = np.sort(xs)# print('myxs', myxs)for i in range(len(myxs) - 1):if (myxs[i + 1] - myxs[i] > params_margin_x):mylistx.append(myxs[i])i = i + 1mylistx.append(myxs[i]) # 包括最后一点,每个点都取的是最大的一个print('纵向:', mylistx)print('纵向线数:', len(mylistx))i = 0myys = np.sort(ys)# print('myys', myys)for i in range(len(myys) - 1):if (myys[i + 1] - myys[i] > params_margin_y):mylisty.append(myys[i])i = i + 1mylisty.append(myys[i])print('横向', mylisty)print('横向线数:', len(mylisty))data_dict = {}data_list = []for i in range(len(myys)):for m in mylisty:for n in mylistx:if abs(m - ys[i]) < params_dot_margin and abs(n - xs[i]) < params_dot_margin and (m, n) not in data_list:data_list.append((m, n))# print('@@@@@@@@@@@@', (ys[i], xs[i]))print('data_list', data_list)print(len(data_list))for m in range(len(mylisty)):line_list = []for i in data_list:if i[0] == mylisty[m]:line_list.append(i)data_dict[m] = sorted(line_list, key=lambda x: x[1])print('data_dict', data_dict)for i in range(len(data_dict) - 1):for index, value in enumerate(data_dict[i]):m = iif index == len(data_dict[i]) - 1:breakfor nn in range(1, len(data_dict[i])):m = imark_num = 0n = index + nnif n == len(data_dict[i]):breakwhile m <= len(data_dict)-2:                      # recognize_line(line_xs, line_ys, 161, 57, 88)if value[1] in [i[1] for i in data_dict[m + 1]] and data_dict[i][n][1] in [i[1] for i in data_dict[m + 1]] and abs(recognize_line_x(line_xs, line_ys, value[1], value[0], data_dict[m + 1][0][0])- (data_dict[m + 1][0][0] - value[0])) <= params_line_y and abs(recognize_line_x(line_xs, line_ys, data_dict[i][n][1], value[0], data_dict[m + 1][0][0])- (data_dict[m + 1][0][0] - value[0])) <= params_line_y and abs(recognize_line_y(line_xs, line_ys, value[0], value[1], data_dict[i][n][1]) - (data_dict[i][n][1] - value[1])) <= params_line_x and abs(recognize_line_y(line_xs, line_ys, data_dict[m + 1][0][0], value[1], data_dict[i][n][1]) - (data_dict[i][n][1] - value[1])) <= params_line_x:mark_num = 1ROI = image[value[0]:data_dict[m + 1][0][0], value[1]:data_dict[i][n][1]]order_num1 = mylisty.index(value[0])order_num2 = mylisty.index(data_dict[m + 1][0][0]) - 1order_num3 = mylistx.index(value[1])order_num4 = mylistx.index(data_dict[i][n][1]) - 1img_name = name.split('/')[1].split('.')[0] + '_' + str(order_num1) + '_' + str(order_num2) + '_' + str(order_num3) + '_' + str(order_num4) + '.jpg'save_path_detail = save_path + 'img_' + name.split('/')[1].split('.')[0]if os.path.exists(save_path_detail):passelse:os.mkdir(save_path_detail)img_path = save_path_detail + '/' + img_namecv2.imwrite(img_path, ROI)breakelse:m += 1if mark_num == 1:breakif __name__ == '__main__':# img_path = 'table_images/'# save_path = 'small_images/'# for i in os.listdir(img_path):#     if i == '12.png' or i == '13.png' or i == '23.png' or i == '7.png' or i == '15.png':#         pass#     else:#         split_image(img_path + i, save_path)split_image('table_images/6.png', 'small_images/')

拆分效果预览:


最后通过命名将拆分的图片拼接在一起:

生成合并单元格的excel:

# 批处理workbook = xlwt.Workbook()worksheet = workbook.add_sheet('sheet1')for i in os.listdir('../small_images/img_21/'):# 直接获取图片的名字excel_name = i.split('_')[0] + '.xls'num1 = i.split('_')[1]num2 = i.split('_')[2]num3 = i.split('_')[3]num4 = i.split('_')[4].split('.')[0]img_path = '../small_images/img_21/' + iim = Image.open(img_path)image = Image.open(img_path).convert('L')  # 'RGB'text = ****  # 识别文字(ocr识别逻辑)worksheet.write_merge(int(num1), int(num2), int(num3), int(num4), text)  # 向第几行第几列     写入获取到的值workbook.save('excel_store/' + excel_name)

python对图片中的表格拆分相关推荐

  1. python提取图片中的表格,Python从图像中的表中提取值

    我要从PDF表格中提取值,然后将数据保存在json文件中, 我使用pytesseract从将pdf转换为的图像中获取文本, 现在的问题是,它给了我一个包含所有数据的大字符串. 我尝试通过SP进行拆分, ...

  2. Python——提取符号、表格拆分数据(指定分隔符、分列)

    目录 1 指定多个分隔符--re.split() 2 表格分列--str.split() 3 提取前几个字符 4 指定分隔符分列 1 指定多个分隔符--re.split() import re tex ...

  3. 产品狗的Python之路(1):按照行数将excel表格拆分成多个

    产品狗的Python之路 (1):使用python将excel表格拆分成多个 背景: 因公司内部数据导入系统限制每一次导入的数据行数,故经常需要将一个几万行的表格拆分成多个,费事费力,所以写了一个小程 ...

  4. 产品狗的Python之路(2):excel表格拆分桌面小程序

    产品狗的Python之路(2):excel表格拆分程序 使用tkinter将excel表格拆分脚本制作了GUI,并使用pyinstaller封装成了桌面程序 import tkinter as tk ...

  5. 人口普查分析:利用python+百度文字识别提取图片中的表格数据

    今天发布了最新的人口普查结果,笔者拿到的文件是pdf格式(网上应该有).之前就一直想实现从pdf提取表格数据,输出为excel.正好这次有公开数据,因此打算用来练个手. 尝试了两种方法: 1.pyth ...

  6. 对图片中的表格进行识别,并转换成excel文件(python、小软件)(批量)

    文章目录 一.python 调用腾讯接口 二.python+百度API识别图片中表格并保存到excel 三.小马识图识别工具 一.python 调用腾讯接口 识别效果就比较拉胯,这个SecretId ...

  7. 80行代码自己动手用python写一个表格拆分与合并小工具

    大家好,我是才哥. 可能是最近加班熬夜太多,这个周末身体不舒服,头痛.冷汗什么的.终于在连着睡了接近2天后,现在慢慢恢复了. 最近有新朋友看到之前<>,想问下有没有免费的小工具,可以进行表 ...

  8. 【python】将一个excel表格按照类目拆分成多个表格

    目的:将一个表格拆分成多个表格,并以分类作为excel的表名保存. 1.首先将本地表格读取进Python中,并将数据进行处理 2.对全部数据进行循环遍历,保存到规定的路径下 全部代码: 1.1导进需要 ...

  9. Python进行表格拆分

    0. 需求:将excel中按照某列中的同一分类的内容将该表格拆分为多个子表 # 拆分为工作表 import pandas as pd import xlrddata = pd.read_excel(r ...

最新文章

  1. python设计及论文-python能否实现学术论文文本分析的功能?
  2. 基于用户投票的排名算法(四):牛顿冷却定律
  3. 【网址收藏】Ubuntu使用OBS录制桌面时黑屏怎么办?
  4. 转载:Linux kernel SPI驱动解释
  5. nginx的模块开发
  6. Aggregate functions cannot be used in the select right after the flatAggregate
  7. MySQL 创建视图
  8. laravel mongodb如何声明数据类型_什么是MongoDB?简介,架构,功能和示例
  9. Redis再入门 codis 对比 Memcached
  10. python访问多个网页_如何使用python请求登录具有多个页面的CAS?
  11. C# 数据库连接字符串拼接
  12. 群晖DS220+ 应用小笔记
  13. 关于AD9371调试笔记
  14. 图像Randon变换含Matlab源码
  15. linux安装docker容器(copy就完了)
  16. Microsoft Visual Studio 2010 Service Pack 1官方下载版(ISO)
  17. 病毒全攻略:我是怎样让你感冒的
  18. [评估指标] 敏感性/特异性/PPV/NPV等指标原理与计算方法
  19. 经典书籍亲子共读云端相约共沐书香
  20. 闪压压缩解压软件官方版

热门文章

  1. 网易126邮箱服务器设置,网易闪电邮企业邮箱设置教程(POP3)
  2. rsyslogd 重启_RE: 服务器定时重启
  3. x390拆机 升级内存和硬盘_iMac 2019 21.5寸 拆机升级内存和固态详细教程
  4. python中面向对象空间时间_python-面向对象的命名空间和组合
  5. 导出数据库dmp出现EXP-00091: Exporting questionable statistics.问题解决!
  6. 局域网监控的分类及模式介绍
  7. 计算机系统的平板有哪些,二合一平板电脑有哪些
  8. PWM脉冲频率可调模块
  9. 京津冀区域AI企业竞争力最强,长三角位列第二,珠三角第三
  10. win8连接wifi成功但受限制_必看丨“格力+”手机APP,智能WiFi连接教程。(含AI语音连接教程)...