win*_*ind 14 opencv tesseract image imagemagick image-processing
我正在尝试使用Tesseract OCR从图像中提取文本.目前,使用原始输入图像(如下所示),输出质量很差(约50%).但是当我尝试删除输入图像中的所有线条和边框(使用photoshop)时,输出提高了很多(~90%).那么有没有办法以编程方式删除图像中的所有线条和边框(保留文本)(使用OpenCV,Image magick,..)?
原始图片:

期待图片:

nat*_*ncy 20
由于没有人发布完整的 OpenCV 解决方案,这里有一个简单的方法
获取二值图像。加载图像,转换为灰度,以及大津阈值
删除水平线。我们创建一个水平形状的内核,cv2.getStructuringElement然后找到轮廓并删除线条cv2.drawContours
去除垂直线。我们执行相同的操作,但使用垂直形状的内核
加载图像,转换为灰度,然后大津阈值得到二值图像
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]
Run Code Online (Sandbox Code Playgroud)
现在我们创建一个水平内核来检测水平线cv2.getStructuringElement()并找到轮廓cv2.findContours()。为了去除水平线,我们使用cv2.drawContours()白色填充每个水平轮廓。这有效地“擦除”了水平线。这是检测到的绿色水平线
# 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)
Run Code Online (Sandbox Code Playgroud)
类似地,我们创建一个垂直内核来去除垂直线,找到轮廓,并用白色填充每个垂直轮廓。这是检测到的垂直线以绿色突出显示
# 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)
Run Code Online (Sandbox Code Playgroud)
用白色填充水平线和垂直线后,这是我们的结果
注意:根据图像,您可能需要修改内核大小。例如,要捕获更长的水平线,可能需要将水平内核从(40, 1)增加到 say (80, 1)。如果你想检测更粗的水平线,那么你可以增加内核的宽度来说(80, 2). 此外,您可以在执行cv2.morphologyEx(). 同样,您可以修改垂直内核以检测更多或更少的垂直线。增加或减少内核大小时需要权衡,因为您可能会捕获更多或更少的行。同样,这一切都取决于输入图像
完整代码
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()
Run Code Online (Sandbox Code Playgroud)
Mar*_*ell 14
不是使用OpenCV,而只是终端中的一行ImageMagick,但它可以让你知道如何在OpenCV中做到这一点.ImageMagick安装在大多数Linux发行版上,可用于OSX和Windows.
该概念的关键是创建一个新图像,其中每个像素设置为其左侧100个相邻像素的中值和右侧100个相邻像素的中值.这样,具有许多黑色水平邻居(即水平黑线)的像素在输出图像中将是白色的.然后在垂直方向上应用相同的处理以去除垂直线.
您在终端中键入的命令将是:
convert input.png \
\( -clone 0 -threshold 50% -negate -statistic median 200x1 \) \
-compose lighten -composite \
\( -clone 0 -threshold 50% -negate -statistic median 1x200 \) \
-composite result.png
Run Code Online (Sandbox Code Playgroud)
第一行表示加载原始图像.
第二行开始一些"旁边处理",其复制原始图像,对其进行阈值化并将其反转,然后计算任一侧的所有相邻像素100的中值.
第三行然后获取第二行的结果并将其合成在原始图像上,选择每个位置处的较亮像素 - 即我的水平线掩模已变白的像素.
接下来的两行再次做同样的事情,但垂直方向为垂直线.
结果是这样的:
如果我与原始图像不同,就像这样,我可以看到它做了什么:
convert input.png result.png -compose difference -composite diff.png
Run Code Online (Sandbox Code Playgroud)
我想,如果你想删除更多的线条,你可以实际模糊差异图像并将其应用到原始图像.当然,您也可以使用滤波器长度和阈值.
lui*_*izv 12
使用ImageMagick有更好的方法.
ImageMagick有一个简洁的功能,称为形状形态.您可以使用它来识别表格线等形状并将其删除.
convert in.png \
-type Grayscale \
-negate \
-define morphology:compose=darken \
-morphology Thinning 'Rectangle:1x80+0+0<' \
-negate \
out.png
Run Code Online (Sandbox Code Playgroud)
申请后
convert in.png -type Grayscale -negate -define morphology:compose=darken -morphology Thinning 'Rectangle:1x80+0+0<' -negate out.png
Run Code Online (Sandbox Code Playgroud)
这是输出图像:
面临同样的问题.而且我觉得更合乎逻辑的解决方案可能是(参考:提取表格边框)
//assuming, b_w is the binary image
inv = 255 - b_w
horizontal_img = new_img
vertical_img = new_img
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (100,1))
horizontal_img = cv2.erode(horizontal_img, kernel, iterations=1)
horizontal_img = cv2.dilate(horizontal_img, kernel, iterations=1)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,100))
vertical_img = cv2.erode(vertical_img, kernel, iterations=1)
vertical_img = cv2.dilate(vertical_img, kernel, iterations=1)
mask_img = horizontal_img + vertical_img
no_border = np.bitwise_or(b_w, mask_img)
Run Code Online (Sandbox Code Playgroud)
您可以使用 Sobel/Laplacian/Canny 的边缘检测算法,并使用霍夫变换来识别 OpenCV 中的线,并将它们涂成白色以删除线:
laplacian = cv2.Laplacian(img,cv2.CV_8UC1) # Laplacian OR
edges = cv2.Canny(img,80,10,apertureSize = 3) # canny Edge OR
# Output dtype = cv2.CV_8U # Sobel
sobelx8u = cv2.Sobel(img,cv2.CV_8U,1,0,ksize=5)
# Output dtype = cv2.CV_64F. Then take its absolute and convert to cv2.CV_8U
sobelx64f = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
abs_sobel64f = np.absolute(sobelx64f)
sobel_8u = np.uint8(abs_sobel64f)
# Hough's Probabilistic Line Transform
minLineLength = 900
maxLineGap = 100
lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength,maxLineGap)
for line in lines:
for x1,y1,x2,y2 in line:
cv2.line(img,(x1,y1),(x2,y2),(255,255,255),2)
cv2.imwrite('houghlines.jpg',img)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
16223 次 |
| 最近记录: |