Point clouds often contain measurements that lie inside the region formed by their outermost samples. A convex hull reduces that cloud to its smallest convex boundary, which makes the perimeter and enclosed area available for later geometry work.
SciPy's scipy.spatial.ConvexHull accepts a two-dimensional NumPy array and delegates hull construction to Qhull. The returned vertices indexes preserve counterclockwise order for 2-D input, so indexing the original array produces an ordered polygon boundary.
Two interior samples are included to show that they do not become boundary vertices. For a 2-D hull, SciPy reports the perimeter through hull.area and the polygon area through hull.volume; a shoelace calculation independently cross-checks the area.
Steps to calculate a convex hull with SciPy:
- Create the initial convex_hull_demo.py script with SciPy imports and a two-dimensional point array.
$ cat > convex_hull_demo.py <<'PY' import numpy as np from scipy.spatial import ConvexHull points = np.array([ [0.0, 0.0], [2.0, 0.0], [2.0, 1.5], [0.0, 1.0], [0.8, 0.5], [1.2, 0.9], ]) PYThe first four points form the outer quadrilateral, while the last two points lie inside it.
- Append the hull calculation and ordered boundary extraction to convex_hull_demo.py.
$ cat >> convex_hull_demo.py <<'PY' hull = ConvexHull(points) boundary = points[hull.vertices] PY
- Append the boundary coordinate and measurement report to convex_hull_demo.py.
$ cat >> convex_hull_demo.py <<'PY' print("boundary vertex indexes:", hull.vertices.tolist()) print("boundary coordinates:") for index, coordinates in zip(hull.vertices, boundary): print(f" {index}: ({coordinates[0]:.1f}, {coordinates[1]:.1f})") print(f"perimeter: {hull.area:.3f}") print(f"area: {hull.volume:.3f}") PYThe last two points sit inside the quadrilateral, so they should not appear in hull.vertices.
- Append an independent shoelace-area check to convex_hull_demo.py.
$ cat >> convex_hull_demo.py <<'PY' next_boundary = np.roll(boundary, -1, axis=0) shoelace_area = 0.5 * abs( np.sum(boundary[:, 0] * next_boundary[:, 1]) - np.sum(boundary[:, 1] * next_boundary[:, 0]) ) np.testing.assert_allclose(hull.volume, shoelace_area) print(f"shoelace area check: {shoelace_area:.3f}") PYFor 2-D input, hull.area is the perimeter and hull.volume is the polygon area. In higher dimensions, the same attributes mean surface area and volume.
- Run convex_hull_demo.py to calculate the boundary, perimeter, and area.
$ python3 convex_hull_demo.py boundary vertex indexes: [0, 1, 2, 3] boundary coordinates: 0: (0.0, 0.0) 1: (2.0, 0.0) 2: (2.0, 1.5) 3: (0.0, 1.0) perimeter: 6.562 area: 2.500 shoelace area check: 2.500
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.