【问题标题】:Detect lines in Python OpenCV without applying Gaussian Blur在不应用高斯模糊的情况下检测 Python OpenCV 中的线条
【发布时间】:2021-10-10 00:33:06
【问题描述】:

我正在检测以编程方式生成的无噪音 png 文件中的线条。我通常会使用霍夫线,这需要我首先从精明检测中提供边缘,但精明检测的第一步是应用高斯模糊来消除噪声。有没有一种方法可以在我的原始图像上进行边缘检测而不会故意模糊它?我怀疑这会比先去毛刺产生更好的效果,因为线条已经非常干净且对比度很高。

这是一个使用精明检测和图像的简单示例。每组中的线从 5 像素宽开始,然后下一行是 4,然后是 3、2 和 1。如您所见,canny 检测不能完美工作(2 像素线看起来小于 1 像素那些):

原图:

边缘(canny 检测的结果):

示例代码:


import cv2
import numpy as np
import matplotlib.pylab as plot

# img = cv2.imread("8px_and_2px_lines.png")
img = cv2.imread("5-1px_lines.png")

crop_size = 520
img = img[100:crop_size, 100:crop_size]
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite("5-1px_lines_cropped.png", img)
cv2.imshow("start", img)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
cv2.imshow("canny", edges)
cv2.imwrite("5-1px_lines_cropped_canny.png", edges)
# plot.imshow(edges, cmap="gray")
# plot.show()

lines = cv2.HoughLines(edges, 1, np.pi / 180, 200)
line_length = 3000
for line in lines:
    rho, theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a * rho
    y0 = b * rho
    x1 = int(x0 + line_length * (-b))
    y1 = int(y0 + line_length * (a))
    x2 = int(x0 - line_length * (-b))
    y2 = int(y0 - line_length * (a))
    cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
cv2.imshow("lines", img)
cv2.waitKey()

关于如何更好地对这些图像进行线检测有什么想法吗?我认为 Canny 检测器内置的高斯模糊使线条更难检测。

【问题讨论】:

  • 您的结果没有问题。每条粗线的两侧都有一条 Canny 边缘和 Hough 线。
  • @fmw42 让我困惑的是为什么两条像素宽度的线只有一条边,而一条像素线仍然有两条
  • 有趣的问题!查看 Canny 边缘图像,看看它显示的是一个还是两个
  • @fmw42 我会更新我的答案,我提供的图像实际上是精明的图像。
  • 我相信答案与梯度算子有关,以及它在边缘移动时如何与边缘重叠。例如,取一个垂直 (1,0,-1) 内核,并在值为 0 的背景上,在值为 1 的 1 行边缘上一次垂直移动一个像素,并进行相关乘法和加法。您将看到 -1、0 和 1 的结果有 3 个值。任何非零值都成为边。所以你有 2 个边缘被黑色 0 空间隔开。使用 2 像素边缘,您可以按顺序获得 5 个非零值,没有空格。这被非最大抑制缩小到一条线。

标签: python opencv edge-detection


【解决方案1】:

一种简单的方法是简单地设置阈值,反转,使线条为白色,然后进行骨架化。这是 Python/OpenCV/Skimage 的代码

输入:

import cv2
import numpy as np
import skimage.morphology

img = cv2.imread("lines_horizontal.png")
ht, wd = img.shape[:2]

# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# create a binary thresholded image
thresh = cv2.threshold(gray, 0, 1, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]

# invert so lines are white
thresh = 1 - thresh

# apply skeletonization
skeleton = skimage.morphology.skeletonize(thresh)
skeleton = (255*skeleton).clip(0,255).astype(np.uint8)

# save result
cv2.imwrite("lines_horizontal_skeleton.png", skeleton)

# show results
cv2.imshow("skeleton", skeleton)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果:

请注意,由于端点的骨架化,末端会出现一些失真。

另请注意,OpenCV opencv-contrib-python 有一种类似于骨架化的细化方法。

【讨论】:

    【解决方案2】:

    想必贴出来的图片不代表一般情况,所以我的回答很可能是不恰当的。

    如果您得到垂直线上的像素,没有什么比检测从白色到黑色的过渡更容易的了,反之亦然。由于这条线是完全水平的,因此对单列执行此操作就足够了(但您可以根据需要对每一列重复)!

    通过上述方法,您可以获得线条的两侧,以及它们的原始间距。如果您需要单条轨迹,请成对平均纵坐标。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多