无法使用opencv在图像中找到表格位置

问题描述 投票:0回答:2

我想处理图像中的表格数据。为此,我们使用

opencv
读取图像,并通过以下七个步骤找到表格的位置。在图像 7 中,我们计划根据边框进行裁剪。在下面的示例数据中,它完全符合我的要求。这是因为图像内表有黑色外边框。

image = cv2.imread(image_path, cv2.IMREAD_COLOR)

enter image description here

grayscaled_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

enter image description here

_, thresholded_image = cv2.threshold(grayscaled_image, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

enter image description here

inverted_image = cv2.bitwise_not(thresholded_image)

enter image description here

dilated_image = cv2.dilate(inverted_image, None, iterations=3)

enter image description here

contours, _ = cv2.findContours(dilated_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
image_with_all_contours = image.copy()
cv2.drawContours(image_with_all_contours, contours, -1, (0, 255, 0), 2)

enter image description here

rectangular_contours = []
for contour in contours:
    peri = cv2.arcLength(contour, True)
    epsilon = peri * 0.02
    approx = cv2.approxPolyDP(contour, epsilon, True)
    if len(approx) == 4:
        rectangular_contours.append(approx)
image_with_only_rectangular_contours = image.copy()
cv2.drawContours(image_with_only_rectangular_contours, rectangular_contours, -1, (0, 255, 0), 2)

enter image description here

max_area = 0
max_area_contour = None
for contour in rectangular_contours:
    area = cv2.contourArea(contour)
    if area > max_area:
        max_area = area
        max_area_contour = contour

image_with_max_area_contour = image.copy()
cv2.drawContours(image_with_max_area_contour, [max_area_contour], -1, (0, 255, 0), 2)

enter image description here

但是,也有表格没有外边框的情况,如下图所示。实际上,我想要处理的图像外部没有线条。下图是为了解释目的而临时创作的作品。

如上图所示,如果没有外边框,在获取

Thresholded Image
的过程中就会出现问题。后来,通过这样做
cv2.findContours
就不可能留下方形轮廓线了。

最终,我想要的是将“名称”和“收藏夹”列中的值读取到 Pandas 中。我目前正在参考this post遵循该流程。如何选择最大轮廓线的矩形?

enter image description here

enter image description here

enter image description here

尝试 1 by @Ivan

下图是在做

cv2.RETE_EXTERNAL
时应用
cv2.findContours
的情况。轮廓线绘制如下。也就是最外面的部分没有画出来。

enter image description here

尝试 2 by @cards

如果选择 50*30 而不是默认的内核大小,则会选择一个扭曲的矩形,如下所示。

dilated_image = cv2.dilate(inverted_image, np.ones((50, 30), np.uint8), iterations=1)

enter image description here

enter image description here

python opencv
2个回答
0
投票

此代码制作一个掩模图像(与上次检测类似)并获取整个边界矩形:

import cv2
import numpy as np

# Create a completely black mask image
mask = np.zeros((300, 400), dtype=np.uint8)

# Draw white rectangles
cv2.rectangle(mask, (140, 50), (150, 250), (255), thickness=cv2.FILLED)
cv2.rectangle(mask, (50, 100), (350, 150), (255), thickness=cv2.FILLED)

# Find contours
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Get bounding rectangles of contours
bounding_rects = [cv2.boundingRect(cnt) for cnt in contours]

# Find the overall bounding rectangle
x, y, w, h = bounding_rects[0]
max_x = x + w
max_y = y + h
for rect in bounding_rects[1:]:
    x = min(x, rect[0])
    y = min(y, rect[1])
    max_x = max(max_x, rect[0] + rect[2])
    max_y = max(max_y, rect[1] + rect[3])
    w = max_x - x
    h = max_y - y

print(x, y, w, h)

# Draw the overall bounding rectangle
cv2.rectangle(mask, (x, y), (x + w, y + h), (255), 2)

# Save the mask image
cv2.imwrite('mask.png', mask)

# Draw the overall rectangle on a copy of the mask
mask_with_rectangle = mask.copy()
# Draw in gray
cv2.rectangle(mask_with_rectangle, (x, y), (x + w, y + h), (50), 2)

# Save the image with the overall rectangle
cv2.imwrite('mask_with_rectangle.png', mask_with_rectangle)

您可以将

mask
替换为您的
dilated_image


0
投票

我不确定你的例子有多普遍,根据这个我的答案可能会改变。

开始:

%matplotlib notebook
import cv2
import numpy as np
import matplotlib.pyplot as plt
im = cv2.imread("table.jpg") # read im
b, g, r = cv2.split(im) # split to bgr
imRGB = cv2.merge([r,g,b]) # generate rgb image for plotting...

总而言之,查看构成图像的不同颜色总是好的。这是您的图像在 RGB 通道中的样子:

fig, axs = plt.subplots(nrows = 1, ncols = 3, sharex = True, sharey = True)
axs[0].imshow(r)
axs[1].imshow(g)
axs[2].imshow(b)
plt.suptitle("R|G|B")
plt.tight_layout()
for ax in axs:
    ax.axis("off")

我们从中看到,R 通道提供了表格和背景之间最大的对比度。

rgb

因此,阈值化是有意义的:

mask = (r<240).astype(np.uint8)
plt.figure()
plt.imshow(mask)
plt.axis("off")

我们在这里看到阈值确实效果很好:

threshold

我们可以做一个小的闭运算,然后找到轮廓并在图像上绘制轮廓:

mask = (r<240).astype(np.uint8)
maskClosed = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, np.ones((5,5)))
contours = cv2.findContours(maskClosed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
largestContour = max(contours, key=cv2.contourArea)
imRGB = cv2.drawContours(imRGB, [largestContour], 0, (255,0,0), 5)
plt.figure()
plt.imshow(imRGB)
plt.axis("off")

我们得到以下信息:

contoured

已经很好了,我们可以将其与

cv2.boundingRect(largestContour)
一起使用来获取裁剪坐标:
(104, 68, 389, 137)

让我知道这是否适合您..

© www.soinside.com 2019 - 2024. All rights reserved.