如何在以编程方式保留文本的同时删除图像中的所有线条和边框? [英] How to remove all lines and borders in an image while keeping text programmatically?

查看:19
本文介绍了如何在以编程方式保留文本的同时删除图像中的所有线条和边框?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 Tesseract OCR 从图像中提取文本.目前,对于这个原始输入图像,输出的质量很差(大约 50%).但是当我尝试使用 Photoshop 删除所有线条和边框时,输出提高了很多(~90%).有没有办法使用 OpenCV、Imagemagick 或其他技术以编程方式删除图像中的所有线条和边框(保留文本)?

原图:

预期图像:

解决方案

由于没有人发布完整的OpenCV解决方案,这里有一个简单的方法

  1. 获取二进制图像.

    现在我们创建一个水平内核来检测水平线

    类似地,我们创建一个垂直内核来移除垂直线,找到轮廓,并用白色填充每个垂直轮廓.这是检测到的以绿色突出显示的垂直线

    # 删除垂直线vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,40))remove_vertical = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,vertical_kernel,迭代次数=2)cnts = cv2.findContours(remove_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)cnts = cnts[0] 如果 len(cnts) == 2 否则 cnts[1]对于 cnts 中的 c:cv2.drawContours(结果,[c],-1,(255,255,255),5)

    用白色填充水平和垂直线后,这是我们的结果


    注意:根据图像,您可能需要修改内核大小.例如,要捕获更长的水平线,可能需要将水平内核从 (40, 1) 增加到 (80, 1).如果你想检测更粗的水平线,那么你可以增加内核的宽度,比如 (80, 2).此外,您可以在执行 cv2.morphologyEx() 时增加迭代次数.同样,您可以修改垂直内核以检测更多或更少的垂直线.在增加或减少内核大小时需要权衡取舍,因为您可能会捕获更多或更少的行.同样,这一切都取决于输入图像

    完整的代码

    导入 cv2图像 = cv2.imread('1.png')结果 = image.copy()灰色 = cv2.cvtColor(图像,cv2.COLOR_BGR2GRAY)thresh = cv2.threshold(灰色, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]# 去除水平线水平内核 = cv2.getStructuringElement(cv2.MORPH_RECT, (40,1))remove_horizo​​ntal = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,horizo​​ntal_kernel,迭代=2)cnts = cv2.findContours(remove_horizo​​ntal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)cnts = cnts[0] 如果 len(cnts) == 2 否则 cnts[1]对于 cnts 中的 c:cv2.drawContours(结果,[c],-1,(255,255,255),5)# 去除垂直线vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,40))remove_vertical = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,vertical_kernel,迭代次数=2)cnts = cv2.findContours(remove_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)cnts = cnts[0] 如果 len(cnts) == 2 否则 cnts[1]对于 cnts 中的 c:cv2.drawContours(结果,[c],-1,(255,255,255),5)cv2.imshow('thresh', thresh)cv2.imshow('结果', 结果)cv2.imwrite('result.png', 结果)cv2.waitKey()

    I'm trying to extract text from an image using Tesseract OCR. Currently, with this original input image, the output has very poor quality (about 50%). But when I try to remove all lines and borders using photoshop, the output improves a lot (~90%). Is there any way to remove all lines and borders in an image (keeping text) programmatically using OpenCV, Imagemagick,.. or some other technique?

    Original Image:

    Expected Image:

    解决方案

    Since no one has posted a complete OpenCV solution, here's a simple approach

    1. Obtain binary image. Load the image, convert to grayscale, and Otsu's threshold

    2. Remove horizontal lines. We create a horizontal shaped kernel with cv2.getStructuringElement() then find contours and remove the lines with cv2.drawContours()

    3. Remove vertical lines. We do the same operation but with a vertical shaped kernel


    Load image, convert to grayscale, then Otsu's threshold to obtain a binary image

    image = cv2.imread('1.png')
    result = image.copy()
    gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
    

    Now we create a horizontal kernel to detect horizontal lines with cv2.getStructuringElement() and find contours with cv2.findContours() .To remove the horizontal lines, we use cv2.drawContours() and fill in each horizontal contour with white. This effectively "erases" the horizontal line. Here's the detected horizontal lines in green

    # Remove horizontal lines
    horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (40,1))
    remove_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
    cnts = cv2.findContours(remove_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    for c in cnts:
        cv2.drawContours(result, [c], -1, (255,255,255), 5)
    

    Similarly we create a vertical kernel to remove the vertical lines, find contours, and fill each vertical contour with white. Here's the detected vertical lines highlighted in green

    # Remove vertical lines
    vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,40))
    remove_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
    cnts = cv2.findContours(remove_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    for c in cnts:
        cv2.drawContours(result, [c], -1, (255,255,255), 5)
    

    After filling in both horizontal and vertical lines with white, here's our result


    Note: Depending on the image, you may have to modify the kernel size. For instance to capture longer horizontal lines, it may be necessary to increase the horizontal kernel from (40, 1) to say (80, 1). If you wanted to detect thicker horizontal lines, then you could increase the width of the kernel to say (80, 2). In addition, you could increase the number of iterations when performing cv2.morphologyEx(). Similarly, you could modify the vertical kernels to detect more or less vertical lines. There is a trade-off when increasing or decreasing the kernel size as you may capture more or less of the lines. Again, it all varies depending on the input image

    Full code for completeness

    import cv2
    
    image = cv2.imread('1.png')
    result = image.copy()
    gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
    
    # Remove horizontal lines
    horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (40,1))
    remove_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
    cnts = cv2.findContours(remove_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    for c in cnts:
        cv2.drawContours(result, [c], -1, (255,255,255), 5)
    
    # Remove vertical lines
    vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,40))
    remove_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
    cnts = cv2.findContours(remove_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    for c in cnts:
        cv2.drawContours(result, [c], -1, (255,255,255), 5)
    
    cv2.imshow('thresh', thresh)
    cv2.imshow('result', result)
    cv2.imwrite('result.png', result)
    cv2.waitKey()
    

    这篇关于如何在以编程方式保留文本的同时删除图像中的所有线条和边框?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆