【问题标题】:How to remove horizontal and vertical lines from an image如何从图像中删除水平线和垂直线
【发布时间】:2017-07-16 14:49:44
【问题描述】:

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

在谷歌搜索时,我发现了一个我认为可行的解决方案: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

【问题讨论】:

  • 你的线条似乎不直。我会从一侧到另一侧进行连续性检测。
  • 关于如何实现这一点的任何指示?
  • 我以前没有实现过类似的东西,但我可以为你写一个基本的伪代码。我敢打赌,还有很多更有效的方法。我假设您的输入数据总是相似的,对吧?
  • 是的,主要是用线条写在纸上。有时线条是水平的,有时是垂直的。
  • 我还会考虑查看概率霍夫变换并删除一定长度和特定方向的线。今晚晚些时候我会试着写一个答案。

标签: python opencv image-processing imagemagick


【解决方案1】:

您的案例没有教程中提供的案例那么简单,您可以根据这些案例制定解决方案。使用这种方法,您将无法 100% 过滤线条,因为字符的水平部分有时会被视为线条。

取决于您的期望(您尚未真正指定),特别是您期望的准确性,您可能想要尝试查找字符而不是查找行。这应该会为您提供更多的稳健性。

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

Result with horizontalsize = int(cols/30)

Result with horizontalsize = int(cols/15)

我再次强调,在您的情况下,这种方法永远不会准确。这是sn-p:

#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)

您还可以尝试对结果进行一些平滑和形态学处理。这应该会使字符更具可读性。

【讨论】:

  • 我对你提到的寻找字符的方法很感兴趣。是否有可能找到字符,将它们裁剪出来,然后将它们放在新的白色背景上?我应该如何寻找角色?轮廓边界?
  • 好吧,现在当我给它更多时间(我认为你可能会接受形态学提供的结果)时,检索字符将非常困难。我认为您可以尝试使用机器学习分别检测每个角色,但这似乎是一个巨大的矫枉过正。我过滤线条的另一个想法是尝试找到轮廓,然后根据它们的长度过滤它们。伪代码会是这样的:a)形态闭合 b)垂直索贝尔 c)找到轮廓 d)根据它们的长度过滤它们
  • 谢谢。我正在尝试复制您的结果。您提供的 sn-p 应该放在哪里?我更改了horizontalsize = int(cols / 15),但不确定您的 sn-p 应该去哪里?在我的代码中 cv2.imshow("horizontal", horizontal) 之前?
  • FWIW,我已经用 ImageMagik 命令更新了这个问题,该命令返回了更好的结果,但仍然不完美
  • 另外,如果线条是垂直的而不是水平的呢?像这样dropbox.com/s/hhxr1pybt76l9sg/vertical_lines.jpg?dl=0
猜你喜欢
  • 2019-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-06
  • 1970-01-01
  • 2022-06-16
  • 1970-01-01
相关资源
最近更新 更多