二进制二维矩阵的python轮廓

发布于 2024-08-09 07:06:58 字数 1293 浏览 9 评论 0原文

我想计算二进制 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 数组,我不介意):

[(0,0),(0,2),(1,0),(1,3),(2,0),(2,3),(4,1),(4,3)]

任何紧密围绕该形状(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(),所以我只需要运行一次坐标列表。但我很难找到一个好的归约函数。

任何帮助将不胜感激!

编辑

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

不过,如果有人知道更快的方法,请说出来:)

I want to calculate a convex hull around a shape in a binary NxM matrix. The convex hull algorithm expects a list of coordinates, so I take numpy.argwhere(im) to have all shape point coordinates. However, most of those points are not contributing to the convex hull (they lie on the inside of the shape). Because convex hull computation time is at least proportional to the number of points that it gets as input, I devised an idea to filter the plethora of useless points on beforehand and only pass those that span the outline. The idea is quite simple, that for each row in the binary NxM matrix I take only the minimal and maximal indices. So for example:

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)

Then outline should read (in tuples or as a 5x2 numpy array, I don't mind):

[(0,0),(0,2),(1,0),(1,3),(2,0),(2,3),(4,1),(4,3)]

Any convex hull tight around this shape (im), must a subset of these points (outline). In other words, if "somefunc()" is efficient in filtering the inside points then it saves time for the convex hull computation.

I have code that does the above trick, but I am hoping someone has a more clever (read faster) approach since I need to run it many many times. The code I have is:

# 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]])

Another idea I had was to use Python's reduce() so I'd need to run over the list of coords only once. But I have difficulty finding a good reducing function.

Any help would greatly be appreciated!

edit

In the meanwhile I have found a faster way to go from im directly to outline. At least with large images this is significantly faster. In the apparent absence of an external solution I am positing it as the solution to this question.

Still, if somebody knows an even faster method, please speak up :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

花想c 2024-08-16 07:06:58

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

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

In the absence of an acceptable answer I post my best working code as the solution.

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
-残月青衣踏尘吟 2024-08-16 07:06:58

这个作业似乎完成了与你最后两个步骤相同的事情:

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

但是不知道它是否更快。

This assignment seems to accomplish the same thing as your last two steps:

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

Don't know if it's any faster, however.

不离久伴 2024-08-16 07:06:58

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

For more general solution, you could use somekind of edge detection method to find only the edge points. I believe (Google..) that NumPy has built-in sobel filter, which will do that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文