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

如何使用OpenCV从底部填充图像直到检测到边缘?,opencv,image-processing,computer-vision,python-3.5,opencv3.2,Opencv,Image Processing,Computer Vision,Python 3.5,Opencv3.2,我的目标是能够使用OpenCV 3复制本文所示的避障方法。他们提供的软件似乎只适用于Windows。我认为这是可能的复制使用OpenCV。我目前正在使用Canny边缘检测进行第2步。我不确定我可以使用什么函数来创建步骤3,即从底部填充图像,直到检测到边缘。任何参考资料都将不胜感激。谢谢 这是通过从图像的底部开始并继续进行操作来实现的 垂直逐像素填充每个空黑色像素,直到 可以看到非黑色像素。然后填充将停止该垂直柱 然后继续下一步 你不需要任何花哨的OpenCV函数。这可以通过简单地使用几个循环来

我的目标是能够使用OpenCV 3复制本文所示的避障方法。他们提供的软件似乎只适用于Windows。我认为这是可能的复制使用OpenCV。我目前正在使用Canny边缘检测进行第2步。我不确定我可以使用什么函数来创建步骤3,即从底部填充图像,直到检测到边缘。任何参考资料都将不胜感激。谢谢

这是通过从图像的底部开始并继续进行操作来实现的 垂直逐像素填充每个空黑色像素,直到 可以看到非黑色像素。然后填充将停止该垂直柱 然后继续下一步

你不需要任何花哨的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
然后,您可以创建一个布尔数组,其中每个大于或等于最大索引的索引都是
True

inds_after_edges = row_inds >= max_row_inds
然后你可以简单地用白色填充一个新的空白图像,在布尔数组给出的新索引处

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

方法2 这种方法的内存效率略高,速度效率略高。这与方法1的基本前提相同

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

如果最大值多次出现,则返回与第一次出现对应的索引

所以一个简单的方法是垂直翻转数组,但这会给我们反向数组的索引。我认为在看到一行文字后,解释它更直观:

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或Fortran的方法实现的,因此它们非常快。我用以下代码测试了差异:

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快一点,但不疯狂。然而,基于循环的方法之间的差异是巨大的


输出

当我能够坐下来写一个解决方案时,这可能已经有了答案,但最简单的方法是使用
np.where()
找到二进制图像中所有非零值的位置,然后在where的结果中找到每列的最大行索引,然后设置
image[max_row_index:,column]=255
(或适用于图像类型的任何适当的白色值)。你可能是说效率较低?@YvesDaoust我没有,但可能我错了。我以前的解决方案需要在列索引上循环,而这没有-因此我的意思是这可能比我的答案预编辑快。如果有任何加快速度的建议,我将不胜感激!可以对反转列使用
argmax
,因为边缘s为白色,而不是将非边VAL设置为零,然后将其设置为
amax
,但这仍然需要创建
np.index
数组(尽管不需要复制)…还有其他建议吗?请看@Pieget的答案。@YvesDaoust我刚刚测试过,我的不带循环的方法比Pieget建议的循环快100倍左右。将发布用于测试的代码。可能是用Python编写的,但x100看起来很大。
method0: 62.79985192901222
method1: 0.9703722179983743
method2: 0.7760374149947893