一、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/zh-hk/n/159881.html