一、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
微信扫一扫
支付宝扫一扫