一、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;
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/159881.html