最近在做有关实验需要计算模型曲率,但是网上找了一圈也没找到满意的资料。最后发现PCL库可以很方便的求取模型中每一个点的曲率,但是我们要想将PCL库求得的曲率数据应用到自己的项目中需要将PCL库与我们的项目进行结合,并且在PCL求出曲率后存放在自己的结构体中,这样才能得到更适合自己项目的数据。
-----------------------------------
实现思路:
鉴于在实际使用中只需要一些曲率较大的点作为特征点使用(我们这里只研究最大的前800个点),所以在使用PCL库求取所有点的曲率后,我们
- 首先将其曲率值与其对应的点在点集中的索引值进行结构化存储最终得到一个包含所有点索引与曲率值的集合。
- 接着应用选择排序特点的逆思想(每一次将最大值放在集合的最开始处)对集合进行排序,为了不影响运行速度,当找到前800个曲率最大值时中断操作。
- 通过对应的索引值在原始点集中找到这800个曲率值对应的模型点。
曲率求取代码:
#include <pcl/io/io.h>
#include <pcl/io/obj_io.h>
#include <pcl/PolygonMesh.h>
#include<pcl/ros/conversions.h>
#include <pcl/point_cloud.h>
#include <pcl/io/vtk_lib_io.h>//loadPolygonFileOBJ所属头文件;
#include<pcl/features/normal_3d.h>
#include<pcl/features/principal_curvatures.h>
vector<PCURVATURE> getModelCurvatures(string modelPath)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PolygonMesh mesh;
pcl::io::loadPolygonFileOBJ(modelPath, mesh);
pcl::fromPCLPointCloud2(mesh.cloud, *cloud);
//计算法线--------------------------------------------------------------------------------------
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setInputCloud(cloud);
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
ne.setSearchMethod(tree); //设置搜索方法
pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>);
//ne.setRadiusSearch(0.05); //设置半径邻域搜索
ne.setKSearch(5);
ne.compute(*cloud_normals); //计算法向量
//计算法线--------------------------------------------------------------------------------------
//计算曲率-------------------------------------------------------------------------------------
pcl::PrincipalCurvaturesEstimation<pcl::PointXYZ, pcl::Normal, pcl::PrincipalCurvatures>pc;
pcl::PointCloud<pcl::PrincipalCurvatures>::Ptr cloud_curvatures(new pcl::PointCloud<pcl::PrincipalCurvatures>);
pc.setInputCloud(cloud);
pc.setInputNormals(cloud_normals);
pc.setSearchMethod(tree);
//pc.setRadiusSearch(0.05);
pc.setKSearch(5);
pc.compute(*cloud_curvatures);
//获取曲率集
vector<PCURVATURE> tempCV;
POINT3F tempPoint;
float curvature = 0.0;
PCURVATURE pv;
tempPoint.x = tempPoint.y = tempPoint.z=0.0;
for (int i = 0; i < cloud_curvatures->size();i++){
//平均曲率
//curvature = ((*cloud_curvatures)[i].pc1 + (*cloud_curvatures)[i].pc2) / 2;
//高斯曲率
curvature = (*cloud_curvatures)[i].pc1 * (*cloud_curvatures)[i].pc2;
//pv.cPoint = tempPoint;
pv.index = i;
pv.curvature = curvature;
tempCV.insert(tempCV.end(),pv);
}
return tempCV;
}
代码中需要的结构体:
//存放每一个点的索引值和其对应的曲率
typedef struct PCURVATURE{
//POINT3F cPoint;
int index;
float curvature;
}PCURVATURE;
代码调用:
vector<PCURVATURE> allCurvates;
//计算模型所有点的曲率(Modelpath为模型所在路径)
allCurvates = getModelCurvatures(Modelpath);
//获取所有曲率中的最大、最小曲率
//选择排序
//找到最大的前800个曲率点
PCURVATURE temp;
int maxIndex = 0;
int count = 0;
for (int i = 0; i < allCurvates.size(); i++){
float maxCurvature = -99999;
for (int j = i + 1; j< allCurvates.size(); j++){
if (maxCurvature<allCurvates[j].curvature){
maxCurvature = allCurvates[j].curvature;
maxIndex = j;
}
}
if (maxCurvature>allCurvates[i].curvature){
temp = allCurvates[maxIndex];
allCurvates[maxIndex] = allCurvates[i];
allCurvates[i] = temp;
count++;
}
if (count>800){
break;
}
}
在我的项目中只需要一部分模型点的曲率,所以只显示了最大曲率的500个点,效果如下(为OpenGL绘制效果):
//绘制曲率点
void DrawCurvatures(){
glEnable(GL_BLEND); //启用混合
glDepthMask(GL_FALSE); //将深度缓存设置为只读状态
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //透明效果混合
glPointSize(3.0f);
glBegin(GL_POINTS);
//绘制高斯曲率最大的500个点(pPointInfo为本项目中存放模型点集的指针)
for (int i = 0; i <500; i++)
{
POINT3F point = (*pPointInfo)[allCurvates[i].index].pt;
glColor4f(0.0f, 1.0f, 0.0f, 0.8f); //alpha值为0.3
glVertex3f(point.x, point.y, point.z);
}
glEnd();
glDepthMask(GL_TRUE); //深度缓存设置为正常状态
glDisable(GL_BLEND); //禁用混合
}
从效果看整体还是不错的,弯曲程度较大的位置都能被找到。
当然也可以使用PCL自带的可视化类进行显示,效果如下:
pcl::visualization::PCLVisualizer viewer("PCL Viewer");
viewer.addPointCloudPrincipalCurvatures(cloud,cloud_normals,cloud_curvatures,10,1,"cloud_curvatures");
while (!viewer.wasStopped ())
{
viewer.spinOnce ();
}
此与上边最左侧的是同一个模型,可以看出可视的蓝色部位与上边绿色的点的位置基本上是吻合的。但是有一点需要注意,经亲测,PCL1.8版本不能对曲率进行可视化,很纳闷,其他版本没试,图为PCL1.6运行效果。
----------------------
希望本博客可以帮助到一些人,如有什么问题可以指出,欢迎交流。