用于将点拟合到网格的算法

时间:2013-01-08 16:34:18

标签: algorithm

我在2D空间中有一个点列表,形成一个(不完美的)网格:

x     x        x         x

 x    x       x           x

                 x
x      x                x

 x     x      x           x

将这些适合刚性网格的最佳方法是什么(即创建一个二维数组并找出每个点适合该数组的位置)?

网格中没有洞,但我事先并不知道它的尺寸是多少。

编辑:网格不一定是规则的(行/列之间的间距不均匀)

4 个答案:

答案 0 :(得分:4)

一点点图像处理方法: 如果你想到你所拥有的二进制图像,其中X是1而其余部分是0,你可以总结行和列,并使用峰值查找算法来识别与网格的x和y行对应的峰值:

你的点作为二进制图像:

enter image description here

行/列的总和

enter image description here

现在对信号应用一些平滑技术(例如,低位):

enter image description here

我相信你明白了: - )

祝你好运

答案 1 :(得分:3)

我能想出的最好的是一个蛮力解决方案,它可以计算网格尺寸,最大限度地减少点与其最近网格交点之间欧几里德距离平方的误差。

这假设点p的数量正好等于列数乘以行数,并且每个网格交叉点上只有一个点。它还假设任何点的最小x / y值为零。如果最小值大于零,则只需从每个点的x坐标中减去最小x值,并从每个点的y坐标中减去最小y值。

我们的想法是根据点数创建所有可能的网格尺寸。在上面的16个点的例子中,我们将制作尺寸为1x16,2x8,4x4,8x2和16x1的网格。对于这些网格中的每一个,我们通过将点的最大宽度除以列数减1来计算网格交叉点的位置,并将点的最大高度除以行数减1.然后我们将每个点拟合为它最近的网格交叉点,找到点和交点之间的误差(距离的平方)。 (请注意,这仅适用于每个点更接近其预期的网格交叉点而不是任何其他交叉点。)

在逐个求和每个网格配置的错误之后(例如,为1x16配置获取一个错误值,为2x8配置获取另一个错误值,等等),我们选择具有最低错误的配置。

初​​始化:

  P is the set of points such that P[i][0] is the x-coordinate and
                                   P[i][1] is the y-coordinate
  Let p = |P| or the number of points in P
  Let max_x = the maximum x-coordinate in P
  Let max_y = the maximum y-coordinate in P
     (minimum values are assumed to be zero)

  Initialize min_error_dist = +infinity
  Initialize min_error_cols = -1

算法:

  for (col_count = 1; col_count <= n; col_count++) {
     // only compute for integer # of rows and cols
     if ((p % col_count) == 0) {   
        row_count = n/col_count;

        // Compute the width of the columns and height of the rows
        // If the number of columns is 1, let the column width be max_x
        // (and similarly for rows)
        if (col_count > 1) col_width = max_x/(col_count-1);
        else col_width=max_x;
        if (row_count > 1) row_height = max_y/(row_count-1);
        else row_height=max_y;

        // reset the error for the new configuration
        error_dist = 0.0;
        for (i = 0; i < n; i++) {
           // For the current point, normalize the x- and y-coordinates
           // so that it's in the range 0..(col_count-1)
           //                       and 0..(row_count-1)
           normalized_x = P[i][0]/col_width;
           normalized_y = P[i][1]/row_height;

           // Error is the sum of the squares of the distances between 
           // the current point and the nearest grid point 
           // (in both the x and y direction)
           error_dist += (normalized_x - round(normalized_x))^2 +
                         (normalized_y - round(normalized_y))^2;
        }

        if (error_dist < min_error_dist) {
           min_error_dist = error_dist;
           min_error_cols = col_count;
        }
     }
  }
  return min_error_cols;

一旦获得了列数(以及行数),就可以重新计算每个点的标准化值并将它们四舍五入以获得它们所属的网格交集。

答案 2 :(得分:2)

最后我使用了这个算法,灵感来自于烧杯:

  1. 给定总点数
  2. ,计算网格的所有可能尺寸
  3. 对于每个可能的维度,将点拟合到该维度并计算对齐方差:
    • 按x值排序点数
    • 将点分组为列:第一个r点构成第一列,其中r是行数
    • 在每列中,按y值对点进行排序,以确定它们位于
    • 中的哪一行
    • 对于每个行/列,计算y值/ x值的范围
    • 对齐方差是找到的最大范围
  4. 选择对齐方差最小的维度

答案 3 :(得分:0)

我编写了此算法,该算法考虑了缺少的坐标以及有错误的坐标。

Python代码

# Input [x, y] coordinates of a 'sparse' grid with errors
xys = [[103,101],
       [198,103],
       [300, 99],
       [ 97,205],
       [304,202],
       [102,295],
       [200,303],
       [104,405],
       [205,394],
       [298,401]]

def row_col_avgs(num_list, ratio):
    # Finds the average of each row and column. Coordinates are
    # assigned to a row and column by specifying an error ratio.
    last_num = 0
    sum_nums = 0
    count_nums = 0
    avgs = []
    num_list.sort()
    for num in num_list:
        if num > (1 + ratio) * last_num and count_nums != 0:
            avgs.append(int(round(sum_nums/count_nums,0)))
            sum_nums = num
            count_nums = 1
        else:
            sum_nums = sum_nums + num
            count_nums = count_nums + 1
        last_num = num
    avgs.append(int(round(sum_nums/count_nums,0)))
    return avgs

# Split coordinates into two lists of x's and y's
xs, ys = map(list, zip(*xys))

# Find averages of each row and column within a specified error.
x_avgs = row_col_avgs(xs, 0.1)
y_avgs = row_col_avgs(ys, 0.1)

# Return Completed Averaged Grid
avg_grid = []
for y_avg in y_avgs:
    avg_row = []
    for x_avg in x_avgs:
        avg_row.append([int(x_avg), int(y_avg)])
    avg_grid.append(avg_row)

print(avg_grid)

代码输出

[[[102, 101], [201, 101], [301, 101]], 
 [[102, 204], [201, 204], [301, 204]], 
 [[102, 299], [201, 299], [301, 299]], 
 [[102, 400], [201, 400], [301, 400]]]

我也在寻找使用线性代数的另一种解决方案。请参阅我的问题here