如何从图像中删除水平和垂直线条

时间:2017-02-25 20:24:39

标签: python opencv image-processing imagemagick

我的图像是用螺旋笔记本纸上写的文字。纸有水平线。我想从图像中删除水平线。

在谷歌搜索时,我发现了一个我认为可行的解决方案:Extract horizontal and vertical lines by using morphological operations解决方案是在C ++中,所以我将其转换为Python。它适用于该解决方案中提供的示例图像,但它似乎不适用于我的图像。

在我的图片上运行时,我得到了以下结果:

Original Image

Resulting Image

以下是我从C ++翻译的Python代码

 #cpp code converted from     http://docs.opencv.org/3.2.0/d1/dee/tutorial_moprh_lines_detection.html

import cv2
import numpy as np

img = cv2.imread("original.jpg")
img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

img = cv2.bitwise_not(img)
th2 = cv2.adaptiveThreshold(img,255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,15,-2)
cv2.imshow("th2", th2)
cv2.imwrite("th2.jpg", th2)
cv2.waitKey(0)
cv2.destroyAllWindows()

horizontal = th2
vertical = th2
rows,cols = horizontal.shape
horizontalsize = cols / 30
horizontalStructure = cv2.getStructuringElement(cv2.MORPH_RECT, (horizontalsize,1))
horizontal = cv2.erode(horizontal, horizontalStructure, (-1, -1))
horizontal = cv2.dilate(horizontal, horizontalStructure, (-1, -1))
cv2.imshow("horizontal", horizontal)
cv2.imwrite("horizontal.jpg", horizontal)
cv2.waitKey(0)
cv2.destroyAllWindows()

verticalsize = rows / 30
verticalStructure = cv2.getStructuringElement(cv2.MORPH_RECT, (1, verticalsize))
vertical = cv2.erode(vertical, verticalStructure, (-1, -1))
vertical = cv2.dilate(vertical, verticalStructure, (-1, -1))
cv2.imshow("vertical", vertical)
cv2.imwrite("vertical.jpg", vertical)
cv2.waitKey(0)
cv2.destroyAllWindows()

vertical = cv2.bitwise_not(vertical)
cv2.imshow("vertical_bitwise_not", vertical)
cv2.imwrite("vertical_bitwise_not.jpg", vertical)
cv2.waitKey(0)
cv2.destroyAllWindows()

#step1
edges = cv2.adaptiveThreshold(vertical,255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,3,-2)
cv2.imshow("edges", edges)
cv2.imwrite("edges.jpg", edges)
cv2.waitKey(0)
cv2.destroyAllWindows()

#step2
kernel = np.ones((2, 2), dtype = "uint8")
dilated = cv2.dilate(edges, kernel)
cv2.imshow("dilated", dilated)
cv2.imwrite("dilated.jpg", dilated)
cv2.waitKey(0)
cv2.destroyAllWindows()

# step3
smooth = vertical.copy()

#step 4
smooth = cv2.blur(smooth, (4,4))
cv2.imshow("smooth", smooth)
cv2.imwrite("smooth.jpg", smooth)
cv2.waitKey(0)
cv2.destroyAllWindows()

#step 5
(rows, cols) = np.where(img == 0)
vertical[rows, cols] = smooth[rows, cols]

cv2.imshow("vertical_final", vertical)
cv2.imwrite("vertical_final.jpg", vertical)
cv2.waitKey(0)
cv2.destroyAllWindows()

我在原始图像上尝试过ImageMagik,以便删除线条。

我使用 ImageMagik 获得更好的结果,但仍然不完全准确。

convert original -morphology close:3 "1x5: 0,1,1,1,0" original_im.jpg

1 个答案:

答案 0 :(得分:5)

您的案例不如您在解决方案基础上提供的教程中提供的案例那么简单。使用这种方法,您将无法100%过滤线条,因为角色的水平部分有时会被视为线条。

取决于您的期望(您还没有真正指定),特别是您期望的准确性,您可能想要尝试找到字符而不是找到该行。这应该会为您提供更强大的功能。

关于您的代码,通过在图像上找到水平线后(在verticalsize = rows / 30代码行之前)添加几行代码,您可以获得一些结果。我已经制作了一张半尺寸的图片。

Result with horizontalsize = int(cols/30)

Result with horizontalsize = int(cols/15)

同样,我强调在你的情况下那些方法永远不会准确。这是片段:

#inverse the image, so that lines are black for masking
horizontal_inv = cv2.bitwise_not(horizontal)
#perform bitwise_and to mask the lines with provided mask
masked_img = cv2.bitwise_and(img, img, mask=horizontal_inv)
#reverse the image back to normal
masked_img_inv = cv2.bitwise_not(masked_img)
cv2.imshow("masked img", masked_img_inv)
cv2.imwrite("result2.jpg", masked_img_inv)
cv2.waitKey(0)
cv2.destroyAllWindows()

如果我提供的图片有些令人满意,请尝试使用horizontalsize。我还使用了int转换,因为这是getStructuringElement函数所期望的:horizontalsize = int(cols / 30)

您还可以在结果上尝试一些平滑和形态。这应该使角色更具可读性。