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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

点云体素下采样 ❤️(体素质心 | 体素中心)

發布時間:2024/1/18 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 点云体素下采样 ❤️(体素质心 | 体素中心) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 1 體素質心下采樣
      • 1.1 原理
      • 1.2 體素質心的計算
      • 1.2 代碼實現
      • 1.3 與 PCL:VoxelGrid 點云體素下采樣結果對比
    • 2 體素中心下采樣
      • 2.1 原理
      • 2.2 體素中心的計算
      • 2.2 代碼實現
      • 2.3 與體素質心下采樣結果對比
    • 3 總結

1 體素質心下采樣

1.1 原理

體素質心下采樣的原理很簡單,首先將點云進行 體素劃分,然后計算非空體素的質心代替該體素內的所有點,實現點云的下采樣。

1.2 體素質心的計算

已知一個非空體素 V V V,其中包含 m m m 個點,則該體素的質心 P c e n t r o i d ( x c e n t r o i d , y c e n t r o i d , z c e n t r o i d ) P_{centroid}(x_{centroid},y_{centroid},z_{centroid}) Pcentroid?(xcentroid?,ycentroid?,zcentroid?) 為:

{ x c e n t r o i d = ∑ i = 1 m x i m y c e n t r o i d = ∑ i = 1 m y i m z c e n t r o i d = ∑ i = 1 m z i m \begin{cases} x_{centroid}=\cfrac{\sum_{i=1}^{m}{x_i}}{m}\\ y_{centroid}=\cfrac{\sum_{i=1}^{m}{y_i}}{m}\\ z_{centroid}=\cfrac{\sum_{i=1}^{m}{z_i}}{m}\\ \end{cases} ??????????????xcentroid?=mi=1m?xi??ycentroid?=mi=1m?yi??zcentroid?=mi=1m?zi???

1.2 代碼實現

代碼分為三部分:

  • main.cpp
  • voxel_centroid_down_sampling.h
  • voxel_centroid_down_sampling.cpp

main.cpp

#include "voxel_centroid_down_sampling.h" #include <pcl/console/time.h>int main() {//----------------------------- 加載點云 -----------------------------pcl::PointCloud<PointT>::Ptr cloud_in(new pcl::PointCloud<PointT>);if (pcl::io::loadPCDFile("grid.pcd", *cloud_in) < 0){PCL_ERROR("/a->點云文件不存在!/n");system("pause");abort();}cout << "->共加載 " << cloud_in->points.size() << " 個數據點" << endl;//===================================================================pcl::console::TicToc time;time.tic();//------------------------- 三維體素格網化點云 ------------------------pcl::PointCloud<PointT>::Ptr cloud_downSample(new pcl::PointCloud<PointT>);VoxelCentriodDownSample vcds; //創建三維體素格網化對象vcds.setInputCloud(cloud_in); //設置輸入點云vcds.setGridStep(0.2); //設置體素格網邊長vcds.downSample(cloud_downSample); //執行體素質心下采樣,并將采樣結果保存到cloud_downSample中cout << "->體素質心下采樣用時:" << time.toc() / 1000 << " s" << endl;//===================================================================//------------------------- 保存體素質心下采樣點云 ------------------------if (!cloud_downSample->empty()){pcl::io::savePCDFileASCII("downSample_centroid.pcd", *cloud_downSample);cout << "->下采樣點云的點數為:" << cloud_downSample->points.size() << endl;}else{PCL_ERROR("\a->下采樣點云為空!\n");system("pause");}//===================================================================return 0; }

輸出結果:

->共加載 5746 個數據點 ->體素質心下采樣用時:0.243 s ->下采樣點云的點數為:856

voxel_centroid_down_sampling.h

#pragma once #include <pcl/io/pcd_io.h> #include <pcl/common/common.h>using namespace std;typedef pcl::PointXYZ PointT;//體素質心下采樣類 class VoxelCentriodDownSample { public:/*** @brief :設置輸入點云* @param[I]:cloud_in(輸入點云)* @param[O]:none* @return : none* @note :**/void setInputCloud(pcl::PointCloud<PointT>::Ptr cloud_in);/*** @brief :設置體素格網邊長* @param[I]:step(體素格網邊長)* @param[O]:none* @return : none* @note :**/void setGridStep(double step);/*** @brief :體素下采樣* @param[I]:none* @param[O]:downSampleCloud(下采樣點云)* @return : none* @note :**/void downSample(pcl::PointCloud<PointT>::Ptr downSampleCloud);private:pcl::PointCloud<PointT>::Ptr m_cloud_in; //輸入點云bool is_setInputCloud = false;double m_step; //格網邊長bool is_setGridStep = false;int m_row; //格網總行數int m_col; //格網總列數int m_lay; //格網總層數};

voxel_centroid_down_sampling.cpp

#include "voxel_centroid_down_sampling.h"/** * @brief :設置輸入點云 * @param[I]:cloud_in(輸入點云) * @param[O]:none * @return : none * @note : **/ void VoxelCentriodDownSample::setInputCloud(pcl::PointCloud<PointT>::Ptr cloud_in) {m_cloud_in = cloud_in;is_setInputCloud = true; }/** * @brief :設置體素格網邊長 * @param[I]:step(體素格網邊長) * @param[O]:none * @return : none * @note : **/ void VoxelCentriodDownSample::setGridStep(double step) {if (step > 0){m_step = step;is_setGridStep = true;}else{PCL_ERROR("\a->格網邊長應為正數!\n");system("pause");abort();} }/** * @brief :體素質心下采樣 * @param[I]:none * @param[O]:downSampleCloud(下采樣點云) * @return : none * @note : **/ void VoxelCentriodDownSample::downSample(pcl::PointCloud<PointT>::Ptr downSampleCloud) {if (!is_setGridStep){PCL_ERROR("\a->請先設置格網邊長!\n");system("pause");abort();}pcl::PointXYZ min;pcl::PointXYZ max;pcl::getMinMax3D(*m_cloud_in, min, max);m_row = (int)((max.y - min.y) / m_step) + 1;m_col = (int)((max.x - min.x) / m_step) + 1;m_lay = (int)((max.z - min.z) / m_step) + 1;int row_i; //每一點的行號,從1開始int col_i; //每一點的列號,從1開始int lay_i; //每一點的層號,從1開始int grid_id_pt; //逐行對應的一維格網編號id,從1開始multimap<int, PointT> m_grid3D; //存放水平面格網點云的容器//遍歷點云,進行三維體素格網化size_t num_cp = m_cloud_in->points.size();for (size_t i = 0; i < num_cp; i++){row_i = (int)((m_cloud_in->points[i].y - min.y) / m_step) + 1; //每一點的行號,從1開始col_i = (int)((m_cloud_in->points[i].x - min.x) / m_step) + 1; //每一點的列號,從1開始lay_i = (int)((m_cloud_in->points[i].z - min.z) / m_step) + 1;//每一點的列號,從1開始grid_id_pt = (lay_i - 1) * (m_row * m_col) + (row_i - 1) * m_col + col_i; //格網一維索引,從1開始m_grid3D.insert(pair<int, PointT>(grid_id_pt, m_cloud_in->points[i])); //將每一個id對應的點坐標存入容器grids2D中}//判斷體素是否為空,若非空,則計算體素內點云質心,以質心代替該體素內的所有點for (int lay = 1; lay <= m_lay; lay++) //層掃描{for (int row = 1; row <= m_row; row++) //行掃描{for (int col = 1; col <= m_col; col++) //列掃描{int grid_id; //逐行對應的一維格網編號id,從1開始grid_id = (lay - 1) * (m_row * m_col) + (row - 1) * m_col + col;if (m_grid3D.count(grid_id)) //若體素格網內有點,則計算體素質心{float sum_x, sum_y, sum_z;sum_x = sum_y = sum_z = 0;auto range = m_grid3D.equal_range(grid_id);for(auto it = range.first;it!=range.second; ++it){sum_x += (*it).second.x;sum_y += (*it).second.y;sum_z += (*it).second.z;}PointT temp; //臨時存放體素質心temp.x = sum_x / m_grid3D.count(grid_id);temp.y = sum_y / m_grid3D.count(grid_id);temp.z = sum_z / m_grid3D.count(grid_id);downSampleCloud->push_back(temp);}}}} }

1.3 與 PCL:VoxelGrid 點云體素下采樣結果對比

PCL提供了 VoxelGrid點云體素下采樣 的接口,直接調用即可,輸出結果如下:

->加載了 5746 個數據點 ->正在進行體素下采樣... ->體素下采樣用時:0.058 s ->下采樣點云的點數為:836 下采樣結果對比
方法用時點數
本文方法0.243s856
PCL:VoxelGrid0.058s836
原始點云本文下采樣點云PCL下采樣點云

2 體素中心下采樣

2.1 原理

與體素質心下采樣類似,首先將點云進行 體素劃分,然后計算非空體素的中心代替該體素內的所有點,實現點云的下采樣。

2.2 體素中心的計算

已知一個點的行列層數 ( r o w , c o l , l a y ) (row,col,lay) (row,col,lay),體素邊長 s t e p step step,坐標最小值 x m i n 、 y m i n 、 z m i n x_{min}、y_{min}、z_{min} xmin?、ymin?、zmin?, 則該點所在體素的中心 P c e n t e r ( x c e n t e r , y c e n t e r , z c e n t e r ) P_{center}(x_{center},y_{center},z_{center}) Pcenter?(xcenter?,ycenter?,zcenter?) 為:
{ x c e n t e r = x m i n + ( c o l ? 0.5 ) ? s t e p y c e n t e r = y m i n + ( r o w ? 0.5 ) ? s t e p z c e n t e r = z m i n + ( l a y ? 0.5 ) ? s t e p \begin{cases} x_{center}=x_{min}+(col-0.5)*step\\ y_{center}=y_{min}+(row-0.5)*step\\ z_{center}=z_{min}+(lay-0.5)*step\\ \end{cases} ??????xcenter?=xmin?+(col?0.5)?stepycenter?=ymin?+(row?0.5)?stepzcenter?=zmin?+(lay?0.5)?step?

2.2 代碼實現

代碼分為三部分:

  • main.cpp
  • voxel_center_down_sampling.h
  • voxel_center_down_sampling.cpp

main.cpp

#include "voxel_center_down_sampling.h" #include <pcl/console/time.h>int main() {//----------------------------- 加載點云 -----------------------------pcl::PointCloud<PointT>::Ptr cloud_in(new pcl::PointCloud<PointT>);if (pcl::io::loadPCDFile("grid.pcd", *cloud_in) < 0){PCL_ERROR("/a->點云文件不存在!/n");system("pause");abort();}cout << "->共加載 " << cloud_in->points.size() << " 個數據點" << endl;//===================================================================pcl::console::TicToc time;time.tic();//------------------------- 體素中心下采樣點云 ------------------------pcl::PointCloud<PointT>::Ptr cloud_downSample(new pcl::PointCloud<PointT>);VoxelCenterDownSample vcds;vcds.setInputCloud(cloud_in);vcds.setGridStep(0.2);vcds.downSample(cloud_downSample);cout << "->體素中心下采樣用時:" << time.toc() / 1000 << " s" << endl;//===================================================================//------------------------- 保存體素下采樣點云 ------------------------if (!cloud_downSample->empty()){pcl::io::savePCDFileASCII("downSample_center.pcd", *cloud_downSample);cout << "->下采樣點云的點數為:" << cloud_downSample->points.size() << endl;}else{PCL_ERROR("\a->下采樣點云為空!\n");system("pause");}//===================================================================return 0; }

輸出結果:

->共加載 5746 個數據點 ->體素中心下采樣用時:0.201 s ->下采樣點云的點數為:856

voxel_center_down_sampling.h

#pragma once #include <pcl/io/pcd_io.h> #include <pcl/common/common.h>using namespace std;typedef pcl::PointXYZ PointT;//體素中心下采樣類 class VoxelCenterDownSample { public:/*** @brief :設置輸入點云* @param[I]:cloud_in(輸入點云)* @param[O]:none* @return : none* @note :**/void setInputCloud(pcl::PointCloud<PointT>::Ptr cloud_in);/*** @brief :設置體素格網邊長* @param[I]:step(體素格網邊長)* @param[O]:none* @return : none* @note :**/void setGridStep(double step);/*** @brief :體素中心下采樣* @param[I]:none* @param[O]:downSampleCloud(下采樣點云)* @return : none* @note :**/void downSample(pcl::PointCloud<PointT>::Ptr downSampleCloud);private:pcl::PointCloud<PointT>::Ptr m_cloud_in; //輸入點云bool is_setInputCloud = false;double m_step; //格網邊長bool is_setGridStep = false;int m_row; //格網總行數int m_col; //格網總列數int m_lay; //格網總層數};

voxel_center_down_sampling.cpp

#include "voxel_center_down_sampling.h"/** * @brief :設置輸入點云 * @param[I]:cloud_in(輸入點云) * @param[O]:none * @return : none * @note : **/ void VoxelCenterDownSample::setInputCloud(pcl::PointCloud<PointT>::Ptr cloud_in) {m_cloud_in = cloud_in;is_setInputCloud = true; }/** * @brief :設置體素格網邊長 * @param[I]:step(體素格網邊長) * @param[O]:none * @return : none * @note : **/ void VoxelCenterDownSample::setGridStep(double step) {if (step > 0){m_step = step;is_setGridStep = true;}else{PCL_ERROR("\a->格網邊長應為正數!\n");system("pause");abort();} }/** * @brief :體素中心下采樣 * @param[I]:none * @param[O]:downSampleCloud(下采樣點云) * @return : none * @note : **/ void VoxelCenterDownSample::downSample(pcl::PointCloud<PointT>::Ptr downSampleCloud) {if (!is_setGridStep){PCL_ERROR("\a->請先設置格網邊長!\n");system("pause");abort();}pcl::PointXYZ min;pcl::PointXYZ max;pcl::getMinMax3D(*m_cloud_in, min, max);m_row = (int)((max.y - min.y) / m_step) + 1;m_col = (int)((max.x - min.x) / m_step) + 1;m_lay = (int)((max.z - min.z) / m_step) + 1;int row_i; //每一點的行號,從1開始int col_i; //每一點的列號,從1開始int lay_i; //每一點的層號,從1開始int grid_id_pt; //逐行對應的一維格網編號id,從1開始multimap<int, PointT> m_grid3D; //存放水平面格網點云的容器//遍歷點云,進行三維體素格網化size_t num_cp = m_cloud_in->points.size();for (size_t i = 0; i < num_cp; i++){row_i = (int)((m_cloud_in->points[i].y - min.y) / m_step) + 1; //每一點的行號,從1開始col_i = (int)((m_cloud_in->points[i].x - min.x) / m_step) + 1; //每一點的列號,從1開始lay_i = (int)((m_cloud_in->points[i].z - min.z) / m_step) + 1;//每一點的列號,從1開始grid_id_pt = (lay_i - 1) * (m_row * m_col) + (row_i - 1) * m_col + col_i; //格網一維索引,從1開始m_grid3D.insert(pair<int, PointT>(grid_id_pt, m_cloud_in->points[i])); //將每一個id對應的點坐標存入容器grids2D中}//判斷體素是否為空,若非空,則計算體素內點云中心,以中心代替該體素內的所有點for (int lay = 1; lay <= m_lay; lay++) //層掃描{for (int row = 1; row <= m_row; row++) //行掃描{for (int col = 1; col <= m_col; col++) //列掃描{int grid_id; //逐行對應的一維格網編號id,從1開始grid_id = (lay - 1) * (m_row * m_col) + (row - 1) * m_col + col;//若體素格網內有點,則計算體素中心if (m_grid3D.count(grid_id)) {PointT temp;temp.x = min.x + (col - 0.5)*m_step;temp.y = min.y + (row - 0.5)*m_step;temp.z = min.z + (lay -0.5)*m_step;downSampleCloud->push_back(temp);}}}} }

2.3 與體素質心下采樣結果對比

下采樣結果對比
方法用時點數
體素質心0.243s856
體素中心0.201s856
原始點云體素質心下采樣點云體素中心下采樣點云

3 總結

  • 體素質心下采樣方法雖然耗時長,但采樣結果更加準確;體素中心下采樣方法耗時短,但容易失真。(由于本次實驗數據點數較少,耗時接近,可嘗試采樣大規模點云驗證)
  • 體素質心下采樣和體素中心下采樣,.h 文件是一樣的,只是下采樣實現的方式(.cpp)不同。
  • 注意下面的代碼,行列層都是從1開始,并非0。因此for循環的判斷條件是 “<=”,并非“=”。
for (int lay = 1; lay <= m_lay; lay++) //層掃描{for (int row = 1; row <= m_row; row++) //行掃描{for (int col = 1; col <= m_col; col++) //列掃描{···}}}

總結

以上是生活随笔為你收集整理的点云体素下采样 ❤️(体素质心 | 体素中心)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。