【问题标题】:Clustering of a set of 3D points一组 3D 点的聚类
【发布时间】:2018-01-22 01:10:12
【问题描述】:

我有一个大小为n 的二维数组,代表n 3D 空间中的点数,position[][] 代表 XYZ(例如,position[0][0]Xposition[0][1] 是 Y,position[0][2]是点0的Z坐标。

我需要做的是对点进行聚类,所以要拥有n/k 大小为k 的集群数量,这样每个集群都包含k 最接近 点3D空间。例如,如果 n=100k=5,我想要 20 个 5 个点的集群,它们是空间中最近的邻居。

我怎样才能做到这一点? (我需要伪代码。对于 sn-ps 最好用 Java)

到目前为止,我所做的是基于每个组件的简单排序。但这确实给了我最近的邻居。

  1. 基于 X 排序 (position[0][0])
  2. 然后根据 Y 排序 (position[0][1])
  3. 然后根据 Z 排序 (position[0][2])


for (int i=0; i<position.length; i++){
  for (int j=i+1; j<position.length; j++){
    if(position[i][0] > position[i+1][0]){
      swap (position[i+1][0], position[i][0]);
     }
   }
}
// and do this for position[i][1] (i.e. Y) and then position[i+2][2] (i.e. Z)

我相信我的问题与 使用 kd-trees 的最近邻搜索略有不同,因为每次迭代中的邻居不应与其他邻居重叠。我想我们可能需要将它用作组件,但如何使用,这是个问题。

【问题讨论】:

  • 到目前为止,您对 3d 或点云聚类技术的搜索结果如何?
  • 查看最近邻搜索alglib.net/other/nearestneighbors.php
  • 我在 3D 空间中找不到 k 个最近邻居的聚类。如上所述,我想出了自己的算法。
  • @TinaJ 我将创建一个低分辨率 3D 体素图来计算每个单元格的点密度。如果高于阈值(递归地)增加该单元格的分辨率,直到您找到您的近似簇位置...然后按与它们的距离对点进行分组...类似于密度图的Finding holes in 2d point sets? 和聚类的Effective gif/image color quantization? .. .
  • @TinaJ 我创建了一个 aswer 并描述了我的意思....

标签: java arrays algorithm 3d k-means


【解决方案1】:

你什么都不是Clustering。根据您所说,我认为您想将您的 N 个点分成 N/k 组,每组有 k 个点,同时保持每个集群中的点在 3D 空间中最接近。

想一个简单的例子,如果你想在一个维度上做同样的事情,也就是对数字进行排序,第一个 k 指向簇 1,第二个 k 指向簇 2,以此类推。

然后返回3D空间问题,答案是一样的。只需首先找到 x 轴、y 轴和 z 轴最小的点,以及它最近的 k-1 个点进入聚类 1。然后对于最少的点,找到最小的 x 轴、y 轴和 z-轴点,以及未聚类到聚类 2 中的 k-1 个最近点,依此类推。

上面的过程会得到你的结果,但这在实践中可能没有意义,也许像 k-means 这样的集群算法可以帮助你。

【讨论】:

  • 我觉得你说的和我做的一样。不是吗?
【解决方案2】:

一开始你没有八叉树,而是点列表,例如:

float position[n][3];

因此,为了简化聚类和八叉树创建,您可以使用 3D 点密度图。类似于创建直方图:

  1. 计算你的点的边界框O(n)

    因此处理所有点并确定最小和最大坐标。

  2. 创建密度图O(max(m^3,n))

    因此,将已用空间 (bbox) 划分为一些 3D 体素网格(使用您想要/需要的分辨率)执行如下密度图:

    int map[m][m][m]`
    

    并用零清除它。

    for (int x=0;x<m;x++)
     for (int y=0;y<m;y++)
      for (int z=0;z<m;z++)
       map[x][y][z]=0;
    

    然后处理所有点,从x,y,z 确定其单元格位置并递增。

    for (int i=0;i<n;i++)
     {
     int x=(m-1)*(position[i][0]-xmin)/(xmax-xmin);
     int y=(m-1)*(position[i][1]-ymin)/(ymax-ymin);
     int z=(m-1)*(position[i][2]-zmin)/(zmax-zmin);
     map[x][y][z]++;
     // here you can add point i into octree belonging to leaf representing this cell
     }
    

    这将为您提供低分辨率密度图。单元格map[x][y][z] 中的数字越大,其中的点越多,这意味着存在一个集群,您也可以将点移动到八叉树中的该集群。

对于具有足够点的单元格,可以递归地重复此操作。要让您的八叉树创建密度图2x2x2 并递归拆分每个单元格,直到其计数小于阈值或单元格大小太小。

有关更多信息,请参阅类似的QAs

【讨论】:

  • 这很好。一件事是我们受到地图单元格大小的限制。最好的尺寸是多少?!我正在考虑一种独立于选择数字的方法。
  • 顺便说一句,您在一行中写了将点 i 添加到八叉树中。所以我假设这种方法可以与八叉树结合来存储点。同时也可用于通过递归创建八叉树。对吗?
  • @TinaJ 八叉树和递归密度图具有几乎相同的结构。最佳分辨率取决于使用情况和数据。通常,如果应用程序处理可以轻松处理每个单元格的点/对象数,例如,如果您正在渲染,则当 gfx 卡可以轻松处理 RT 中的数千个图元时,每个叶子都没有单个点。所以没有必要在八叉树中的每个叶子都有一个点,除非你出于某种目的想要它......最佳八叉树分辨率取决于你正在创建的应用程序的性能,所以划分直到性能停止或再次下降......
  • 我明白了。所以理论上我的假设是正确的,但实际上对于大点来说可能是不可能的。
  • @Spektre 我能和你谈谈吗,我是奥地利的艾哈迈德,请给我一个联系方式
猜你喜欢
  • 2015-12-09
  • 2021-09-15
  • 1970-01-01
  • 1970-01-01
  • 2014-06-23
  • 2013-08-26
  • 1970-01-01
  • 2011-03-29
  • 1970-01-01
相关资源
最近更新 更多