检查点是否在ConvexHull中?

时间:2018-08-09 15:47:39

标签: python numpy scipy

我很难理解如何计算n维点是否在n维ConvexHull中。

在这里提出了一个非常相似的问题(相同): What's an efficient way to find if a point lies in the convex hull of a point cloud?

但是,答案使我感到困惑或似乎对我没有用,我也不知道为什么。

def in_hull(p, hull):
    """ Copied and from the Top Original answer """
    from scipy.spatial import Delaunay
    if not isinstance(hull,Delaunay):
        hull = Delaunay(hull)

    return hull.find_simplex(p)>=0

此功能给我大量使用真实数据的错误或不需要的结果。但是,在调试时,我编写了一个简单的脚本来测试一些明显的期望值:

  

如果我根据一组点构造一个ConvexHull,   当我检查那组要点的“成员资格”时,它们都应该是   “成员”。

results_all = []
for _ in range(5000):
    cloud = np.random.rand(5000, 2)
    result = in_hull(cloud, cloud)
    results_all.append(np.all(result))

arr = np.array(results_all)
print(np.sum(np.logical_not(arr)))

尽管这种情况很少见,但是对于随机生成的数据(5000个中的3个)却似乎失败了,但实际数据的问题更大。我失败的意思是,我实际上遇到了某些情况,其中并非所有要点都被视为成员。

我在做错什么吗?还是完全误会?在这一点上我很困惑,所以很想解释发生的事情。

最后,我想要;给定一个ConvexHull,它是在前一阶段计算的;能够确定点是否在外壳内。

1 个答案:

答案 0 :(得分:2)

对于几乎平坦的单纯形(三角形),find_simplex对象的Delaunay方法似乎是一种边缘情况问题。

这是一个仅用3点即可找到并绘制故障案例的代码:

import matplotlib.pylab as plt
from scipy.spatial import Delaunay
from scipy.spatial import delaunay_plot_2d

for _ in range(5000):
    cloud = np.random.rand(3, 2)

    tri = Delaunay(cloud)

    if np.any( tri.find_simplex(cloud)<0 ):
        print('break at', _)

        delaunay_plot_2d(tri);
        id_break = np.where(tri.find_simplex(cloud)<0)
        plt.plot( *cloud[id_break].ravel(), 'or' );
        break

faulty example

提出的另一种方法here似乎效果很好:

hull = ConvexHull(cloud)

def point_in_hull(point, hull, tolerance=1e-12):
    return all(
        (np.dot(eq[:-1], point) + eq[-1] <= tolerance)
        for eq in hull.equations)

[ point_in_hull(point, hull) for point in cloud ]
# [True, True, True]