如何从底部填充图像直到使用 OpenCV 检测到边缘?

How to fill an image from bottom side until an edge is detected using OpenCV?

我的目标是能够使用 OpenCV 3 复制 link 中显示的避障方法。他们提供的软件似乎仅适用于 Windows。我认为这可以使用 OpenCV 进行复制。我目前正处于使用 Canny 边缘检测的第 2 步。我不确定我可以使用什么功能来创建步骤 3,其中图像从底部填充直到检测到边缘。任何参考 material 将不胜感激。谢谢

This works by starting at the bottom of the image and proceeding vertically pixel by pixel filling each empty black pixel until a non-black pixel is seen. The filling then stops that vertical column and proceeds with the next.

您不需要任何花哨的 OpenCV 函数。这可以通过简单地使用几个循环来完成。

您可以就地执行此操作,也可以使用用零初始化的单独输出图像。

您所要做的就是从底部开始遍历图像的列。如果一个像素的值为零,将输出像素设置为 255,一旦你击中一个不为零的像素,将剩余的像素设置为 0(或将它们保留为 0)

方法 0

这是完成此操作的标准、基于循环的方法。这个想法是从每一列的底部开始,并将每个像素着色为白色,直到遇到一个白色像素。这是小猪在下面建议的。

h, w = edges.shape[:2]
filled_from_bottom = np.zeros((h, w))
for col in range(w):
    for row in reversed(range(h)):
        if edges[row][col] < 255: filled_from_bottom[row][col] = 255
        else: break

方法一

现在这个方法使用了一些numpy技巧来加速操作。

首先,对于每一列,找到边缘图像中存在非零值的最大行索引。

h, w = img.shape[:2]
row_inds = np.indices((h, w))[0] # gives row indices in shape of img
row_inds_at_edges = row_inds.copy()
row_inds_at_edges[edges==0] = 0 # only get indices at edges, 0 elsewhere
max_row_inds = np.amax(row_inds_at_edges, axis=0) # find the max row ind over each col

然后你可以创建一个布尔数组,其中每个大于或等于最大索引的索引是 True:

inds_after_edges = row_inds >= max_row_inds

然后您可以简单地在布尔数组给出的那些新索引处用白色填充新的空白图像

filled_from_bottom = np.zeros((h, w))
filled_from_bottom[inds_after_edges] = 255

方法二

此方法的内存效率和速度效率稍高。与方法一的基本前提相同。

首先,对于每一列,找到与每一列中的最大值对应的行索引(这将是边缘图像中的白色)。请注意,函数 np.argmax 将 return 数组中最大值的 第一个 实例,而我们需要最后一个:

In case of multiple occurrences of the maximum values, the indices corresponding to the first occurrence are returned.

因此,一个简单的解决方法是垂直翻转数组,但这会为我们提供反向数组的索引。看到后觉得单单解释一下更直观:

h, w = img.shape[:2]
max_row_inds = h - np.argmax(edges[::-1], axis=0)

切片 [::-1] 从上到下反转边缘(或者可以使用 np.flipud)。然后由于数组被翻转,np.argmax 给出了从末尾开始的索引,所以 h - np.argmax 给出了正确定向数组的索引。 np.argmax(..., axis=0) 意味着我们对每列取最大值。

现在我们可以像以前一样创建布尔数组:

row_inds = np.indices((h, w))[0]
inds_after_edges = row_inds >= max_row_inds

此方法稍微好一点的原因是因为我们没有创建数组的副本,而且我们正在删除许多值的数组赋值。


速度测试

第一种方法最简单,但 Python 中最慢。 Python 循环非常慢,而 numpy 操作通常在 C 或基于 Fort运行 的方法中实现,因此它们非常活泼。我用下面的代码测试了差异:

import timeit
times = range(1000)

start_time = timeit.default_timer()
A = [method0(edges) for t in times]
print("method0: ", timeit.default_timer() - start_time)

start_time = timeit.default_timer()
B = [method1(edges) for t in times]
print("method1: ", timeit.default_timer() - start_time)

start_time = timeit.default_timer()
C = [method2(edges) for t in times]
print("method2: ", timeit.default_timer() - start_time)

所以每个方法运行 1000次。结果:

method0: 62.79985192901222
method1: 0.9703722179983743
method2: 0.7760374149947893

正如预期的那样,我们看到最终方法是最快的;只比 method1 快一点,但并不疯狂。然而,基于循环的方法之间的差异是巨大的。


输出