1. 程式人生 > >PCL求取三維點雲模型每點曲率

PCL求取三維點雲模型每點曲率

最近在做有關實驗需要計算模型曲率,但是網上找了一圈也沒找到滿意的資料。最後發現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執行效果。

----------------------

希望本部落格可以幫助到一些人,如有什麼問題可以指出,歡迎交流。