问题描述
我正在尝试使用 Tesseract OCR 从图像中提取文本.目前,对于这个原始输入图像,输出的质量很差(大约 50%).但是当我尝试使用 Photoshop 删除所有线条和边框时,输出提高了很多(~90%).有没有办法使用 OpenCV、Imagemagick 或其他技术以编程方式删除图像中的所有线条和边框(保留文本)?
原图:
预期图像:
由于没有人发布完整的OpenCV解决方案,这里有一个简单的方法
获取二进制图像.
现在我们创建一个水平内核来检测水平线
类似地,我们创建一个垂直内核来移除垂直线,找到轮廓,并用白色填充每个垂直轮廓.这是检测到的以绿色突出显示的垂直线
# 删除垂直线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_horizontal = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,horizontal_kernel,迭代=2)cnts = cv2.findContours(remove_horizontal, 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
Obtain binary image. Load the image, convert to grayscale, and Otsu's threshold
Remove horizontal lines. We create a horizontal shaped kernelwith
cv2.getStructuringElement()
then find contoursand remove the lines withcv2.drawContours()
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 withcv2.findContours()
.To remove the horizontal lines, we usecv2.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 performingcv2.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 imageFull 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()
这篇关于如何在以编程方式保留文本的同时删除图像中的所有线条和边框?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!