【问题标题】:Find the end of a curved line in a binary image在二值图像中查找曲线的末端
【发布时间】:2017-01-13 10:21:55
【问题描述】:

我正在寻找一种能够检测曲线末端的算法。我要将二值图像转换为点云作为坐标,我需要找到线的末端,这样我才能开始另一个算法。

我正在考虑对每个点的 N 个最近的“1”像素取向量的平均值,并说具有最长向量的像素必须是端点,因为如果一个点位于一条线的中间,那么向量的平均值将抵消。但是,我认为这一定是图像处理中众所周知的问题,所以我想我会把它扔在这里看看是否有人知道“正确”的算法。

【问题讨论】:

  • 这条线是二值图像吗?如果是这样,端点检测是微不足道的(只有一个邻居的像素),您的问题将是算法是否会产生马刺。

标签: algorithm image-processing


【解决方案1】:

如果线条只有一个或两个像素粗,您可以使用 Malcolm McLean 在评论中建议的方法。

否则,一种方法是为每个红色像素计算同一组件中最远的红色像素,以及最远像素的距离。 (在图论术语中,这两个像素之间的距离是每个像素的离心率。)靠近长线末端的像素将具有最大的离心率,因为它们之间的最短路径指向线路的另一端很长。 (请注意,无论最大偏心率是多少,至少会有两个像素具有它,因为从 a 到 b 的距离与从 b 到 a 的距离相同。)

如果您有 n 个红色像素,则可以在 O(n^2) 时间内计算所有的偏心率(以及相应的最远像素):对于每个像素,依次在该像素处开始 BFS,并取您找到的最深节点作为其最远的像素(可能有几个;任何都可以)。每个 BFS 在 O(n) 时间内运行,因为在任何像素上只有恒定数量的边(4 或 8,取决于您对像素连接的建模方式)。

为了稳健性,您可以考虑选取前 10 或 50 个(等)像素对,并检查它们是否形成了 2 个分离良好、定义明确的集群。然后,您可以将每个集群中的平均位置作为您的 2 个端点。

【讨论】:

  • 这条线比两个像素粗得多,所以我已经实现了你建议的东西。它似乎可以解决问题!
  • 很高兴听到这个消息! :)
【解决方案2】:

如果您对线条应用细化,因此您的线条只有一个像素厚,您可以利用morphologyEX 并在OpenCV 中使用MORPH_HITMISS。本质上,您为每个可能的角落(有 8 个可能)创建一个模板(内核或过滤器)并通过每个角落进行卷积。每个卷积的结果将在内核匹配的地方为 1,否则为 0。所以如果你觉得你可以在 c 中做得更好,你可以手动做同样的事情。

这是一个例子。它将任何 0 和 1 像素粗线的图像作为 input_image。

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

def find_endoflines(input_image, show=0):

kernel_0 = np.array((
        [-1, -1, -1],
        [-1, 1, -1],
        [-1, 1, -1]), dtype="int")

kernel_1 = np.array((
        [-1, -1, -1],
        [-1, 1, -1],
        [1,-1, -1]), dtype="int")

kernel_2 = np.array((
        [-1, -1, -1],
        [1, 1, -1],
        [-1,-1, -1]), dtype="int")

kernel_3 = np.array((
        [1, -1, -1],
        [-1, 1, -1],
        [-1,-1, -1]), dtype="int")

kernel_4 = np.array((
        [-1, 1, -1],
        [-1, 1, -1],
        [-1,-1, -1]), dtype="int")

kernel_5 = np.array((
        [-1, -1, 1],
        [-1, 1, -1],
        [-1,-1, -1]), dtype="int")

kernel_6 = np.array((
        [-1, -1, -1],
        [-1, 1, 1],
        [-1,-1, -1]), dtype="int")

kernel_7 = np.array((
        [-1, -1, -1],
        [-1, 1, -1],
        [-1,-1, 1]), dtype="int")

kernel = np.array((kernel_0,kernel_1,kernel_2,kernel_3,kernel_4,kernel_5,kernel_6, kernel_7))
output_image = np.zeros(input_image.shape)
for i in np.arange(8):
    out = cv2.morphologyEx(input_image, cv2.MORPH_HITMISS, kernel[i,:,:])
    output_image = output_image + out

return output_image

if show == 1:
    show_image = np.reshape(np.repeat(input_image, 3, axis=1),(input_image.shape[0],input_image.shape[1],3))*255
    show_image[:,:,1] = show_image[:,:,1] -  output_image *255
    show_image[:,:,2] = show_image[:,:,2] -  output_image *255
    plt.imshow(show_image)

【讨论】:

  • 即使您有多条线相互交叉且形状怪异,这也能正常工作。
猜你喜欢
  • 1970-01-01
  • 2019-10-18
  • 1970-01-01
  • 2018-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多