根据密度在网格上分布点

时间:2012-02-15 13:30:00

标签: algorithm mesh approximation

给定一个(可能是开放的)具有密度纹理和多个点的网格,我需要根据网格上的密度分布这些点。

到目前为止,我已经制定了几个解决方案,其中一些有效,有些则无效。我尝试的算法之一是通过弹簧连接点并模拟分布直到平衡(或直到解决方案适合用户需求)。来源Retiling Polygonal Surfaces 不幸的是,对于更高的点数(> 2k),这有点慢,所以我需要一个可行的解决方案来获得更高的数字。

我已经有了一些想法,但我想听听是否有一些标准解决方案。我试过谷歌,但我使用的关键字(分布密度离散)只显示处理与我的其他问题的页面。如果你指出要搜索的正确词语,我会很高兴。

3 个答案:

答案 0 :(得分:5)

通常,在具有任意密度函数的任意空间中,您可以通过rejection sampling得到合理的近似值。

  • 找到最大密度D
  • 选择一个随机点p
  • r范围内选择一个随机数[0,D)
  • 如果p的密度大于r,请接受p作为您的一个点。

我不确定这适用于您的案件有多容易。在网格上生成随机,均匀分布的点本身就像一个棘手的问题。我能想到的唯一解决方案是计算网格中每个三角形的面积,随机选择一个与其面积成比例的三角形,并在三角形内选择一个random point。我相信你可以在O(logN)的N个三角形上做这个选择。

但是考虑到你可能会抛出大部分这些点,这可能会比你当前的方法更糟糕,因为网格足够大且密度函数非常令人不快(即最大值远大于平均值)

与任何类型的随机抽样一样,在它开始类似于基础分布之前需要相当多的几点;一小部分点可能看起来或多或少随机。但是你可以通过某种准随机的点放置方法解决这个问题(即使使用大型集合,也可能会产生更好的结果)。

首先想到的是上述方法与@ BlackBear算法的混合。您可以计算每个三角形的面积和平均密度,并使用它来确定每个三角形必须包含的点数。然后,要将点实际放置在三角形内,请使用拒绝抽样方法。

答案 1 :(得分:4)

这是我的想法:

  1. 将密度纹理分成相等的矩形部分;
  2. 每个部分计算一个介于0.0和1.0之间的数字,其中1.0表示“最高点密度”,0.0表示相反,“根本没有点”;
  3. 通过划分您想要放置的总点数和所有平均值之和来计算与1.0值对应的点数;
  4. 然后你就知道你需要在每个矩形中绘制多少点,以便均匀地绘制它们;
  5. 现在,矩形越小,得到的结果就越精确。我做了一个小测试程序(C#使用慢速方法,即位图上的GetPixel和SetPixel),这里是结果,假设10k点,256x256像素图像。图片显示该算法适用于2 ^ 2,10 ^ 2,50 ^ 2和90 ^ 2部分:

    enter image description here

    这是基准:

    parts   time
    ------------------------
    2      00:00:00.7957087
    10     00:00:00.6713345
    50     00:00:00.5873524
    90     00:00:00.4153544
    

答案 2 :(得分:0)

根据任意函数分布点云的问题与dithering灰度图像同构为黑白图像。 algorithms都具有与O(N)成比例的运行时复杂度(其中N是原始图像/位图/网格/中的点数),使用像拜耳矩阵ordered dithering这样的简单方法只执行一次每点浮点比较,更复杂的error diffusion方法运行更像O(24N),但产生更好的结果,产生更少的工件。

使用简单的高斯密度函数,简单的拜耳矩阵方法可以得到令人惊讶的良好结果,小到32x32矩阵: Bayer matrix dither

在给定矩阵的情况下,可以直接生成基于矩阵的有序抖动:

matrix = generate_bayer(32);
for (y=0; y<height; y++) {
  for (var x=0; x<width; x++) {
    i = x % matrix.length;
    j = y % matrix.length;

    function_val = gaussian(x, y);  #returns a value 0<=x<=1
    scaled_val = function_val * matrix.length * matrix.length;  #scale to the max element in the matrix
    if (scaled_val > matrix[j][i]) {
      draw_pixel(x, y);
    }
  }
}

生成矩阵稍微有些棘手,但这里是一种迭代方法,用于matricies,其边长是2的幂:

//size should be a power of 2, and is the length of a side of the matrix
function generate_bayer(size) {
  base = [[0, 2],
          [3, 1]];
  old_matrix = base;
  mult = 4;

  //successively double the size of the matrix, using the previous one as the base
  while (old_matrix.length < size) {
    //generate a new matrix of the proper dimensions
    new_size = old_matrix.length * 2;
    matrix = new Array[new_size][new_size];

    for (y=0; y<old_matrix.length; y++) {
      for (x=0; x<old_matrix[y].length; x++) {
        //fill in the new 4x4 submatrix
        matrix[y*2]    [x*2]     = old_matrix[y][x] + (mult * base[0][0]);
        matrix[y*2]    [x*2 + 1] = old_matrix[y][x] + (mult * base[0][1]);
        matrix[y*2 + 1][x*2]     = old_matrix[y][x] + (mult * base[1][0]);
        matrix[y*2 + 1][x*2 + 1] = old_matrix[y][x] + (mult * base[1][1]);
      }
    }

    mult *= 4;
    old_matrix = matrix;
  }
  return old_matrix;
}