如何 图片中的表格数据 图片截取

我们分以下几步进行识别:

  1. 识别表格中的横线,即分割记录(每一行)的横线;
  2. 识别表格中的竖线,即每个列的分割线;
  3. 找到数据所在的单元格;
  4. 利用pyteressact识别单元格的文字。

识别表格中的横线

  识别横线之前,我们先创建一个图片表格识别类(ImageTableOCR),如下:

# -*- coding: utf-8 -*-
import cv2
import pytesseract
import numpy as np

class ImageTableOCR(object):

    # 初始化
    def __init__(self, ImagePath):
        # 读取图片
        self.image = cv2.imread(ImagePath, 1)
        # 把图片转换为灰度模式
        self.gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)

其中self.image为RGB模块的图片,self.gray为灰度模式的图片。
  接下来,我们识别图片中的分割两条记录的横线。注意到,相邻两条记录之间的颜色是不一致的,因此,我们利用图片灰度化后,每一行像素的平均值的差的绝对值来作为相邻两条记录的分割线,这样就能检测出分割两条记录的横线了。具体的识别横线的函数的Python代码如下:(接以上代码)

    # 横向直线检测
    def HorizontalLineDetect(self):

        # 图像二值化
        ret, thresh1 = cv2.threshold(self.gray, 240, 255, cv2.THRESH_BINARY)
        # 进行两次中值滤波
        blur = cv2.medianBlur(thresh1, 3)  # 模板大小3*3
        blur = cv2.medianBlur(blur, 3)  # 模板大小3*3

        h, w = self.gray.shape

        # 横向直线列表
        horizontal_lines = []
        for i in range(h - 1):
            # 找到两条记录的分隔线段,以相邻两行的平均像素差大于120为标准
            if abs(np.mean(blur[i, :]) - np.mean(blur[i + 1, :])) > 120:
                # 在图像上绘制线段
                horizontal_lines.append([0, i, w, i])
                cv2.line(self.image, (0, i), (w, i), (0, 255, 0), 2)

        horizontal_lines = horizontal_lines[1:]
        # print(horizontal_lines)
        return horizontal_lines

首先对图片进行二值化处理,再进行两次中值滤波,这样是为了使相邻两条记录之间的像素区别尽可能大。然后对该图片中的每一行的像素进行检测, 以相邻两行的平均像素差大于120为标准, 识别出分割两条记录的横线。识别后的横线如下:(图片中的绿色线段)

 

识别表格中的竖线

  在这一步中,我们利用opencv中的Hough直线检测方法来检测图片中的竖线。完整的Python代码如下:(接以上代码)

    #  纵向直线检测
    def VerticalLineDetect(self):
        # Canny边缘检测
        edges = cv2.Canny(self.gray, 30, 240)

        # Hough直线检测
        minLineLength = 500
        maxLineGap = 30
        lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, minLineLength, maxLineGap).tolist()
        lines.append([[13, 937, 13, 102]])
        lines.append([[756, 937, 756, 102]])
        sorted_lines = sorted(lines, key=lambda x: x[0])

        # 纵向直线列表
        vertical_lines = []
        for line in sorted_lines:
            for x1, y1, x2, y2 in line:
                # 在图片上绘制纵向直线
                if x1 == x2:
                    print(line)
                    vertical_lines.append((x1, y1, x2, y2))
                    cv2.line(self.image, (x1, y1), (x2, y2), (0, 0, 255), 2)

        return vertical_lines

首先我们对灰度图片进行Canny边缘检测,在此基础上再利用Hough直线检测方法识别图片中的直线,要求识别的最大间距为30,线段长度最小为500,并且为竖直直线(x1 == x2),当然,也有一些人为的因素,那就是笔者自己添加了两条竖直直线([[13, 937, 13, 102]],[[756, 937, 756, 102]])。运行上述方法,输出的结果如下:

[[13, 937, 13, 102]]
[[75, 937, 75, 102]]
[[77, 937, 77, 102]]
[[270, 937, 270, 104]]
[[272, 937, 272, 102]]
[[756, 937, 756, 102]]

识别竖直直线后的图片如下:(图片中的红色线段)

 

可以看到,图片六条竖直的线段都已经完整标记出来了。

识别图片中的单元格

  在识别图片中的单元格之前,我们先来识别每个单元格所在的顶点,也就是上述识别后的横线与竖线的交点。完整的Python代码如下:(接以上代码)

    # 顶点检测
    def VertexDetect(self):
        vertical_lines = self.VerticalLineDetect()
        horizontal_lines = self.HorizontalLineDetect()

        # 顶点列表
        vertex = []
        for v_line in vertical_lines:
            for h_line in horizontal_lines:
                vertex.append((v_line[0], h_line[1]))

        #print(vertex)

        # 绘制顶点
        for point in vertex:
            cv2.circle(self.image, point, 1, (255, 0, 0), 2)

        return vertex

顶点检测后的图片如下:(图片中的蓝色点即为每个单元格的顶点)

 

由此可见,我们识别出来的单元格的顶点是正确的。接着,我们把这些单元格取出来,代码如下:(接以上代码)

 


import cv2
import numpy as np
 

def HorizontalLineDetect(gray,image):

    # 图像二值化
    ret, thresh1 = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY)
    # 进行两次中值滤波
    blur = cv2.medianBlur(thresh1, 3)  # 模板大小3*3
    blur = cv2.medianBlur(blur, 3)  # 模板大小3*3

    h, w = gray.shape

    # 横向直线列表
    horizontal_lines = []
    for i in range(h - 1):
        # 找到两条记录的分隔线段,以相邻两行的平均像素差大于120为标准
        if abs(np.mean(blur[i, :]) - np.mean(blur[i + 1, :])) > 50:
            # 在图像上绘制线段
            horizontal_lines.append([0, i, w, i])
            cv2.line(image, (0, i), (w, i), (0, 255, 0), 2)

    horizontal_lines = horizontal_lines[1:]
    # print(horizontal_lines)
    return horizontal_lines


def VerticalLineDetect(gray,image):
        # Canny边缘检测
        edges = cv2.Canny(gray, 30, 240)

        # Hough直线检测
        #minLineLength = 500
        minLineLength = 500
        maxLineGap = 30
        lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, minLineLength, maxLineGap).tolist()
        lines.append([[13, 937, 13, 102]])
        lines.append([[756, 937, 756, 102]])
        sorted_lines = sorted(lines, key=lambda x: x[0])

        # 纵向直线列表
        vertical_lines = []
        for line in sorted_lines:
            for x1, y1, x2, y2 in line:
                # 在图片上绘制纵向直线
                if x1 == x2:
                    print(line)
                    vertical_lines.append((x1, y1, x2, y2))
                    cv2.line( image, (x1, y1), (x2, y2), (0, 0, 255), 2)

        return vertical_lines


def VertexDetect(gray,image):
    vertical_lines =  VerticalLineDetect(gray,image)
    horizontal_lines =  HorizontalLineDetect(gray,image)

    # 顶点列表
    vertex = []
    for v_line in vertical_lines:
        for h_line in horizontal_lines:
            vertex.append((v_line[0], h_line[1]))

    #print(vertex)

    # 绘制顶点
    for point in vertex:
        cv2.circle(image, point, 1, (255, 0, 0), 2)

    return vertex
    
def CellDetect(gray,image ):
    vertical_lines = VerticalLineDetect(gray,image)
    horizontal_lines = HorizontalLineDetect(gray,image)

    # 顶点列表
    rects = []
    for i in range(0, len(vertical_lines) - 1, 2):
        for j in range(len(horizontal_lines) - 1):
            rects.append((vertical_lines[i][0], horizontal_lines[j][1], \
                          vertical_lines[i + 1][0], horizontal_lines[j + 1][1]))

    # print(rects)
    return rects    
    
path1="C:\\Users\\admin\\Desktop\\ocr\\temp\\"
filename=path1+"dianli.jpg"
    
image = cv2.imread(filename, 1)
        # 把图片转换为灰度模式
gray = cv2.cvtColor( image, cv2.COLOR_BGR2GRAY)


vertex=VertexDetect(gray,image)


rects=CellDetect(gray,image)


cv2.imwrite(path1+"out\\image.jpg", image)
 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值