检测图像中最长的水平线和垂直线

Rah*_*hul 2 python ocr opencv

我有一个pdf 文件,我想从中提取文本。我使用 tesseract 进行 OCR,效果很好。但我的问题是它无法识别文档的 2 列格式,因此它将 2 列合并在一起。

我想在垂直(页面中间)和水平(页面顶部)线上分割文档,然后将其输入超正方体。所以我做了以下事情

预处理步骤:

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

# edge detection
edges = cv2.Canny(gray, 500, 1000, apertureSize=7)

# dialate
kernel = np.ones((5,5),np.float32)/25
edges = cv2.dilate(edges, kernel, iterations=1)

# blur
blur = cv2.GaussianBlur(edges, (7, 7), 0)
Run Code Online (Sandbox Code Playgroud)

这些步骤产生: 预处理图像

现在,我进行线路检测:

minLineLength = 1000
maxLineGap = 500
lines = cv2.HoughLinesP(processed_img, 1, np.pi, 2, minLineLength, maxLineGap)
for line in lines:
    x1, y1, x2, y2 = line[0]
    cv2.line(img, (x1, y1), (x2, y2), (0, 0, 0), 1)
Run Code Online (Sandbox Code Playgroud)

最终结果(将所有图像拼接回 pdf 后)如下所示

我尝试了各种组合thetaminLineLengthmaxLineGap是我能得到的最好结果。任何帮助/指示将不胜感激!

Rav*_*rya 5

下面描述了一种可能的解决方案:

1) 检测水平线。以下是执行此操作的一种方法:

import cv2
import numpy as np


def discard(image):
    image = np.uint8(image)
    _, im_label, stts, _ = cv2.connectedComponentsWithStats(image, connectivity=4)

    msk1 = np.isin(im_label, np.where(stts[:, cv2.CC_STAT_WIDTH] > 500)[0])
    msk2 = np.isin(im_label, np.where(stts[:, cv2.CC_STAT_HEIGHT] > 500)[0])

    image[(msk1 | msk2)] = 0
    return image


img = cv2.imread("page_1.jpg", 0)
img = cv2.resize(img, None, fx=0.35, fy=0.35, interpolation=cv2.INTER_LINEAR)
height, width = img.shape[:2]

# Binarization
thresh = 255 - img
ret, thresh = cv2.threshold(thresh, 5, 255, cv2.THRESH_BINARY)

# Discarding long connected components
without_lines = discard(thresh.copy())
just_lines = cv2.bitwise_xor(thresh, without_lines)
horizontal = just_lines.copy()

# separating horizontal line
h_kernel_large = np.array([[0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0],
                           [1, 1, 1, 1, 1],
                           [0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0]], np.uint8)
horizontal = cv2.morphologyEx(horizontal, cv2.MORPH_OPEN, h_kernel_large, iterations=2)
cv2.imshow("horizontal_line", horizontal)
Run Code Online (Sandbox Code Playgroud)

这就是我们在水平矩阵中得到的: 在此输入图像描述

2) 使用findContoursboundingRect获取该水平线的坐标。然后使用该坐标水平裁剪图像。

upper_portion = img
lower_portion = img
contours, hierarchy = cv2.findContours(horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
    x, y, w, h = cv2.boundingRect(cnt)
    upper_portion = img[0:y, 0:width]
    lower_portion = img[y+h:height, 0:width]

cv2.imshow("upper_portion", upper_portion)
cv2.imshow("lower_portion", lower_portion)
cv2.waitKey(0)
Run Code Online (Sandbox Code Playgroud)

下面是裁剪后的图片。

上部部分: 在此输入图像描述

下部部分: 在此输入图像描述

3) 使用步骤 1 中描述的相同过程检测垂直线并裁剪 lower_portion 图像。

在第一步中,我基本上使用了“连通分量分析”,然后是“开运算”。在这里这里阅读它们