【问题标题】:Why the vertical line coordinates vary?为什么垂直线坐标不同?
【发布时间】:2020-08-22 08:07:26
【问题描述】:

我正在尝试使用 openCV 和 Azure 读取从表中提取文本。目标是明智地提取文本列。因此,执行的第一步是检测图像(表)中的垂直线。现在使用这些垂直线的坐标作为极端边界,我们识别这些线之间的文本。

从而获得基于Vertical Line Filter的文本。

尽管脚本运行良好,但我观察到了一种情况,其中线坐标不适用于一种特定类型(A 型)的表格。所以调试后我们观察到问题出在表格的标题部分(仅适用于 A 类)。

因此,当我们消除(裁剪图像)表格(A 类)的标题部分时,垂直线坐标是合适的。

坐标的格式为(x,y,w,h)。 x 和 y 是垂直线的最高点。 w 是线的宽度。(在垂直线上它几乎是最大 2 像素)。 h 是垂直线的高度。

这里我附上两个场景: 1. 带标题的表格 - 给出错误的坐标。 Actual Image, Binarized Vertical lines of Actual Image

带有标题的垂直线的坐标(从左到右) - [(9, 0, 14, 439), (213, 0, 93, 426), (337, 28, 1, 398), (397, 29, 1, 410), (470, 29, 1, 397) , (522, 0, 12, 439)]

  1. 没有标题的表格 - 给出了适当的坐标。 Image without headings, Without headings

没有标题的垂直线的坐标(从左到右)- [(7, 0, 1, 404), (303, 0, 1, 391), (335, 0, 1, 391), (395, 0, 1, 404), (468, 0, 1, 391) , (531, 0, 1, 404)]

我们可以观察到第二条线的坐标变化很大,而其他线很接近。 所以问题是,带有标题的图像中的第二条垂直线坐标不正确。可能是什么原因?

【问题讨论】:

标签: python opencv contour


【解决方案1】:

这可能是因为为过滤掉垂直线指定的阈值。

import numpy as np
import sys
import cv2 as cv

def show_wait_destroy(winname, img):
    cv.imshow(winname, img)
    cv.moveWindow(winname, 500, 0)
    cv.waitKey(0)
    cv.destroyWindow(winname)

def main(argv):
    # [load_image]
    # Check number of arguments
    if len(argv) < 1:
        print ('Not enough parameters')
        print ('Usage:\nmorph_lines_detection.py < path_to_image >')
        return -1
    # Load the image
    src = cv.imread(argv[0], cv.IMREAD_COLOR)
    # Check if image is loaded fine
    if src is None:
        print ('Error opening image: ' + argv[0])
        return -1
    # Show source image
    cv.imshow("src", src)
    # [load_image]
    # [gray]
    # Transform source image to gray if it is not already
    if len(src.shape) != 2:
        gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
    else:
        gray = src
    # Show gray image
    show_wait_destroy("gray", gray)
    # [gray]
    # [bin]
    # Apply adaptiveThreshold at the bitwise_not of gray, notice the ~ symbol
    gray = cv.bitwise_not(gray)
    bw = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_MEAN_C, \
                                cv.THRESH_BINARY, 15, -2)
    # Show binary image
    show_wait_destroy("binary", bw)
    # [bin]
    # [init]
    # Create the images that will use to extract the horizontal and vertical lines
    horizontal = np.copy(bw)
    vertical = np.copy(bw)
    # [init]
    # [horiz]
    # Specify size on horizontal axis
    cols = horizontal.shape[1]
    horizontal_size = cols // 30
    # Create structure element for extracting horizontal lines through morphology operations
    horizontalStructure = cv.getStructuringElement(cv.MORPH_RECT, (horizontal_size, 1))
    # Apply morphology operations
    horizontal = cv.erode(horizontal, horizontalStructure)
    horizontal = cv.dilate(horizontal, horizontalStructure)
    # Show extracted horizontal lines
    show_wait_destroy("horizontal", horizontal)
    # [horiz]
    # [vert]
    # Specify size on vertical axis
    rows = vertical.shape[0]
    verticalsize = rows // 10 #####--->>>>>This decides the threshold for vertical line
    # Create structure element for extracting vertical lines through morphology operations
    verticalStructure = cv.getStructuringElement(cv.MORPH_RECT, (1, verticalsize))
    # Apply morphology operations
    vertical = cv.erode(vertical, verticalStructure)
    vertical = cv.dilate(vertical, verticalStructure)
    # Show extracted vertical lines
    show_wait_destroy("vertical", vertical)
    # [vert]
    # [smooth]
    # Inverse vertical image
    vertical = cv.bitwise_not(vertical)
    show_wait_destroy("vertical_bit", vertical)
    '''
    Extract edges and smooth image according to the logic
    1. extract edges
    2. dilate(edges)
    3. src.copyTo(smooth)
    4. blur smooth img
    5. smooth.copyTo(src, edges)
    '''
    # Step 1
    edges = cv.adaptiveThreshold(vertical, 255, cv.ADAPTIVE_THRESH_MEAN_C, \
                                cv.THRESH_BINARY, 3, -2)
    show_wait_destroy("edges", edges)
    # Step 2
    kernel = np.ones((2, 2), np.uint8)
    edges = cv.dilate(edges, kernel)
    show_wait_destroy("dilate", edges)
    # Step 3
    smooth = np.copy(vertical)
    # Step 4
    smooth = cv.blur(smooth, (2, 2))
    # Step 5[![enter image description here][1]][1]
    (rows, cols) = np.where(edges != 0)
    vertical[rows, cols] = smooth[rows, cols]
    # Show final result
    show_wait_destroy("smooth - final", vertical)
    # [smooth]
    return 0
if __name__ == "__main__":
    main(sys.argv[1:])
    ####to run the script use >>>>python image.py path/to/image

【讨论】:

  • 谢谢阿迪尔·斯里瓦斯塔瓦。自适应阈值技术有助于消除标题部分的小噪音。这使标题部分变得杂乱无章。这使得计算线坐标的过程更简单。
猜你喜欢
  • 1970-01-01
  • 2021-08-27
  • 1970-01-01
  • 2023-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-11
  • 1970-01-01
相关资源
最近更新 更多