首页 > 解决方案 > 使用 Open CV 屏蔽水平线和垂直线

问题描述

我正在尝试删除此图像中的水平线和垂直线,以便拥有更多不同的文本区域。

在此处输入图像描述

我正在使用以下代码,该代码遵循本指南

image = cv2.imread('image.jpg')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh = cv2.adaptiveThreshold(
                    blurred, 255,
                    cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV,
                    25,
                    15
                )
# Create the images that will use to extract the horizontal and vertical lines
horizontal = np.copy(thresh)
vertical = np.copy(thresh)

# Specify size on horizontal axis
cols = horizontal.shape[1]
horizontal_size = math.ceil(cols / 20)

# Create structure element for extracting horizontal lines through morphology operations
horizontalStructure = cv2.getStructuringElement(cv2.MORPH_RECT, (horizontal_size, 1))

# Apply morphology operations
horizontal = cv2.erode(horizontal, horizontalStructure)
horizontal = cv2.dilate(horizontal, horizontalStructure)

# Show extracted horizontal lines
cv2.imwrite("horizontal.jpg", horizontal)

# Specify size on vertical axis
rows = vertical.shape[0]
verticalsize = math.ceil(rows / 20)

# Create structure element for extracting vertical lines through morphology operations
verticalStructure = cv2.getStructuringElement(cv2.MORPH_RECT, (1, verticalsize))

# Apply morphology operations
vertical = cv2.erode(vertical, verticalStructure)
vertical = cv2.dilate(vertical, verticalStructure)

在此之后,我知道我需要隔离线条并用白线掩盖原始图像,但是我不确定如何继续。

有人有什么建议吗?

标签: pythonpython-3.xopencvcomputer-vision

解决方案


Jeru 的回答已经给了你你想要的。但我想添加一个可能比你目前所拥有的更通用的替代方案。

您正在将彩色图像转换为灰度值,然后应用自适应阈值以尝试查找线条。您对其进行过滤以仅获得长的水平和垂直线,然后使用该蒙版在这些位置将原始图像绘制为白色。

在这里,我们查找所有线条,并将它们从图像中删除,然后用周围的颜色绘制它们。这个过程根本不涉及阈值,所有形态学操作都应用于彩色图像的通道。

理想情况下,我们会使用颜色形态,但这种实现很少见。数学形态学是基于最大值和最小值运算,颜色三元组(即向量)的最大值或最小值没有很好的定义。

因此,我们将以下过程分别应用于三个颜色通道中的每一个。这应该会产生对这个应用程序来说足够好的结果:

  1. 提取红色通道:inputRGB图像,提取第一个通道。这是一张灰度图像。我们将调用此图像channel

  2. 应用顶帽过滤器来检测薄结构:在 上应用小结构元素 (SE)的闭合channelchannel(闭合是膨胀,然后是具有相同 SE 的腐蚀,您正在使用它来也可以找到行)。我们称之为输出thinthin = closing(channel)-channel. 此步骤类似于您的本地阈值,但未应用实际阈值。得到的强度表明线条对背景的暗度。如果添加thinchannel您将填充这些薄结构。这里 SE 的大小决定了什么被认为是“薄”的。

  3. 过滤掉短线,只保留长线:将具有长水平 SEthin的开口应用于 ,并将具有长垂直 SE 的开口应用于thin,并取两个结果中的最大值。我们称之为lines. 请注意,这与您用于生成horizontal和的过程相同vertical。我们没有按照 Jeru 的建议将它们加在一起,而是取最大值。这使得输出强度仍然与channel. (用数学形态学的说法,开口的上界是一个开口)。这里 SE 的长度决定了什么长度足以成为一条线。

  4. 填充原始图像通道中的行:现在只需添加lineschannel. 将结果写入输出图像的第一个通道。

  5. 对其他两个通道重复相同的过程。

使用PyDIP,这是一个非常简单的脚本:

import PyDIP as dip

input = dip.ImageReadTIFF('/home/cris/tmp/T4tbM.tif')
output = input.Copy()

for ii in range(0,3):
   channel = output.TensorElement(ii)
   thin = dip.Closing(channel, dip.SE(5, 'rectangular')) - channel
   vertical = dip.Opening(thin, dip.SE([100,1], 'rectangular'))
   horizontal = dip.Opening(thin, dip.SE([1,100], 'rectangular'))
   lines = dip.Supremum(vertical,horizontal)
   channel += lines # overwrites output image

编辑:

当增加第一个 SE 的大小时,上面设置为 5,大到足以移除示例图像中间的较粗的灰色条,导致包含反转文本“POWERLIFTING”的部分块留在thin.

为了过滤掉这些部分,我们可以改变thin如下的定义:

notthin = dip.Closing(channel, dip.SE(11, 'rectangular'), ["add max"]))
notthin = dip.MorphologicalReconstruction(notthin, channel, 1, "erosion")
thin = notthin - channel

也就是说thin=closing(channel)-channel,我们做的不是thin=reconstruct(closing(channel))-channel。重建只是扩展选定的(不是薄的)结构,以便选择结构的一部分,现在选择完整的结构。现在唯一存在的thin是未连接到较厚结构的线。

我还添加"add max"了一个边界条件——这会导致关闭以白色扩大图像外部的区域,因此将图像边缘的线条视为线条。

输出


推荐阅读