python - 使用 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)
在此之后,我知道我需要隔离线条并用白线掩盖原始图像,但是我不确定如何继续。
有人有什么建议吗?
解决方案
Jeru 的回答已经给了你你想要的。但我想添加一个可能比你目前所拥有的更通用的替代方案。
您正在将彩色图像转换为灰度值,然后应用自适应阈值以尝试查找线条。您对其进行过滤以仅获得长的水平和垂直线,然后使用该蒙版在这些位置将原始图像绘制为白色。
在这里,我们查找所有线条,并将它们从图像中删除,然后用周围的颜色绘制它们。这个过程根本不涉及阈值,所有形态学操作都应用于彩色图像的通道。
理想情况下,我们会使用颜色形态,但这种实现很少见。数学形态学是基于最大值和最小值运算,颜色三元组(即向量)的最大值或最小值没有很好的定义。
因此,我们将以下过程分别应用于三个颜色通道中的每一个。这应该会产生对这个应用程序来说足够好的结果:
提取红色通道:取
input
RGB图像,提取第一个通道。这是一张灰度图像。我们将调用此图像channel
。应用顶帽过滤器来检测薄结构:在 上应用小结构元素 (SE)的闭合
channel
和channel
(闭合是膨胀,然后是具有相同 SE 的腐蚀,您正在使用它来也可以找到行)。我们称之为输出thin
。thin = closing(channel)-channel
. 此步骤类似于您的本地阈值,但未应用实际阈值。得到的强度表明线条对背景的暗度。如果添加thin
,channel
您将填充这些薄结构。这里 SE 的大小决定了什么被认为是“薄”的。过滤掉短线,只保留长线:将具有长水平 SE
thin
的开口应用于 ,并将具有长垂直 SE 的开口应用于thin
,并取两个结果中的最大值。我们称之为lines
. 请注意,这与您用于生成horizontal
和的过程相同vertical
。我们没有按照 Jeru 的建议将它们加在一起,而是取最大值。这使得输出强度仍然与channel
. (用数学形态学的说法,开口的上界是一个开口)。这里 SE 的长度决定了什么长度足以成为一条线。填充原始图像通道中的行:现在只需添加
lines
到channel
. 将结果写入输出图像的第一个通道。对其他两个通道重复相同的过程。
使用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"
了一个边界条件——这会导致关闭以白色扩大图像外部的区域,因此将图像边缘的线条视为线条。
推荐阅读
- angular - Angular:从父组件隐藏显示子组件
- hive - Hive - 加载到外部表的默认位置
- vba - Excel:如何在整个列中只允许一个值
- java - 毕加索保留旧图像直到加载新图像
- docker - Docker 构建无法复制文件
- javascript - Nativescript 4 - Http 模块将 +(加号)转换为空格
- ios - 如何从 UIActivityViewController 中排除操作活动?
- sas - LAG 功能的替代方案
- linux - 解释修补/保护 POP SS 后跟 #BP 中断 (INT3) 的 Linux 提交消息
- android - 错误:无法解析“:app@debug/compileClasspath”的依赖关系:无法解析com.android.support:appcompat-v7:27.1.1