Algorithm 网格点拟合算法

Algorithm 网格点拟合算法,algorithm,Algorithm,我有一个2D空间中形成(不完美)网格的点列表: 将这些点拟合到刚性网格的最佳方法是什么(即创建一个二维数组并计算出每个点在该数组中的位置) 网格上没有洞,但我事先不知道它的尺寸是多少 编辑:网格不一定是规则的(甚至不是行/列之间的间距)我能想到的最好的解决方案是一个蛮力解决方案,它计算网格尺寸,使点与其最近的网格交点之间的欧几里德距离的平方误差最小化 这假设点的数量p正好等于列的数量乘以行的数量,并且每个网格交点上正好有一个点。它还假设任意点的最小x/y值为零。如果最小值大于零,只需从每个点的x

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

将这些点拟合到刚性网格的最佳方法是什么(即创建一个二维数组并计算出每个点在该数组中的位置)

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


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

我能想到的最好的解决方案是一个蛮力解决方案,它计算网格尺寸,使点与其最近的网格交点之间的欧几里德距离的平方误差最小化

这假设点的数量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;
for(col_count=1;col_count 1)col_width=max_x/(col_count-1);
else col_width=最大值x;
如果(行计数>1)行高度=最大y/(行计数-1);
else行高度=最大值;
//重置新配置的错误
误差_dist=0.0;
对于(i=0;i

得到列数(从而得到行数)后,可以重新计算每个点的标准化值,并对其进行四舍五入,以获得它们所属的网格交点。

最后,我使用了这个算法,灵感来自比克的:

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

  • 一点图像处理方法: 如果你认为你有一个二进制图像,其中X是1,其余的是0,你可以将行和列相加,并使用峰值查找算法来识别对应于网格X和y线的峰值:

    您的点作为二进制图像:

    行/列之和

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

    我相信你会明白的:-)


    祝你好运

    我写了这个算法,它可以解释丢失的坐标以及有错误的坐标

    Python代码 代码输出
    我也在寻找另一个使用线性代数的解决方案。查看我的问题。

    为什么不舍入每个坐标?您需要每个行/列的大小,或者只需要行/列计数?看起来像是某种傅里叶变换的工作。@n.m.您的意思是如果您事先不知道虚拟网格是什么?如果是的话…@dystroy-我不能对坐标进行舍入,因为同一行/列中的点可能不止一个单位。谢谢!这几乎就是我想要的,只是我忘了指定网格不一定是规则的(参见其他答案)谢谢!最后,我针对一个稍微不同的问题采用了这种方法,我不能假设没有空白(但不能太稀疏):分别考虑
    x
    y
    坐标,我尝试增加
    插槽的数量(即col或rows),当发现超过百分之几的插槽为空时停止,然后返回具有最小平方误差和的解决方案。
    
      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;
    
    # 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]]]