obb包围盒详解(OBB包围盒详解)

一、obb包围盒算法

obb包围盒即是用一个有向盒子框住物体,这个盒子有三个轴(长轴、中轴、短轴),轴上的长度叫做半长宽高。obb包围盒的算法是根据物体的点云数据生成obb包围盒,而点云数据是物体表面上的点的集合。obb包围盒算法的具体步骤如下:

1. 将点云数据转化为本体坐标系下的点集(即减去物体中心点坐标)

void processPointCloud(const pcl::PointCloud::Ptr &cloud, pcl::PointCloud::Ptr &outputCloud) {
    Eigen::Vector4f centroid;
    pcl::compute3DCentroid(*cloud, centroid);
    Eigen::Matrix4f transformationMatrix = Eigen::Matrix4f::Identity();
    transformationMatrix(0,3) = -centroid(0);
    transformationMatrix(1,3) = -centroid(1);
    transformationMatrix(2,3) = -centroid(2);
    pcl::transformPointCloud(*cloud, *outputCloud, transformationMatrix);
}

2. 进行主分量分析(PCA)得到obb包围盒的长轴、中轴、短轴和半长宽高

pcl::PCA pca;
pca.setInputCloud(cloud);
Eigen::Matrix3f eigenVectorsPCA = pca.getEigenVectors();
Eigen::Vector3f eigenValuesPCA = pca.getEigenValues();
Eigen::Matrix4f transformationMatrix = Eigen::Matrix4f::Identity();
transformationMatrix.block(0,0) = eigenVectorsPCA.transpose();
transformationMatrix(0,3) = pca.getMean()(0);
transformationMatrix(1,3) = pca.getMean()(1);
transformationMatrix(2,3) = pca.getMean()(2);
// 半长宽高
float boxLength = max(max(maxX - minX, maxY - minY), maxZ - minZ);
float boxWidth = min(min(maxX - minX, maxY - minY), maxZ - minZ);
float boxHeight = boxLength * (eigenValuesPCA(0) / eigenValuesPCA(2));

二、obb包围盒算法实现

上述obb包围盒算法的具体实现需要使用到第三方库pcl,pcl包含了很多点云相关的算法,因此可以很方便地生成obb包围盒。而obb包围盒可视化的最直观的方式是通过vtk库,代码实现如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));

void visualizeOBB(pcl::PointCloud::Ptr cloud, float boxLength, float boxWidth, float boxHeight) {
    vtkSmartPointer cube = vtkSmartPointer::New();
    cube->SetXLength(boxLength);
    cube->SetYLength(boxWidth);
    cube->SetZLength(boxHeight);
    cube->SetCenter(0, 0, 0);
    vtkSmartPointer cubeMapper = vtkSmartPointer::New();
    cubeMapper->SetInputConnection(cube->GetOutputPort());
    vtkSmartPointer cubeActor = vtkSmartPointer::New();
    cubeActor->SetMapper(cubeMapper);
    vtkSmartPointer transform = vtkSmartPointer::New();
    transform->Translate(cloud->at(0).x, cloud->at(0).y, cloud->at(0).z);
    vtkSmartPointer transformFilter = vtkSmartPointer::New();
    transformFilter->SetInputConnection(cube->GetOutputPort());
    transformFilter->SetTransform(transform);
    transformFilter->Update();
    cubeMapper->SetInputConnection(transformFilter->GetOutputPort());
    cubeActor->SetMapper(cubeMapper);
    viewer->addActor(cubeActor);
    viewer->setBackgroundColor(0.1, 0.1, 0.1);
    viewer->resetCamera();
    viewer->spin();
}

三、obb包围盒碰撞检测

obb包围盒在游戏、物理引擎等领域中广泛应用,碰撞检测是obb包围盒的一个常见应用。obb包围盒间的碰撞检测可以转化为obb包围盒间的距离计算问题,距离为0即为碰撞,例如obb1和obb2两个包围盒间的距离计算公式为:

float distance = sqrt((obj2.position.x - obj1.position.x) * eigenVectorsPCA(0, 0) +
                       (obj2.position.y - obj1.position.y) * eigenVectorsPCA(0, 1) + 
                       (obj2.position.z - obj1.position.z) * eigenVectorsPCA(0, 2)) - (boxLength1 + boxLength2) / 2;

四、obb包围盒中心点、半长宽高

obb包围盒有三个重要参数:中心点、半长宽高。中心点是有向盒子的中点,通常是通过点云数据计算得到的物体几何中心点,即计算点云数据点坐标的平均值得到。半长宽高是obb包围盒三个轴上的长度,因此要根据PCA得到obb包围盒的长轴、中轴、短轴和半长宽高。

Eigen::Vector4f centroid;
pcl::compute3DCentroid(*cloud, centroid);
float centerX = centroid(0);
float centerY = centroid(1);
float centerZ = centroid(2);
float boxLength = max(max(maxX - minX, maxY - minY), maxZ - minZ);
float boxWidth = min(min(maxX - minX, maxY - minY), maxZ - minZ);
float boxHeight = boxLength * (eigenValuesPCA(0) / eigenValuesPCA(2));

五、aabb包围盒

与obb包围盒相对应的是aabb包围盒(轴对齐包围盒,也叫AABB包围盒)。aabb包围盒与obb包围盒最大的区别是aabb包围盒的轴与坐标轴重合,因而如下代码即可计算出物体的aabb包围盒:

float minX, minY, minZ, maxX, maxY, maxZ;
pcl::getMinMax3D(*cloud, minX, minY, minZ, maxX, maxY, maxZ);
Eigen::Vector4f centroid;
pcl::compute3DCentroid(*cloud, centroid);
float centerX = centroid(0);
float centerY = centroid(1);
float centerZ = centroid(2);
float boxLength = maxX - minX;
float boxWidth = maxY - minY;
float boxHeight = maxZ - minZ;

Published by

风君子

独自遨游何稽首 揭天掀地慰生平