展开2D点分布的算法

时间:2009-08-19 19:51:19

标签: geometry 2d distribution point

在2D像素阵列中,我需要一种有效的算法来选择分布最多的p%像素。

这可以通过选择点自适应地完成,然后重复调整太靠近的点的位置。但这并不高效,因为它需要多次迭代和距离计算。

它不一定非常完美,它只需要尽可能多地避免点聚类。

10 个答案:

答案 0 :(得分:1)

你想要Poisson Disk发行版,但它很棘手。进行搜索会产生大量关于如何有效地进行搜索的学术论文:http://people.csail.mit.edu/thouis/JonesPoissonPreprint.pdf

答案 1 :(得分:1)

感谢大家的答案!

最好的解决方案似乎是使用“预构建构建块”:n x n个已经选定单元格的数组,并用这些数组覆盖像素数组。

例如,覆盖率为12.5%的4 x 4阵列将是:

0 0 1 0
0 0 0 0
1 0 0 0
0 0 0 0

覆盖率为6.3%:

0 0 0 0
0 1 0 0
0 0 0 0
0 0 0 0

要在这些之间获得%覆盖率,只需根据到目前为止整体实际%覆盖率的运行记录在这些块之间切换。要覆盖不是4的倍数的宽度,请使用一些3 x 3块。为了更有效地覆盖更大的区域,只需使用更大的块。

这有效地覆盖整个阵列,无需进行距离计算或浮点运算。

答案 2 :(得分:1)

像素的“最大分散”选择是其Delaunay三角测量由等边三角形组成的集合。导致这种三角测量的点集是通过将像素阵列分成一组框来找到的,其中每个框比它宽的方格(3)长。每个盒子为最终像素组贡献5个像素(每个角落一个,加上盒子中心的中心节点)。诀窍是找到多少行和列的框将为您提供1:sqrt(3)比率。没有经过推导,这就是你如何得到它:

std::vector<PixelIndices> PickPixels(int width, int height, float percent)
{
  int total_pixels = width*height;
  int desired_pixel_count = (int)total_pixels*percent;

  // split the region up into "boxes" with 4 corner nodes and a center node.
  // each box is sqrt(3) times taller than it is wide.

  // calculate how many columns of boxes
  float a = 1.155*height/(float)width;
  float b = .577*height/(float)width + 1;
  float c = 1 - desired_pixel_count;
  int num_columns = (int)((-b + sqrt(b*b -4*a*c))/(2*a));

  // Now calculate how many rows
  int num_rows = .577*height*num_columns/(float)width;

  // total number of pixels
  int actual_pixel_count = 2*num_rows*num_columns + num_rows + num_columns + 1;

  std::cout << "  Total pixels: " << total_pixels << std::endl;
  std::cout << "       Percent: " << percent << std::endl;
  std::cout << "Desired pixels: " << desired_pixel_count << std::endl;
  std::cout << " Actual pixels: " << actual_pixel_count << std::endl;
  std::cout << "   Number Rows: " << num_rows << std::endl;
  std::cout << "Number Columns: " << num_columns << std::endl;

  // Pre-allocate space for the pixels
  std::vector<PixelIndices> results;
  results.reserve(actual_pixel_count);

  // Now get the pixels, my integer math is probably wrong here, didn't test
  //  (didn't even finish, ran out of time)
  for (int row = 0; row <= num_rows; row++)
  {
    int row_index = row*height/num_rows;

    // Top of box
    for (int col = 0; col <= num_columns; col++)
    {
      int col_index = col*width/num_columns;
      results.push_back(PixelIndices(row_index, col_index));
    }

    // Middle of box
    if (row != num_columns)
    {
      for (int col = 0; col < num_columns; col++)
      {
         // I'll leave it to you to get this, I gotta go!
      }
    }
  }

  return results;
}

不是使用整数除法来查找索引,而是可以通过查找行/列中每个点之间的距离并仅添加偏移来加快速度。

答案 3 :(得分:1)

你可以试试王瓦:
http://en.wikipedia.org/wiki/Wang_tile
(请参阅与Cohen的论文相关的页面,以及Kopf的论文。我是新用户,因此无法发布所有链接。)

这些将预构建的瓷砖概念以及通常用泊松磁盘模式解决的均匀分布的要求结合在一起。 Wang瓷砖可以避免周期性效应,这几乎肯定是更直接使用预制瓷砖的问题。

答案 4 :(得分:1)

相当陈旧,但值得深入研究,因为答案错过了一个重要的方法,并专注于您不感兴趣的最佳解决方案。但我建议的方法可能适合或不适合您的需求。

您可以使用专为此类问题设计的quasi random sequences。最普遍的是Sobol sequences,您可以为其找到几乎任何语言的罐装包。它们非常快:只有按位运算。

它们很可能会产生一些簇,但可以通过选择预先用于x和y维度的“种子”并用肉眼检查来避免这种情况。

这取决于你想要点数:如果“视觉传播”很重要,这可能不是你想要的。如果你想要几乎均匀地“填充飞机”的点,他们完美地完成这项工作。它们对于快速平均图像上的某些内容特别有用,因为它需要较少的点来进行“正常”随机生成。尝试不同的尺寸,并参见。

有关示例实验和图片,请参阅this link

答案 5 :(得分:0)

这个怎么样:

  1. 发现从每个点到另一个点的距离之和。所以A点的总距离为dist(A,B)+ dist(A,C)+ dist(A,D)+ ......
  2. 对这些总距离进行排序。
  3. 删除距离最小的点,直至达到所需的百分比。
  4. 这可能足够准确,但如果没有,您可以随时将步骤3替换为:

    “删除总和最小的点,如果您需要删除更多点数以达到所需的百分比,请返回步骤1.”

    等待。现在我想知道。您是否正在尝试找到从给定点集中分布最多的点...或者尝试从给定数组中找到最分散的点?那是完全不同的......而且还很难。

答案 6 :(得分:0)

如何根据每个像素与所有其他像素的接近程度计算每个像素的“密度”值。然后,重复删除最“密集”的像素,直到列表中剩余的p%以下为止。

您需要进行距离计算,以确定任意给定两点之间的密度最多两次。第一次是在构建原始列表时 - 每个像素都需要与其他像素进行比较。第二个是当您从列表中删除一个像素时 - 您必须针对列表中剩余的每个像素计算删除的像素。这是为了考虑密度值随着每个像素被移除而变化 - 例如,直接相邻的2个像素将具有非常高的值,但是一旦移除一个,则剩余的一个可能具有非常低的值。

一些快速伪代码(请注意,在此示例中,较高密度区域的数字较低)

For I = 0 to MaxPixel
    For J = I to MaxPixel
        PixelDensity[I], PixelDensity[J] += DistanceBetween(Pixels[I], Pixels[J])

While PixelDensity.Count > TargetCount
    RemovePixel = IndexOfSmallest(PixelDensity)
    ForEach I in PixelDensity
        PixelDensity[I] -= DistanceBetween(Pixels[I], Pixels[RemovePixel])
    PixelDensity.Remove(RemovePixel)

如果内存不像计算时间那么令人担忧,您还可以在简单的2d数组中存储任意两点之间的距离。此外,代替简单的距离,使距离计算成指数可能是有帮助的 - 这将避免像两个点几乎在彼此之上,但远离其他一切,并且两者都通过它。

答案 7 :(得分:0)

迭代的扫雷洪水填充方法可以直观地进行可视化。

  1. 对于每个单元格,找到两个最近的点并记录这两个距离的乘积。
  2. 产品含量最高的细胞是附着在最远点的细胞。

答案 8 :(得分:0)

噢!怎么样!

(以非常手动的方式,因为我不知道你的矩阵是正方形还是其他......我会认为它是。)

假设你有一个1000x1000数组,你想要放入47点(我选择47这是一个不寻常的数字,不适合“很好”)。

你拿ceil(sqrt(47))...这会给你一个值(7)。所以我们制作一个7x7的正方形,用47像素(有些是空白的)填充它,并想象将它放在数组的角落。

现在,根据它们在小型(7x7)阵列到大型阵列(1000x1000)的位置,将每个像素转换为新位置。一个简单的等式应该为你做...对于X坐标,例如:

xBigArrayIndex = xSmallArrayIndex * 1000 / 7;

然后你的像素将超级散开!它很好而且很快。

唯一的缺点是,只有当你的方形理想地间隔开始时才能完美地工作......如果你天真地填充它(从左上角开始,穿过等等),你最终会有一点点亚理想的扩散...因为翻译的像素不会完全到达大阵列的右下角。但也许这足够好了?如果没有,也许这个问题的一小部分更容易处理?

答案 9 :(得分:0)

您可以使用凸包算法,并排除此算法将计算的点,并重复它,只要它达到您的p%标准, 或

执行凸包算法步骤,检查船体及其内部包含的点数是否符合标准100% - p%

凸壳的一些演示在这里 http://www.cs.unc.edu/~snoeyink/demos/

在这里你得到了更多信息 http://softsurfer.com/Archive/algorithm_0109/algorithm_0109.htm