我正在尝试删除此图像中的水平和垂直线条,以使文本区域更加鲜明。
我正在使用下面的代码,该代码遵循guide
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)
此后,我知道我需要隔离线条并用白线遮盖原始图像,但是我不确定如何继续。
有人有什么建议吗?
答案 0 :(得分:3)
Jeru's answer已经为您提供了想要的东西。但是我想添加一个替代方法,它可能比您目前所拥有的更普遍。
您正在将彩色图像转换为灰度值,然后应用自适应阈值以尝试找到线条。您可以对此进行过滤,以仅获得较长的水平和垂直线,然后使用该蒙版在这些位置将原始图像绘制为白色。
在这里,我们查找所有线条,并将其从图像中删除,从而使用周围的颜色绘画它们。此过程完全不涉及阈值处理,所有形态学操作都应用于彩色图像的通道。
理想情况下,我们将使用颜色形态,但是这种形态的实现很少。数学形态学基于最大和最小运算,并且颜色三元组(即向量)的最大或最小定义不明确。
因此,我们改为将以下过程分别应用于三个颜色通道。这应该会产生对这个应用程序足够好的结果:
提取红色通道:拍摄input
RGB图像,然后提取第一个通道。这是灰度图像。我们将此图像称为channel
。
应用大礼帽过滤器来检测薄结构::对channel
施加带有小结构元素(SE)的闭合与{{1 }}(闭合是一个扩张,其后是具有相同SE的侵蚀,您也可以使用它来查找线)。我们将此输出称为channel
。 thin
。此步骤类似于您的本地阈值,但未应用实际阈值。所得强度表明线的黑暗程度。背景。如果将thin = closing(channel)-channel
添加到thin
,则将填写这些精简结构。 SE的大小在这里决定了什么被认为是“薄”。
过滤掉短行,只保留长行:将水平长SE的开口应用于channel
,将垂直长SE的开口应用于thin
,并取两个结果中的最大值。我们将其称为thin
。请注意,这与生成lines
和horizontal
所用的过程相同。我们没有按照Jeru的建议将它们加在一起,而是采用了最大值。这样一来,输出强度仍与vertical
中的对比度匹配。 (按照数学形态学的说法,开口的最大值是开口)。 SE的长度在这里决定了足以成为一条线的长度。
填充原始图像通道中的行:现在,只需将channel
添加到lines
。将结果写入输出图像的第一个通道。
与其他两个渠道重复相同的过程。
使用PyDIP这是一个非常简单的脚本:
channel
编辑:
当将第一个SE的大小增加到大于5时,如果大小足够大,可以同时去除示例图像中间的较粗的灰色条,则会导致包含反向文本“ POWERLIFTING”的块的一部分留在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
中。
同样要过滤掉这些部分,我们可以如下更改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
作为边界条件-这导致闭合以白色扩大图像外部的区域,因此将图像边缘的线视为线。
答案 1 :(得分:2)
要在此处进行详细说明,请执行以下操作:
vertical
和horizontal
。这将为您提供包含水平线和垂直线的图像。由于两个图像都是uint8
类型(无符号的8位整数),将它们添加在一起将不会有问题: res = vertical + horizontal
cv2.bitwise_and
:
fin = cv2.bitwise_and(image, image, mask = cv2.bitwise_not(res))
答案 2 :(得分:1)
您想要这样的东西吗?
image = cv2.imread('image.jpg', cv2.IMREAD_UNCHANGED);
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret,binary = cv2.threshold(gray, 170, 255, cv2.THRESH_BINARY)#|cv2.THRESH_OTSU)
V = cv2.Sobel(binary, cv2.CV_8U, dx=1, dy=0)
H = cv2.Sobel(binary, cv2.CV_8U, dx=0, dy=1)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
V = cv2.morphologyEx(V, cv2.MORPH_DILATE, kernel, iterations = 2)
H = cv2.morphologyEx(H, cv2.MORPH_DILATE, kernel, iterations = 2)
rows,cols = image.shape[:2]
mask = np.zeros(image.shape[:2], dtype=np.uint8)
contours = cv2.findContours(V, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[1]
for cnt in contours:
(x,y,w,h) = cv2.boundingRect(cnt)
# manipulate these values to change accuracy
if h > rows/2 and w < 10:
cv2.drawContours(mask, [cnt], -1, 255,-1)
contours = cv2.findContours(H, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[1]
for cnt in contours:
(x,y,w,h) = cv2.boundingRect(cnt)
# manipulate these values to change accuracy
if w > cols/2 and h < 10:
cv2.drawContours(mask, [cnt], -1, 255,-1)
mask = cv2.morphologyEx(mask, cv2.MORPH_DILATE, kernel, iterations = 2)
image[mask == 255] = (255,255,255)
答案 3 :(得分:1)
因此,我通过使用Juke建议的一部分找到了解决方案。最终,我将需要继续使用二进制模式处理图像,以至于我可能会保持这种方式。
首先,添加生成的图像vertical
和horizontal
。这将为您提供包含水平线和垂直线的图像。由于两个图像均为uint8类型(无符号的8位整数),因此添加它们将不是问题:
res = vertical + horizontal
然后,从用于查找行的原始输入图像res
中减去tresh
。这样可以去除白线,并且可以将其应用于其他一些形态转换。
fin = thresh - res
答案 4 :(得分:0)