【问题标题】:Remove noisy lines from an image从图像中删除嘈杂的线条
【发布时间】:2019-01-03 19:17:35
【问题描述】:

我的图像带有一些随机线条,如下所示:

我想对它们进行一些预处理,以消除不需要的噪音(扭曲书写的线条),以便我可以将它们与 OCR(Tesseract)一起使用。
我想到的想法是使用膨胀来消除噪音,然后在第二步中使用腐蚀来修复缺失的部分。
为此,我使用了以下代码:

import cv2
import numpy as np

img = cv2.imread('linee.png', cv2.IMREAD_GRAYSCALE)
kernel = np.ones((5, 5), np.uint8)
img = cv2.dilate(img, kernel, iterations=1)
img = cv2.erode(img, kernel, iterations=1)
cv2.imwrite('delatedtest.png', img)

很遗憾,膨胀效果不佳,噪音线仍然存在。


我尝试更改内核形状,但情况变得更糟:文字被部分或完全删除。
我还发现了一个answer 说可以通过

删除这些行

将具有两个或更少相邻黑色像素的所有黑色像素变为白色。

这对我来说似乎有点复杂,因为我是计算机视觉和 opencv 的初学者。
任何帮助将不胜感激,谢谢。

【问题讨论】:

  • 腐蚀首先去除了最薄的部分......如果你仔细观察,你可以看到。这些线条与您的文字一样粗 - 如果您将它们侵蚀/扩张,您的文字将会消失。通常,您首先侵蚀以去除微小的东西,然后再次膨胀以使幸存者再次变厚……您以相反的方式使用它们。为什么?
  • 尽管图像被污损,您是否尝试通过 OCR 运行它来检查结果?
  • @PatrickArtner 我尝试先使用膨胀然后腐蚀,我也尝试先使用腐蚀然后膨胀,但也没有用。
  • @WaynePhipps 是的,我试过了,但没有给出任何结果,输出为空

标签: python opencv image-processing noise-reduction


【解决方案1】:

path opening 就是为此而发明的。 DIPlib 有一个实现(披露:我在那里实现了它)。作为替代方案,您可以尝试使用我上面链接的论文的the implementation by the authors。该实现没有我在下面使用的the "constrained" mode

这是一个快速演示,说明如何使用它:

import diplib as dip
import matplotlib.pyplot as pp

img = 1 - pp.imread('/home/cris/tmp/DWRTF.png')
lines = dip.PathOpening(img, length=300, mode={'constrained'})

在这里,我们首先反转图像,因为这使以后的其他事情变得更容易。如果不反转,请改用闭合路径。 lines 图片:

接下来我们减去这些线。一个小区域开口会移除被路径开口过滤掉的线的少数孤立像素:

text = img - lines
text = dip.AreaOpening(text, filterSize=5)

但是,我们现在在文本中留出了空白。填补这些并非易事。这是一个快速而肮脏的尝试,您可以将其用作起点:

lines = lines > 0.5
text = text > 0.5
lines -= dip.BinaryPropagation(text, lines, connectivity=-1, iterations=3)
img[lines] = 0

【讨论】:

  • 对不起,我有一个问题:PyDIP 工作得很好,但有时,它会给我这个错误:Traceback (most recent call last): File "pydoc.py", line 5, in <module> lines = dip.PathOpening(img, length=300, mode={'constrained'}) RuntimeError: Image is not scalar in function: void dip::PathOpening(const dip::Image&, const dip::Image&, dip::Image&, dip::uint, const String&, const StringSet&) (/home/hani/cert/pydip/diplib/src/morphology/pathopening.cpp at line number 396) 你知道这个错误的原因吗?可以是图像分辨率吗?
  • @test:“Image is not scalar”表示图像有多个通道,但目前形态函数中只允许使用标量(单通道)图像。我想你有一个 RGB 图像。您应该将其转换为灰度,例如通过dip.ColorSpaceManager.Convert(img, 'gray')
  • 抱歉打扰了,但我收到了这个错误:RuntimeError: Image's number of tensor elements and color space are inconsistent in function: void dip::ColorSpaceManager::Convert(const dip::Image&, dip::Image&, const String&) const (/home/hani/cert/pydip/diplib/src/color/color.cpp at line number 234)
  • @test:做img = dip.Image(img)。现在img.TensorElements() 返回什么? img.ColorSpace() 返回什么?也许你有 3 个张量元素(==通道)但颜色空间是一个空字符串?如果是这样,请执行img.SetColorSpace('RGB'),然后您将能够转换为灰色。另一种选择是使用img=img.TensorElement(0) 来提取第一个通道。 ——显然这个领域还没有经过广泛的用户测试。 :) 我会考虑提高可用性。感谢您指出这一点!
  • @test:太棒了!您应该也可以直接使用 OpenCV 在 PyDIP 中读取的图像,无需先保存。只需使用 OpenCV imread 而不是 pyplot imread
【解决方案2】:

你可以使用createLineSegmentDetector(),一个来自opencv的函数

import cv2

#Read gray image
img = cv2.imread("lines.png",0)

#Create default parametrization LSD
lsd = cv2.createLineSegmentDetector(0)

#Detect lines in the image
lines = lsd.detect(img)[0] #Position 0 of the returned tuple are the detected lines

#Draw the detected lines
drawn_img = lsd.drawSegments(img,lines)

#Save the image with the detected lines
cv2.imwrite('lsdsaved.png', drawn_img)


下一部分代码将只删除长度超过 50 像素的行:

for element in lines:

  #If the length of the line is more than 50, then draw a white line on it
  if (abs(int(element[0][0]) - int(element[0][2])) > 50 or abs(int(element[0][1]) - int(element[0][3])) > 50): 

    #Draw the white line
    cv2.line(img, (int(element[0][0]), int(element[0][1])), (int(element[0][2]), int(element[0][3])), (255, 255, 255), 12)

#Save the final image
cv2.imwrite('removedzz.png', img)

嗯,它不能完美地与当前图像配合使用,但它可能会为不同的图像提供更好的效果。您可以调整要删除的线条的长度和要绘制的白线的粗细来代替已删除的线条。
希望对你有帮助。

【讨论】:

    猜你喜欢
    • 2019-10-28
    • 1970-01-01
    • 1970-01-01
    • 2017-10-04
    • 2018-11-13
    • 2018-07-13
    • 2017-04-03
    • 2014-06-01
    • 2019-04-24
    相关资源
    最近更新 更多