平面的法線是垂直於它的單位向量。在點雲的表面的法線被定義為垂直於與點雲表面相切的平面的向量。表面法線也可以計算點雲中一點的法線,被認為是一種十分重要的性質。常常在被使用在很多計算機視覺的應用里面,比如可以用來推出光源的位置,通過陰影與其他視覺影響,表面法線的問題可以近似化解為切面的問題,這個切面的問題又會變成最小二乘法擬合平面的問題
解決表面法線估計的問題可以最終化簡為對一個協方差矩陣的特征向量和特征值的分析(或者也叫PCA-Principal Component Analysis 主成分分析),這個協方差矩陣是由查詢點的最近鄰產生的。對於每個點Pi,我們假設協方差矩陣C如下:
法線提供了關於曲面的曲率信息,這是它的優勢。許多的PCL的算法需要我們提供輸入點雲的法線。為了估計它們,代碼分析如下
#include <pcl/io/pcd_io.h> #include <pcl/features/normal_3d.h> #include <boost/thread/thread.hpp> #include <pcl/visualization/pcl_visualizer.h> int main(int argc,char**argv) { //創建點雲對象 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); //創建法線的對象 pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>); //讀取PCD文件 if(pcl::io::loadPCDFile<pcl::PointXYZ>(argv[1],*cloud) !=0) { return -1; } //創建法線估計的對象 pcl::NormalEstimation<pcl::PointXYZ,pcl::Normal> normalEstimation; normalEstimation.setInputCloud(cloud); //對於每一個點都用半徑為3cm的近鄰搜索方式 normalEstimation.setRadiusSearch(0.03); //Kd_tree是一種數據結構便於管理點雲以及搜索點雲,法線估計對象會使用這種結構來找到哦啊最近鄰點 pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZ>); normalEstimation.setSearchMethod(kdtree); //計算法線 normalEstimation.compute(*normals); //可視化 boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("Normals")); viewer->addPointCloud<pcl::PointXYZ>(cloud,"cloud"); while(!viewer->wasStopped()) { viewer->spinOnce(100); boost::this_thread::sleep(boost::posix_time::microseconds(1000000)); } }
試驗結果就是運行命令,這里就隨便輸入一個PCD 文件
可能看不處什么效果*********************
(2)圖像積分
積分圖像是對有序點雲的發現的估計的一種方法。該算法把點雲作為一個深度圖像,並創建一定的矩形區域來計算法線,考慮到相鄰像素關系,而無需建立樹形查詢結構。因此,它是非常有效的。
#include <pcl/io/pcd_io.h> #include <pcl/features/integral_image_normal.h> #include <boost/thread/thread.hpp> #include <pcl/visualization/pcl_visualizer.h> int main(int argc, char** argv) { // 點雲數據對象 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); // 法線對象 pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>); // 讀取文件 if (pcl::io::loadPCDFile<pcl::PointXYZ>(argv[1], *cloud) != 0) { return -1; } // 法線估計對象 pcl::IntegralImageNormalEstimation<pcl::PointXYZ, pcl::Normal> normalEstimation; normalEstimation.setInputCloud(cloud); // 法線估計方法: COVARIANCE_MATRIX, AVERAGE_DEPTH_CHANGE, SIMPLE_3D_GRADIENT. normalEstimation.setNormalEstimationMethod(normalEstimation.AVERAGE_3D_GRADIENT); //設置深度變化的閥值 normalEstimation.setMaxDepthChangeFactor(0.02f); // 設置計算法線的區域 normalEstimation.setNormalSmoothingSize(10.0f); // 計算 normalEstimation.compute(*normals); // 可視化 boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("Normals")); viewer->addPointCloud<pcl::PointXYZ>(cloud, "cloud"); viewer->addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals, 20, 0.03, "normals"); while (!viewer->wasStopped()) { viewer->spinOnce(100); boost::this_thread::sleep(boost::posix_time::microseconds(100000)); } }
結果可視化
具體官方的網址查看pointclouds.org/documentation/tutorials/normal_estimation_using_integral_images.php
大神請忽略!!!!
微信公眾號號可掃描二維碼一起共同學習交流