日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

pcl里面的法线估计

發(fā)布時間:2025/3/15 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 pcl里面的法线估计 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

法線估計是一個很重要的特征,常常在被使用在很多計算機視覺的應用里面,比如可以用來推出光源的位置,通過陰影與其他視覺影響。

給一個幾何表面,去推斷給定點的法線方向,即垂直向量的方向往往是不容易的。然而,在我們獲取物體表面的點云數(shù)據(jù)后,有兩大選擇:

1.從已獲取的點云數(shù)據(jù)集中得到潛在表面,并用表面網(wǎng)格化技術(shù),來計算網(wǎng)格的表面法線。

2.使用近似值來推斷點云數(shù)據(jù)集的表面法線。

盡管有很多法線估計的方法存在,但是我們這次將會講的是最簡單的方法。表面法線的問題可以近似化解為切面的問題,這個切面的問題又會變成最小二乘法擬合平面的問題。

解決表面法線估計的問題可以最終化簡為對一個協(xié)方差矩陣的特征向量和特征值的分析(或者也叫PCA-Principal Component Analysis 主成分分析),這個協(xié)方差矩陣是由查詢點的最近鄰產(chǎn)生的。對于每個點Pi,我們假設協(xié)方差矩陣C如下:

這里K指的是離點的最近的K個點,是最近鄰的中心,是第j個特征值,是第j個特征向量。

下面是一段用來估計協(xié)方差矩陣的代碼

// Placeholder for the 3x3 covariance matrix at each surface patchEigen::Matrix3f covariance_matrix;// 16-bytes aligned placeholder for the XYZ centroid of a surface patchEigen::Vector4f xyz_centroid;// Estimate the XYZ centroidcompute3DCentroid (cloud, xyz_centroid);// Compute the 3x3 covariance matrixcomputeCovarianceMatrix (cloud, xyz_centroid, covariance_matrix);

總的來說,因為數(shù)學上沒有方法解決法線的符號,比如一個球面,法線可以指向球心,也可以背向球心。下面的兩幅圖像是描述廚房的點云圖,右邊的圖像是通過高斯擴展圖(EGI?Extended Gaussian Image),也常常叫做法線球。法線球是一個描述點云里面所有法線方向的一種方式。因為數(shù)據(jù)集是2.5D的,何為2.5D,你可以把上下,左右,前后看成一個D,然后現(xiàn)實生活里面往往不可能每個方向都兼顧,比如攝像機只能拍到前面的,所有是1(上下)+1(左右)+0.5(前)叫2.5D,當然這是建立在攝像機為單一視角的情況下,即攝像機不會動,一直是固定的。所以理論上,EGI圖,即高斯球也應該是2.5D的,因為你攝像機是向前拍攝的,所以物體的法線也是向前的,然而因為這個算法的原因。主成分分析這個算法,不能解決法線的符號,所以導致了法線指向可能往前,也可能往后,導致整個球里面各個方向都可能存在著法線。



解決上面的法線方向不定的問題,我們得知道視角的向量,這就很簡單了,只要法線和? 視角與點的連線,這兩條線的夾角是銳角,即這兩個向量的點積大于0即可。

我們經(jīng)過上述的處理后,圖片就變成了這樣

可以看到左邊的那副圖,法線的指向全都變成一個方向了,同時高斯擴展圖只有前半個球面是有法線的,即我們的方法是有效的。

我們可以使用下面的方法去改變法線的方向

flipNormalTowardsViewpoint (const PointT &point, float vp_x, float vp_y, float vp_z, Eigen::Vector4f &normal);

上面的這個方法就像我們剛才說的,只適用于單一視角的情況下。

選擇正確的比例

就像前面說的,預測一個表面法線需要最近鄰的方法,那么如何設置最近鄰所需要的半徑與點的個數(shù)呢?

這個問題是非常重要的,是對點的特征自動化評估的重要因素。為了更好的闡述這個問題,下面的圖將顯示選擇一個小比例和大比例的影響。左邊的圖是比例(r和k)比較小的情況,我們發(fā)現(xiàn)它的法線是另人滿意的,而右邊就不盡人意了,你看那個桌角的位置,有一個法線出軌了,是一個小三,不屬于上一個表面也不屬于側(cè)面,這就是比例選擇太大的弊端,所以小比例往往更注重細節(jié),更適合描述比較復雜的物體。


我們得根據(jù)不同的細節(jié)來選取比例,簡單的說,如果邊緣的曲率在杯子的把柄和圓柱體之間的時候,比例需要比較小來獲取足夠的細節(jié)。

下面是官方的一段代碼段:

#include <pcl/point_types.h> #include <pcl/features/normal_3d.h>{pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);... read, pass in or create a point cloud ...// Create the normal estimation class, and pass the input dataset to itpcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;ne.setInputCloud (cloud);// Create an empty kdtree representation, and pass it to the normal estimation object.// Its content will be filled inside the object, based on the given input dataset (as no other search surface is given).pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());ne.setSearchMethod (tree);// Output datasetspcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);// Use all neighbors in a sphere of radius 3cmne.setRadiusSearch (0.03);// Compute the featuresne.compute (*cloud_normals);// cloud_normals->points.size () should have the same size as the input cloud->points.size ()* }

NormalEstimation這個類

做了以下3件事

1.得到p的最近鄰

2.計算p的表面法線n

3.檢查法線的朝向,然后撥亂反正。

默認的視角是(0,0,0),可以通過下面的方法來更改

setViewPoint (float vpx, float vpy, float vpz);

計算一個點的法線

computePointNormal (const pcl::PointCloud<PointInT> &cloud, const std::vector<int> &indices, Eigen::Vector4f &plane_parameters, float &curvature);

前面兩個參數(shù)很好理解,plane_parameters包含了4個參數(shù),前面三個是法線的(nx,ny,nz)坐標,加上一個?nc . p_plane (centroid here) + p的坐標,然后最后一個參數(shù)是曲率。


接下去是我寫的一個代碼,先通過從磁盤里面加載一個PCD文件,然后進行降低采樣和濾波等操作,最后通過PCLVisulizer顯示出來.

#include <iostream> #include <pcl/visualization/cloud_viewer.h> #include<pcl/io/pcd_io.h> #include<pcl/point_types.h> #include <pcl_conversions/pcl_conversions.h> #include <pcl/features/normal_3d.h> #include <boost/thread/thread.hpp> #include <pcl/common/common_headers.h> #include <pcl/filters/voxel_grid.h> #include <pcl/visualization/pcl_visualizer.h> #include <pcl/console/parse.h> #include <pcl/filters/statistical_outlier_removal.h>int main () {pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_old (new pcl::PointCloud<pcl::PointXYZ>);pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_downsampled (new pcl::PointCloud<pcl::PointXYZ>);pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);pcl::io::loadPCDFile ("test_pcd.pcd", *cloud_old);//Use a voxelSampler to downsamplepcl::VoxelGrid<pcl::PointXYZ> voxelSampler;voxelSampler.setInputCloud(cloud_old);voxelSampler.setLeafSize(0.01f, 0.01f, 0.01f);voxelSampler.filter(*cloud_downsampled);//Use a filter to reduce noisepcl::StatisticalOutlierRemoval<pcl::PointXYZ> statFilter;statFilter.setInputCloud(cloud_downsampled);statFilter.setMeanK(10);statFilter.setStddevMulThresh(0.2);statFilter.filter(*cloud);// Create the normal estimation class, and pass the input dataset to itpcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;ne.setInputCloud (cloud);// Create an empty kdtree representation, and pass it to the normal estimation object.// Its content will be filled inside the object, based on the given input dataset (as no other search surface is given).pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());ne.setSearchMethod (tree);// Output datasetspcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);// Use all neighbors in a sphere of radius 1cmne.setRadiusSearch(0.01);// Compute the featuresne.compute (*normals);boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer (new pcl::visualization::PCLVisualizer ("3D Viewer"));viewer->setBackgroundColor (0, 0, 0);viewer->addPointCloud<pcl::PointXYZ> (cloud, "sample cloud");viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud");viewer->addPointCloudNormals<pcl::PointXYZ, pcl::Normal> (cloud, normals, 10, 0.2, "normals");viewer->addCoordinateSystem (1.0);viewer->initCameraParameters ();while (!viewer->wasStopped()){viewer->spinOnce (100);boost::this_thread::sleep (boost::posix_time::microseconds (100000));}return 0; }

因為我的PCD的點云文件里面的點是PointXYZ類型,所以顯示得時候,都是白色的,下面上一張效果圖。


這是一張桌子,可以看到上面充滿了密密麻麻的法線。如果你要下載這個PCD文件,點擊下面這個鏈接。

點擊打開鏈接




 

總結(jié)

以上是生活随笔為你收集整理的pcl里面的法线估计的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。