【问题标题】:Detect the longest horizontal and vertical line in an image检测图像中最长的水平和垂直线
【发布时间】:2020-09-27 15:46:45
【问题描述】:

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

我想在垂直(页面中间)和水平(页面顶部)行上拆分文档,然后将其提供给 tesseract。所以我做了以下

预处理步骤:

# 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)

这些步骤产生:

现在,我进行线路检测:

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)

最终结果(将所有图像拼接回 pdf 后)看起来像 this

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

【问题讨论】:

    标签: python opencv ocr


    【解决方案1】:

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

    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)
    

    这是我们在水平矩阵中得到的:

    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)
    

    以下是裁剪后的图片。

    上部:

    lower_portion:

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

    在第一步中,我基本上使用了“连通分量分析”,然后是“打开操作”。阅读它们herehere

    【讨论】:

    • 这就像一个魅力!您能否添加更多文本来解释您在步骤 1 中所做的事情?我是 OpenCV 新手,所以我没有完全遵循它。另外,你会如何改变垂直线?只是核矩阵?
    • 没错。你只需要改变内核矩阵。
    • 谢谢!现在接受答案。如果我再次卡住会发表评论:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-13
    • 2013-05-18
    相关资源
    最近更新 更多