当前位置:   article > 正文

点云:点云格网化 (师弟师妹)简单教学版

点云格网化

一、原理与方法

点云格网化是点云数据处理的常用方法,是一种降维或压缩的方法。(论文里烂大街了)

基本原理是将点放入不同的格网,进而以格网为基本操作单元,对点云进行分块、抽稀、语义分割等。二维格网化是投影,类似像素;三维格网是体素。

基本方法是根据范围,划分成规则或不规则的格网,将不同的点分别放入不同的格网。下面是规则格网的划分。

 

(1)

式中,Xmax、Xmin、Ymax、Ymin、Zmax、Zmin分别代表点云区域X、Y、Z坐标的最大值和最小值; GSD为格网分辨率。

 

(2)

式中,col、row、lay分别为当前点P(X, Y, Z)的格网列号、行号和层号。

二、分享给有需要的人,代码质量勿喷

下面是点云格网化与体素抽稀的C++(老)代码了(有用到Qt)。

2.1 格网化:用PDAL读点,存入 QMultiHash 中

  1. //格网化
  2. QMultiHash<uint, xjPoint> PointCloudGrid::GriddingPC(const QString & lasPath, const double & GSD, const bool & bVoxel)
  3. {
  4. QMultiHash<uint, xjPoint> mhGrid;
  5. #pragma region read las
  6. using namespace pdal;
  7. using namespace pdal::Dimension;
  8. pdal::Option las_opt("filename", lasPath.toStdString());//参数1:"filename"(键)
  9. pdal::Options las_opts;
  10. las_opts.add(las_opt);
  11. pdal::PointTable rTable;
  12. pdal::LasReader las_reader;
  13. las_reader.setOptions(las_opts);
  14. las_reader.prepare(rTable);
  15. pdal::PointViewSet point_view_set = las_reader.execute(rTable);
  16. pdal::PointViewPtr point_view = *point_view_set.begin();
  17. pdal::Dimension::IdList dims = point_view->dims();
  18. pdal::LasHeader las_header = las_reader.header();
  19. #pragma endregion
  20. //X-cols Y-rows Z-lays
  21. double xMax = las_header.maxX();
  22. double xMin = las_header.minX();
  23. double yMax = las_header.maxY();
  24. double yMin = las_header.minY();
  25. double zMax = las_header.maxZ();
  26. double zMin = las_header.minZ();
  27. uint cols = uint((xMax - xMin) / GSD) + 1;
  28. uint rows = uint((yMax - yMin) / GSD) + 1;
  29. uint lays = uint((zMax - zMin) / GSD) + 1;
  30. //traversal
  31. uint col = 0, row = 0, lay = 0, gridNumber = 0;
  32. for (int idx = 0; idx < point_view->size(); ++idx)
  33. {
  34. xjPoint p;
  35. p.x = point_view->getFieldAs<double>(Id::X, idx);
  36. p.y = point_view->getFieldAs<double>(Id::Y, idx);
  37. p.z = point_view->getFieldAs<double>(Id::Z, idx);
  38. if (las_header.hasColor())
  39. {
  40. p.red = point_view->getFieldAs<int>(Id::Red, idx);
  41. p.green = point_view->getFieldAs<int>(Id::Green, idx);
  42. p.blue = point_view->getFieldAs<int>(Id::Blue, idx);
  43. }
  44. if (las_header.hasTime())
  45. {
  46. p.GPStime = point_view->getFieldAs<double>(Id::GpsTime, idx);
  47. }
  48. p.intensity = point_view->getFieldAs<int>(Id::Intensity, idx);
  49. p.pointSourceID = point_view->getFieldAs<int>(Id::PointSourceId, idx);
  50. p.classification = point_view->getFieldAs<int>(Id::Classification, idx);
  51. p.userData = point_view->getFieldAs<int>(Id::UserData, idx);
  52. //compute r c l
  53. row=uint((p.y - yMin) / GSD) + 1;
  54. col=uint((p.x - xMin) / GSD) + 1;
  55. lay=uint((p.z - zMin) / GSD) + 1;
  56. gridNumber = (row - 1)*cols + col;
  57. if (bVoxel)
  58. gridNumber = (lay - 1)*rows*cols + (row - 1)*cols + col;
  59. //store
  60. mhGrid.insert(gridNumber, p);
  61. }
  62. return mhGrid;
  63. }

2.2 体素抽稀:格网内点坐标取均值,用PDAL写点

  1. //降采样-抽稀:均值
  2. void PointCloudGrid::VoxelDownSample(const QMultiHash<uint, xjPoint> &mhGrid, const QString &resultPath)
  3. {
  4. #pragma region write 1as
  5. using namespace pdal;
  6. using namespace pdal::Dimension;
  7. double xoffset = 0, yoffset = 0, zoffset = 0;
  8. PointTable table;
  9. table.layout()->registerDim(Dimension::Id::X);
  10. table.layout()->registerDim(Dimension::Id::Y);
  11. table.layout()->registerDim(Dimension::Id::Z);
  12. table.layout()->registerDim(Dimension::Id::Red);
  13. table.layout()->registerDim(Dimension::Id::Green);
  14. table.layout()->registerDim(Dimension::Id::Blue);
  15. PointViewPtr view(new PointView(table));
  16. #pragma endregion
  17. //traversal
  18. int idx = 0;
  19. QList<xjPoint> listP;
  20. QMultiHash<uint, int> mhKey;
  21. for (QMultiHash<uint, xjPoint>::const_iterator it = mhGrid.constBegin(); it != mhGrid.constEnd(); ++it)
  22. {
  23. uint gn = it.key();
  24. if (mhKey.contains(gn)) { continue; }
  25. mhKey.insert(gn, gn);
  26. //average
  27. double nx = 0, ny = 0, nz = 0;
  28. int nr = 0, ng = 0, nb = 0;
  29. listP = mhGrid.values(it.key());
  30. for each (xjPoint p in listP)
  31. {
  32. nx += p.x;
  33. ny += p.y;
  34. nz += p.z;
  35. nr += p.red;
  36. ng += p.green;
  37. nb += p.blue;
  38. }
  39. nx /= listP.size();
  40. ny /= listP.size();
  41. nz /= listP.size();
  42. nr /= listP.size();
  43. ng /= listP.size();
  44. nb /= listP.size();
  45. //store
  46. view->setField(Id::X, idx, nx);
  47. view->setField(Id::Y, idx, ny);
  48. view->setField(Id::Z, idx, nz);
  49. view->setField(Id::Red, idx, static_cast<uint16_t>(nr));
  50. view->setField(Id::Green, idx, static_cast<uint16_t>(ng));
  51. view->setField(Id::Blue, idx, static_cast<uint16_t>(nb));
  52. idx++;
  53. xoffset = nx;
  54. yoffset = ny;
  55. zoffset = nz;
  56. }
  57. #pragma region write las
  58. Options xjOptions;
  59. xjOptions.add("filename", resultPath.toStdString());
  60. xjOptions.add("offset_x", xoffset);
  61. xjOptions.add("offset_y", yoffset);
  62. xjOptions.add("offset_z", zoffset);
  63. xjOptions.add("scale_x", 0.0001);
  64. xjOptions.add("scale_y", 0.0001);
  65. xjOptions.add("scale_z", 0.0001);
  66. BufferReader xjBufferReader;
  67. xjBufferReader.addView(view);
  68. StageFactory factory;
  69. Stage *writer = factory.createStage("writers.las");
  70. writer->setInput(xjBufferReader);
  71. writer->setOptions(xjOptions);
  72. writer->prepare(table);
  73. writer->execute(table);
  74. #pragma endregion
  75. }

三、试验结果

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/394195
推荐阅读
相关标签
  

闽ICP备14008679号