您的位置:

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<3,3>(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;