OBB-最小外接矩形包围框-原理-代码实现

前言

  • 定义:OBB是相对于物体方向对齐的包围盒,不再局限于坐标轴对齐,因此包围点云时更加紧密。
  • 优点:能够更好地贴合物体形状,减少空白区域。
  • 缺点:计算较为复杂,需要计算物体的主方向,进行旋转和缩放变换。

Pasted image 20240920104735

算法原理

实现OBB通常涉及以下步骤:

  1. 计算凸包(Convex Hull)
  2. 使用主成分分析(Principal Component Analysis,简称PCA)找到最佳的旋转方向
  3. 根据这些方向确定包围盒的边界

步骤一:计算凸包

凸包是一组点的最小凸多边形,包含所有点,并且所有点都在多边形的边界上或内部。可以使用scipy库中的ConvexHull函数来计算。

import numpy as np
from scipy.spatial import ConvexHull
# 生成数据
mean = [0, 0]
cov = [[3, 1], [1, 2]]
points = np.random.multivariate_normal(mean, cov, 300)

# 计算凸包
convex_hull = ConvexHull(points)
# 可视化
plt.figure(figsize=(10, 8))
plt.scatter(points[:, 0], points[:, 1], s=10, alpha=0.5, label='Points')

Pasted image 20240920105021
图 展示了图包得到的最外层点及其点之间的连线

步骤二:主成分分析(PCA)

PCA可以帮助我们找到数据的主方向。通过分析凸包顶点的协方差矩阵,我们可以得到主要的方向,这些方向定义了OBB的方向。

from sklearn.decomposition import PCA

pca = PCA(n_components=2)
pca.fit(points[convex_hull.vertices])  # 仅对凸包顶点进行PCA

步骤三:根据PCA方向计算OBB

根据PCA的结果,我们可以确定OBB的方向。然后,我们需要计算在这些方向上点的投影,以此来确定矩形的边界。

# OBB计算函数
def compute_obb(points):
    # 使用PCA找到数据的主成分方向
    pca = PCA(n_components=2)
    pca.fit(points)
    
    # 得到主轴
    eigen_vectors = pca.components_
    eigen_values = pca.explained_variance_
    
    # 将点投影到主轴上
    projected_points = np.dot(points, eigen_vectors.T)
    
    # 计算包围盒的边界
    min_proj = np.min(projected_points, axis=0)
    max_proj = np.max(projected_points, axis=0)
    
    # 通过主轴和包围盒的边界重构OBB顶点
    obb_vertices = np.array([
        [min_proj[0], min_proj[1]],
        [min_proj[0], max_proj[1]],
        [max_proj[0], max_proj[1]],
        [max_proj[0], min_proj[1]]
    ])
    
    # 将OBB顶点从PCA空间转换回原始空间
    obb_vertices = np.dot(obb_vertices, eigen_vectors)
    
    return obb_vertices
obb_vertices = compute_obb(points)

上述代码定义了计算OBB的整个过程,从计算凸包到应用PCA,最后确定边界框的角。每步都是基于数学原理进行建模,确保能找到最合适的包围盒。
Pasted image 20240920104735

完整代码

import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from scipy.spatial import ConvexHull

# OBB计算函数
def compute_obb(points):
    # 使用PCA找到数据的主成分方向
    pca = PCA(n_components=2)
    pca.fit(points)
    
    # 得到主轴
    eigen_vectors = pca.components_
    eigen_values = pca.explained_variance_
    
    # 将点投影到主轴上
    projected_points = np.dot(points, eigen_vectors.T)
    
    # 计算包围盒的边界
    min_proj = np.min(projected_points, axis=0)
    max_proj = np.max(projected_points, axis=0)
    
    # 通过主轴和包围盒的边界重构OBB顶点
    obb_vertices = np.array([
        [min_proj[0], min_proj[1]],
        [min_proj[0], max_proj[1]],
        [max_proj[0], max_proj[1]],
        [max_proj[0], min_proj[1]]
    ])
    
    # 将OBB顶点从PCA空间转换回原始空间
    obb_vertices = np.dot(obb_vertices, eigen_vectors)
    
    return obb_vertices

np.random.seed(42)
mean = [0, 0]
cov = [[3, 1], [1, 2]]
points = np.random.multivariate_normal(mean, cov, 300)

# 计算OBB顶点
obb_vertices = compute_obb(points)

# 计算凸包
convex_hull = ConvexHull(points)

# 可视化点云、OBB和凸包
plt.figure(figsize=(10, 8))
plt.scatter(points[:, 0], points[:, 1], s=10, alpha=0.5, label='Points')

# 绘制OBB
obb_polygon = np.vstack([obb_vertices, obb_vertices[0]])  # 闭合OBB多边形
plt.plot(obb_polygon[:, 0], obb_polygon[:, 1], 'r-', linewidth=2, label='OBB')

# 绘制凸包
for simplex in convex_hull.simplices:
    plt.plot(points[simplex, 0], points[simplex, 1], 'g--', linewidth=1)

plt.plot(points[convex_hull.vertices, 0], points[convex_hull.vertices, 1], 'g-', linewidth=2, label='Convex Hull')
plt.scatter(points[convex_hull.vertices, 0], points[convex_hull.vertices, 1], color='green')

plt.title('OBB and Convex Hull Visualization')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
plt.legend()
plt.axis('equal')
plt.grid(True)
plt.show()

利用Open3D使用OBB算法

import open3d as o3d
import numpy as np

# 读取点云 txt 文件,假设文件名为 'point_cloud.txt'
file_path = './data/5.txt'

# 使用 numpy 读取数据
point_cloud_data = np.loadtxt(file_path)

# 提取点的坐标 (x, y, z) 和颜色 (r, g, b)
points = point_cloud_data[:, :3]
colors = point_cloud_data[:, 3:] / 255.0  # Open3D expects colors in [0, 1] range

# 创建 Open3D 点云对象
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(points)
pcd.colors = o3d.utility.Vector3dVector(colors)


# 计算AABB(轴对齐包围盒)
obb = pcd.get_oriented_bounding_box()
axis = o3d.geometry.TriangleMesh.create_coordinate_frame()


# 可视化点云和AABB
obb.color = (0, 1, 0)  
o3d.visualization.draw_geometries([pcd,obb])


可视化结果:
Pasted image 20240920105437

### CloudCompare 中计算点云数据的最小包围盒方法 在CloudCompare软件中,默认情况下使用的包围盒是轴向AABB(Axis-Aligned Bounding Box),这种类型的包围盒未与点云紧密贴合。为了获得更加精确的结果,可以采用OBB(Object-Oriented Bounding Box)来作为最小包围盒。 #### 使用图形界面操作 当用户想要获取更贴近实际形状的最小包围盒时,在CloudCompare内可以通过菜单栏中的`Tools -> Orientation -> Oriented bounding box (PCA)`选项完成这一过程[^1]。这一步骤会基于主成分分析(Principal Component Analysis, PCA),自动调整方向并找到最合适的外接矩形体。 #### 编程接口调用 除了手动设置之外,还可以利用CloudCompare提供的API来进行自动化处理。下面给出了一段Python脚本的例子,展示了怎样通过命令行参数控制程序执行上述任务: ```python import sys from cloudcompare import ccPointCloud, ccHObject def compute_min_bouding_box(point_cloud_path): point_cloud = ccPointCloud.LoadFromFile(point_cloud_path) # Compute oriented bounding box using PCA method. obb = point_cloud.computeOrientedBoundingBox() result_file_name = "output_obb.txt" with open(result_file_name,'w') as f: for i in range(len(obb)): line = ' '.join([str(x) for x in obb[i]]) f.write(line + '\n') if __name__ == "__main__": if len(sys.argv)>1: input_file=sys.argv[1] compute_min_bounding_box(input_file) ``` 这段代码首先加载了一个指定路径下的点云文件,接着运用内置函数`computeOrientedBoundingBox()`实现了最小包围盒(OBB) 的计算,并最终将结果保存到了文本文件当中[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值