二进制2D矩阵的python轮廓

二进制2D矩阵的python轮廓,python,algorithm,numpy,contour,Python,Algorithm,Numpy,Contour,我想计算一个二元NxM矩阵中形状周围的凸包。凸包算法需要一个坐标列表,所以我采用numpy.argwhere(im)来表示所有的形状点坐标。但是,这些点中的大多数都不是凸包(它们位于形状的内部)。因为凸包计算时间至少与它作为输入得到的点数成正比,所以我设计了一个想法,预先过滤过多的无用点,只传递那些跨越轮廓的点。这个想法很简单,对于二进制NxM矩阵中的每一行,我只取最小和最大索引。例如: im = np.array([[1,1,1,0], [1,0,1,1],

我想计算一个二元NxM矩阵中形状周围的凸包。凸包算法需要一个坐标列表,所以我采用numpy.argwhere(im)来表示所有的形状点坐标。但是,这些点中的大多数都不是凸包(它们位于形状的内部)。因为凸包计算时间至少与它作为输入得到的点数成正比,所以我设计了一个想法,预先过滤过多的无用点,只传递那些跨越轮廓的点。这个想法很简单,对于二进制NxM矩阵中的每一行,我只取最小和最大索引。例如:

im = np.array([[1,1,1,0],
              [1,0,1,1],
              [1,1,0,1],
              [0,0,0,0],
              [0,1,1,1]], dtype=np.bool)
outline = somefunc(im)
然后大纲应该是(元组或5x2 numpy数组,我不介意):

任何紧靠此形状(im)的凸面外壳必须是这些点(轮廓)的子集。换句话说,如果“somefunc()”能够有效地过滤内部点,则可以节省凸包计算的时间

我有实现上述技巧的代码,但我希望有人有更聪明(读得更快)的方法,因为我需要多次运行它。我的密码是:

# I have a 2D binary field. random for the purpose of demonstration.
import numpy as np
im = np.random.random((320,360)) > 0.9

# This is my algorithm so far. Notice that coords is sorted.
coords = np.argwhere(im)
left = np.roll(coords[:,0], 1, axis=0) != coords[:,0]
outline = np.vstack([coords[left], coords[left[1:]], coords[-1]])
我的另一个想法是使用Python的reduce(),因此我只需要运行一次coords列表。但是我很难找到一个好的归约函数

任何帮助都将不胜感激

编辑

与此同时,我找到了一种更快的方法,可以从
im
直接进入
outline
。至少对于大型图像,这要快得多。在明显缺乏外部解决方案的情况下,我将其作为这个问题的解决方案


不过,如果有人知道一种更快的方法,请大声说:)

这项作业似乎完成了与您的最后两个步骤相同的任务:

outline = np.array(dict(reversed(coords)).items() + dict(coords).items())

但是,不知道它是否更快。

对于更一般的解决方案,您可以使用某种边缘检测方法仅查找边缘点。我相信(谷歌…)NumPy有内置的sobel过滤器,可以做到这一点。

在没有可接受答案的情况下,我发布了我最好的工作代码作为解决方案

def outline(im):
    ''' Input binary 2D (NxM) image. Ouput array (2xK) of K (y,x) coordinates
        where 0 <= K <= 2*M.
    '''
    topbottom = np.empty((1,2*im.shape[1]), dtype=np.uint16)
    topbottom[0,0:im.shape[1]] = np.argmax(im, axis=0)
    topbottom[0,im.shape[1]:] = (im.shape[0]-1)-np.argmax(np.flipud(im), axis=0)
    mask      = np.tile(np.any(im, axis=0), (2,))
    xvalues   = np.tile(np.arange(im.shape[1]), (1,2))
    return np.vstack([topbottom,xvalues])[:,mask].T
def大纲(im):
''输入二进制2D(NxM)图像。K(y,x)坐标的输出阵列(2xK)

其中0
fast
没有太大帮助。唉,我在寻找答案,聪明的家伙。@Paul:也许是一个很好的抱怨方法,因为你的问题有一部分不清楚,也没有帮助。如果我们不能得到你的问题(包括你的标签),我们几乎帮不上忙。对于任何到这里的人,请看以下答案:是的,我知道sobel过滤器,它太棒了。事实上,我就是这样得到这些二值图像的。但是,过滤器不提供索引。过滤器将提供位图/矩阵,您可以在其中找到所有索引,就像您在代码中所做的那样。哦,等等,您得到了带有sobel的示例图像,它有太多的点?您是对的。我想在(阈值化的)sobel周围拟合一个多边形。因此,首先,我想减少分数。在机器视觉应用程序中,我一直在使用blob工具中的轮廓输出,但不幸的是,我在OpenCV中没有看到这样的功能。这将是一个优雅的解决方案。太糟糕了,它慢了10倍。
def outline(im):
    ''' Input binary 2D (NxM) image. Ouput array (2xK) of K (y,x) coordinates
        where 0 <= K <= 2*M.
    '''
    topbottom = np.empty((1,2*im.shape[1]), dtype=np.uint16)
    topbottom[0,0:im.shape[1]] = np.argmax(im, axis=0)
    topbottom[0,im.shape[1]:] = (im.shape[0]-1)-np.argmax(np.flipud(im), axis=0)
    mask      = np.tile(np.any(im, axis=0), (2,))
    xvalues   = np.tile(np.arange(im.shape[1]), (1,2))
    return np.vstack([topbottom,xvalues])[:,mask].T