Python & OpenCV:如何在无网格表中添加线条

Posted

技术标签:

【中文标题】Python & OpenCV:如何在无网格表中添加线条【英文标题】:Python & OpenCV: How to add lines to gridless table 【发布时间】:2021-07-12 08:58:35 【问题描述】:

我有下表:

我想编写一个脚本,根据表格文本上的自然中断创建行。结果如下所示:

是否有可以绘制这些线条的 OpenCV 实现?我查看了here 和here 问题的答案,但都没有奏效。解决这个问题的最佳方法是什么?

【问题讨论】:

转换为灰度和阈值,这样所有白色的东西都保持白色,而其他所有的东西都变成黑色。然后计算每行中非零像素的数量(np.count_nonzero)。您的线条将绘制在每组全白行的中间。 正是我需要的,谢谢!由于某种原因出现脑梗塞 【参考方案1】:

这是在 Python/OpenCV 中获取水平线的一种方法,方法是计算图像每行中白色像素的数量,以找到它们的中心 y 值。垂直线可以通过类似的过程添加。

输入:

import cv2
import numpy as np

# read image
img = cv2.imread("table.png")
hh, ww = img.shape[:2]

# convert to grayscale 
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# threshold gray image
thresh = cv2.threshold(gray, 254, 255, cv2.THRESH_BINARY)[1]

# count number of non-zero pixels in each row
count = np.count_nonzero(thresh, axis=1)

# threshold count at ww (width of image)
count_thresh = count.copy()
count_thresh[count==ww] = 255
count_thresh[count<ww] = 0
count_thresh = count_thresh.astype(np.uint8)

# get contours
contours = cv2.findContours(count_thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]

# loop over contours and get bounding boxes and ycenter and draw horizontal line at ycenter
result = img.copy()
for cntr in contours:
    x,y,w,h = cv2.boundingRect(cntr)
    ycenter = y+h//2
    cv2.line(result, (0,ycenter), (ww-1,ycenter), (0, 0, 0), 2)

# write results
cv2.imwrite("table_thresh.png", thresh)
cv2.imwrite("table_lines.png", result)

# display results
cv2.imshow("THRESHOLD", thresh)
cv2.imshow("RESULT", result)
cv2.waitKey(0)

阈值图像:

带有线条的结果:

添加

这是一种稍微简单的替代方法。它将图像平均到一列,而不是计算白色像素。

import cv2
import numpy as np

# read image
img = cv2.imread("table.png")
hh, ww = img.shape[:2]

# convert to grayscale 
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# average gray image to one column
column = cv2.resize(gray, (1,hh), interpolation = cv2.INTER_AREA)

# threshold on white
thresh = cv2.threshold(column, 254, 255, cv2.THRESH_BINARY)[1]

# get contours
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]

# loop over contours and get bounding boxes and ycenter and draw horizontal line at ycenter
result = img.copy()
for cntr in contours:
    x,y,w,h = cv2.boundingRect(cntr)
    ycenter = y+h//2
    cv2.line(result, (0,ycenter), (ww-1,ycenter), (0, 0, 0), 2)

# write results
cv2.imwrite("table_lines2.png", result)

# display results
cv2.imshow("RESULT", result)
cv2.waitKey(0)

结果:

【讨论】:

非常有帮助 - 比我想出的更优雅 更新:我运行了代码,它运行良好。再次感谢周到的回答! 在我的回答中添加一个稍微简单的方法。 更简单的方法效果很好。如果它不会太麻烦,我想知道你将如何使用更简单的方法来实现垂直线。我尝试将column = cv2.resize(gray, (1, hh), interpolation=cv2.INTER_AREA) thresh = cv2.threshold(column, 254, 255, cv2.THRESH_BINARY)[1] 更改为row = cv2.resize(gray, (1, ww), interpolation=cv2.INTER_AREA) thresh = cv2.threshold(row, 254, 255, cv2.THRESH_BINARY)[1],但是在调用cv2.drawContours 时,看到轮廓仍在逐行绘制。我错过了什么吗?这是我使用 OpenCV 的第一天 几乎可以使用第一个版本。我只是在中心值方面遇到了麻烦。我目前有xcenter = y+h//2,这会导致线条略微偏离。 (我使用了另一张图片,因为实心标题干扰了列标识。)

以上是关于Python & OpenCV:如何在无网格表中添加线条的主要内容,如果未能解决你的问题,请参考以下文章

opencv在g++&win7下如何配置

OpenCV | 图片与视频的相互转换(C++&Python)

OpenCV|图片与视频的相互转换(C++&Python)

NABCD分析

Python 和 OpenCV:如何裁剪半成形的边界框

达菲系统如何无网连接