Python 使用OpenCV检测表图像中的行数和列数
如何通过Opencv获得图像表中的行数和列数 用于在表中获取我正确获取的框的代码Python 使用OpenCV检测表图像中的行数和列数,python,image,opencv,image-processing,computer-vision,Python,Image,Opencv,Image Processing,Computer Vision,如何通过Opencv获得图像表中的行数和列数 用于在表中获取我正确获取的框的代码 contours, hierarchy = cv2.findContours(img_final_bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) def sort_contours(cnts, method="left-to-right"): # initialize the reverse flag and sort index reverse = False i =
contours, hierarchy = cv2.findContours(img_final_bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
def sort_contours(cnts, method="left-to-right"):
# initialize the reverse flag and sort index
reverse = False
i = 0
# handle if we need to sort in reverse
if method == "right-to-left" or method == "bottom-to-top":
reverse = True
# handle if we are sorting against the y-coordinate rather than
# the x-coordinate of the bounding box
if method == "top-to-bottom" or method == "bottom-to-top":
i = 1
# construct the list of bounding boxes and sort them from top to
# bottom
boundingBoxes = [cv2.boundingRect(c) for c in cnts]
(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
key=lambda b:b[1][i], reverse=reverse))
# return the list of sorted contours and bounding boxes
return (cnts, boundingBoxes)
(contours, boundingBoxes) = sort_contours(contours, method="top-to-bottom")
似乎一个简单的解决方案是首先从左到右查看每个像素是否为黑色(这表示我们找到了一列。然后对行执行相同的操作(如果从上到下每个像素为黑色,则表示它找到了一行) 一个复杂的问题是行的宽度,这意味着在找到白色之前,只能将其计算为1行/列
我可以为此编写代码,但我现在不在家,所以也许其他人可以编写代码,我稍后会删除我的答案。我知道这可能是一条评论,但我没有50%的声誉。这里有一个可能的方法:
上到下对轮廓进行排序。接下来,我们迭代轮廓并找到相应的值以获得(cX,cY)
坐标。我们可以比较每个单元格的cY
值,通过使用偏移量来确定它是新行还是同一行中的单元格。如果cY
值是+/-某个偏移量值,则单元格应该在同一行中。如果大于该值,则表示该单元格在新行中。我们构建了一个模型表,其中表的长度为行,而任何索引的长度为列数
二值图像 删除文本轮廓+反转图像 这是一个通过迭代每个单元格来计算行数和列数的可视化过程 结果
Rows: 7
Columns: 4
代码
将numpy导入为np
从imutils导入等高线
进口cv2
#加载图像、灰度、高斯模糊、大津阈值
image=cv2.imread('1.jpg')
灰色=cv2.CVT颜色(图像,cv2.COLOR\u BGR2GRAY)
模糊=cv2.高斯模糊(灰色,(5,5),0)
thresh=cv2.threshold(模糊,0,255,cv2.thresh\u二进制\u INV+cv2.thresh\u OTSU)[1]
#查找轮廓并删除单元格内的文本
cnts=cv2.查找对象(阈值、cv2.RETR\u树、cv2.链近似值、简单值)
如果len(cnts)==2个其他cnts[1],则cnts=cnts[0]
对于碳纳米管中的碳:
面积=cv2。轮廓面积(c)
如果面积小于4000:
cv2.拉深轮廓(阈值[c],-1,0,-1)
#反转图像
反转=255-阈值
偏移量,旧值,第一个=10,0,真值
可视化=cv2.CVT颜色(反转,cv2.COLOR_GRAY2BGR)
#找到等高线,从上到下排序,然后汇总列/行
cnts=cv2.findContours(反转、cv2.RETR\u树、cv2.CHAIN\u近似、简单)
如果len(cnts)==2个其他cnts[1],则cnts=cnts[0]
(CNT,u)=等高线。等高线排序(CNT,方法=“从上到下”)
对于碳纳米管中的碳:
#找到质心
M=cv2.力矩(c)
cX=int(M[“m10”]/M[“m00”])
cY=int(M[“m01”]/M[“m00”])
#新行
如果(abs(cY)-abs(old_cY))>偏移量:
如果首先:
行,表=[],[]
第一个=错误
旧的
表.追加(行)
行=[]
#同行单元格
如果((abs(cY)-abs(old_cY))另一种方法是首先验证它是否是一个真实的表,因为该hough线变换可以使用,一旦完成,您可以使用上面由fellow解释的方法。请将您的示例图像添加到帖子:)由于限制,无法上载确切的文件,但以下是示例图像。需要在pandas dataframe中转换此图像。使用上述代码从图像中提取框,并使用tesserocr提取这些框中的内容。如果我们可以知道确切数字中的列数和行数,我们可以在pandas和中创建空数据框然后将方框数据放入pandas表中,从而从图像中获取pandas表。请建议是否有其他方法从该图像获取pandas表。我们如何确定面积,即4000,可以是任何预定的阈值面积值。它只是过滤掉任何小的噪声颗粒
import numpy as np
from imutils import contours
import cv2
# Load image, grayscale, Gaussian blur, Otsu's threshold
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5,5), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Find contours and remove text inside cells
cnts = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area < 4000:
cv2.drawContours(thresh, [c], -1, 0, -1)
# Invert image
invert = 255 - thresh
offset, old_cY, first = 10, 0, True
visualize = cv2.cvtColor(invert, cv2.COLOR_GRAY2BGR)
# Find contours, sort from top-to-bottom and then sum up column/rows
cnts = cv2.findContours(invert, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
(cnts, _) = contours.sort_contours(cnts, method="top-to-bottom")
for c in cnts:
# Find centroid
M = cv2.moments(c)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
# New row
if (abs(cY) - abs(old_cY)) > offset:
if first:
row, table = [], []
first = False
old_cY = cY
table.append(row)
row = []
# Cell in same row
if ((abs(cY) - abs(old_cY)) <= offset) or first:
row.append(1)
# Uncomment to visualize
'''
cv2.circle(visualize, (cX, cY), 10, (36, 255, 12), -1)
cv2.imshow('visualize', visualize)
cv2.waitKey(200)
'''
print('Rows: {}'.format(len(table)))
print('Columns: {}'.format(len(table[1])))
cv2.imshow('invert', invert)
cv2.imshow('thresh', thresh)
cv2.waitKey()