[3D Vision] Minimum Bounding Box Calculation of Spatial Point Sets

0 problem description

Suppose there is a spatial point set, and there are N non-overlapping points.
When N=1, the minimum bounding box is a point: the center is itself, and the radius is infinitely small.
When N=2, the minimum bounding box is a circle: the center is the midpoint of the connection line, and the radius is half the side length
. The three points of the line are connected to form a triangle, and the smallest enclosing circle of acute and right triangles is the circumcircle. The circle with the longest side as the diameter of an obtuse triangle is the smallest circumscribed circle
N=4, four points that are not coplanar form a tetrahedron, and its smallest enclosing sphere? How to calculate? Is it his receiver? It shouldn't be, but how should the outside ball be calculated? Questions worth thinking about.
Then
N>4,...
insert image description here

1 Bounding Box Introduction

There are four common types of bounding boxes:

①Axis-aligned bounding box AABB (Axis-aligned bounding box)
②Bounding Sphere (Bounding Sphere)
③Oriented bounding box OBB (Oriented bounding box)
④Fixed direction convex hull FDH (Fixed directions hulls or k-DOP)

insert image description here

1.1 AABB axis-aligned bounding box

It is defined as the smallest hexahedron containing the object with sides parallel to the coordinate axes. Therefore, to describe an AABB, only six scalars are needed. The structure of AABB is relatively simple, the storage space is small, but the compactness is poor, especially for irregular geometric shapes, the redundant space is large, and when the object is rotated, it cannot be rotated accordingly. The processing objects are rigid and convex, which is not suitable for complex virtual environment situations involving soft body deformations.

1.2 BS Surrounding Ball

It is defined as the smallest sphere that contains the object. To determine the enclosing sphere, it is first necessary to calculate the mean values ​​of the x, y, and z coordinates of the vertices of all the elements in the basic geometric elements that make up the object to determine the center of the enclosing sphere, and then determine the center of the sphere and the coordinates of the three maximum values. The distance between the points determines the radius r. The collision detection of the surrounding sphere is mainly to compare the radius between the two spheres and the distance from the center of the sphere.

1.3 OBB directed bounding box

OBB is a more commonly used bounding box type. It is the smallest cuboid that contains the object and is oriented with respect to the coordinate axes. The biggest feature of OBB is the arbitrariness of its direction, which makes it possible to surround the object as closely as possible according to the shape characteristics of the surrounded object, but it also makes its intersection test complicated. The OBB bounding box is closer to the object than the AABB bounding box and the bounding sphere, which can significantly reduce the number of bounding volumes, thereby avoiding the intersection detection between a large number of bounding volumes. But intersection detection between OBBs is more time-consuming than intersection detection between AABBs or bounding spheres.

1.4 FDH fixed direction convex hull

FDH (k-DOP) is a special convex hull, which inherits the simplicity of AABB, but it must use enough fixed directions to have good spatial compactness. is defined as the convex hull that contains the object and whose normal vectors are taken from a fixed set of orientations (k vectors). FDH surrounds the original object more closely than other bounding volumes, and the created hierarchical tree has fewer nodes, which reduces more redundant calculations during intersection detection, but the intersecting operations between them are more complicated.

2 Bounding box calculation algorithm

2.1 BS Bounding Sphere Calculation Algorithm

2.2.1 naive algorithm

One of the simplest ideas is to calculate the maximum and minimum values ​​of the spatial vertices in the X, Y, and Z directions, then you can get a bounding box composed of 8 vertices. Take the center of the enclosing sphere as the center point of the bounding box, and some people think that the radius of the enclosing sphere can be the maximum distance from the center point to the eight vertices-this is actually not strict. It is better to calculate the maximum distance from the center point to all vertices:

2.2.2 ritter algorithm

Another algorithm is proposed by a person named ritter, so it is called ritter algorithm.

First calculate the two farthest points in the X direction, the two farthest points in the Y direction, and the two farthest points in the Z direction. The range of the three farthest distances is used as the initial diameter, and the center point of the three distances is used as the initial center of the sphere.

Then traverse all points in turn to determine whether the point is within the enclosing sphere. If not, update the bounding sphere. As shown below:

2.2.3 Welzl Algorithm

It's easy to implement with a recursive algorithm:

First generate a sphere based on np-1 points (recursive);
judge whether the npth point is in the sphere, if yes, keep the sphere;
if not, need to generate a new sphere based on the old sphere and the npth point (recursive ). Among them, the npth point must be on the newly generated sphere;
recursive end condition: when one point or two points, a sphere can be generated directly; if all three points are on the sphere, a triangular circumscribed sphere will be generated;

3. Ready-made code library (package)

PCL
scipy
trimesh
open3d

4. The difference between the circumscribed ball and the minimum enclosing ball

Note that the outer ball is different from the minimum enclosing ball I understand.
The yellow one is the minimum enclosing ball, and the green one is the circumscribed ball
insert image description here
insert image description here
insert image description here

5. Calculation of four-point circumscribed ball and minimum enclosing ball

import numpy as np
import matplotlib.pyplot as plt


def get_min_sphere_4points(points):
    """
    Get the minimum radius of a circumscribed sphere that encloses all the points
    """
    def minimum_enclosing_sphere_3points(triangle):
        # Compute the circumcenter of the triangle
        a, b, c = triangle
        ab = b - a
        ac = c - a
        ab_cross_ac = np.cross(ab, ac)
        ab_cross_ac_norm_sq = np.dot(ab_cross_ac, ab_cross_ac)
        if ab_cross_ac_norm_sq == 0:
            # Points are colinear, return a point and radius of infinity
            return a, np.inf
        ab_norm_sq = np.dot(ab, ab)
        ac_norm_sq = np.dot(ac, ac)
        circumcenter = a + (np.cross(ab_norm_sq * ac - ac_norm_sq * ab, ab_cross_ac) / (2 * ab_cross_ac_norm_sq))
        # Calculate the radius of the circumcircle
        radius = np.linalg.norm(circumcenter - a)
        # Check if the circumcenter lies inside the triangle
        if np.all(np.logical_and(circumcenter >= a, circumcenter <= c)):
            return circumcenter, radius
        # Otherwise, the minimum enclosing sphere is the circumcircle
        else:
            center = np.mean(triangle, axis=0)
            radius = np.max(np.linalg.norm(triangle - center, axis=1))
            return center, radius
    def _min_sphere(points, center, radius):
        if len(points) == 0 or len(center) == 3:
            if len(center) == 3:
                # c1, c2, c3 = center
                # return np.array([(c1 + c2 + c3) / 3]), 0
                return minimum_enclosing_sphere_3points(center)
            elif len(center) == 2:
                c1, c2 = center
                return (c1 + c2) / 2, np.linalg.norm(c1 - c2) / 2
            elif len(center) == 1:
                return center[0], 0
            else:
                return None, 0
        else:
            p = points[0]
            points = points[1:]
            c, r = _min_sphere(points, center, radius)
            if c is None or np.linalg.norm(p - c) > r:
                center.append(p)
                c, r = _min_sphere(points, center, radius)
                center.pop()
            return c, r

    if len(points) < 4:
        raise ValueError("At least 4 points are required.")
    np.random.shuffle(points)
    center, radius = _min_sphere(points, [], 0)
    print("Center:", center)
    print("Radius:", radius)
    return center, radius


def fit_circumscribed_sphere_4points(array, tol=1e-6):
    # Check if the the points are co-linear
    D12 = array[1] - array[0]
    D12 = D12 / np.linalg.norm(D12)
    D13 = array[2] - array[0]
    D13 = D13 / np.linalg.norm(D13)
    D14 = array[3] - array[0]
    D14 = D14 / np.linalg.norm(D14)

    chk1 = np.clip(np.abs(np.dot(D12, D13)), 0., 1.)  # 如果共线,chk1=1
    chk2 = np.clip(np.abs(np.dot(D12, D14)), 0., 1.)
    # 求的是反余弦值,如果是1,反余弦值为0(弧度),乘以180/pi,就是0(度),说明共线
    if np.arccos(chk1) / np.pi * 180 < tol or np.arccos(chk2) / np.pi * 180 < tol:
        R = np.inf
        C = np.full(3, np.nan)
        return R, C

    # Check if the the points are co-planar
    n1 = np.linalg.norm(np.cross(D12, D13))
    n2 = np.linalg.norm(np.cross(D12, D14))

    chk = np.clip(np.abs(np.dot(n1, n2)), 0., 1.)
    if np.arccos(chk) / np.pi * 180 < tol:
        R = np.inf
        C = np.full(3, np.nan)
        return R, C

    # Centroid of the sphere
    A = 2 * (array[1:] - np.full(len(array) - 1, array[0]))
    b = np.sum((np.square(array[1:]) - np.square(np.full(len(array) - 1, array[0]))), axis=1)
    C = np.transpose(np.linalg.solve(A, b))

    # Radius of the sphere
    R = np.sqrt(np.sum(np.square(array[0] - C), axis=0))
    print("Center:", C)
    print("Radius:", R)

    return C, R


if __name__ == '__main__':

    # # Define the four points
    p1 = np.array([0, 0, 0])
    p2 = np.array([0, 4, 0])
    p3 = np.array([4, 0, 0])
    p4 = np.array([1, 2, 0])

    points1 = np.array([p1, p2, p3, p4])

    points1 = np.random.rand(4, 3)
    # show_tetrahedron(points1)
    center0, radius0 = fit_circumscribed_sphere_4points(points1)

    center1, radius1 = get_min_sphere_4points(points1)


    from mpl_toolkits.mplot3d import Axes3D

    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    # Plot the points
    ax.scatter(points1[:, 0], points1[:, 1], points1[:, 2], c='b')
    # plot the tetrahedron
    ax.plot(points1[:, 0], points1[:, 1], points1[:, 2], c='b')

    # Plot the sphere1
    u, v = np.mgrid[0:2 * np.pi:20j, 0:np.pi:10j]
    x = center0[0] + radius0 * np.cos(u) * np.sin(v)
    y = center0[1] + radius0 * np.sin(u) * np.sin(v)
    z = center0[2] + radius0 * np.cos(v)
    ax.plot_wireframe(x, y, z, color="g")

    # Plot the sphere2
    u, v = np.mgrid[0:2 * np.pi:20j, 0:np.pi:10j]
    x = center1[0] + radius1 * np.cos(u) * np.sin(v)
    y = center1[1] + radius1 * np.sin(u) * np.sin(v)
    z = center1[2] + radius1 * np.cos(v)
    ax.plot_wireframe(x, y, z, color="y")

    # Set the axes properties
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    ax.set_aspect('equal')
    # Show the plot
    print('Showing the plot...')
    plt.show()

references

Minimum enclosing sphere: naive algorithm and ritter algorithm
Minimum enclosing sphere: welzl algorithm

Guess you like

Origin blog.csdn.net/weixin_43693967/article/details/131162207