如何计算网格中的重心?

时间:2013-02-02 03:34:58

标签: algorithm math

给定具有x * y单元格的网格(或表格)。每个单元格都包含一个值。这些单元格中的大多数都具有值0,但是在该网格上的某处可能存在具有高值的单元格的“热点”。然后该单元的邻居也具有> 1的值。 0.越远离热点,因为相应的网格单元中的值越低。

因此,这个热点可以看作是山顶,随着价值的降低,我们远离这座山。在某个距离,值再次降至0。

现在我需要确定网格中代表网格重心的单元格。在上面的简单示例中,这个质心将只是具有最高值的一个单元格。然而,并不总是那么简单:

  1. 热点单元周围相邻单元的下降值可能不均匀分布,或者“山边”可能比另一侧更早下降到0。

  2. 还有另一个热点/山,值为> 0也在网格内。

  3. 我可以认为这是一个典型的问题。不幸的是,我不是数学专家所以我不知道要搜索什么(至少我没有在谷歌找到答案)。

    任何想法如何解决这个问题?

    提前致谢。

2 个答案:

答案 0 :(得分:3)

您正在寻找单元格值的“加权平均值”。假设每个单元格的值为z(x,y),那么您可以执行以下操作

zx = sum( z(x, y) ) over all values of y
zy = sum( z(x, y) ) over all values of x

meanX = sum( x * zx(x)) / sum ( zx(x) )
meanY = sum( y * zy(y)) / sum ( zy(y) )

我相信你可以把它转换成你选择的语言......

示例:如果您了解Matlab,则上述内容将编写如下

zx = sum( Z, 1 ); % sum all the rows
zy = sum( Z, 2 ); % sum all the columns

[ny nx] = size(Z); % find out the dimensions of Z

meanX = sum((1:nx).*zx) / sum(zx);
meanY = sum((1:ny).*zy) / sum(zy);

这将给出1 ... nx范围内的meanX:如果它在中间,则值为(nx + 1)/ 2。显然,您可以根据需要进行扩展。

编辑:再一次,用“几乎真实”的代码:

// array Z(N, M) contains values on an evenly spaced grid
// assume base 1 arrays

zx = zeros(N);
zy = zeros(M);

// create X profile:
for jj = 1 to M
  for ii = 1 to N
    zx(jj) = zx(jj) + Z(ii, jj);
  next ii
next jj

// create Y profile:
for ii = 1 to N
  for jj = 1 to M
    zy(ii) = zy(ii) + Z(ii, jj);
  next jj
next ii

xsum = 0;
zxsum = 0;
for ii = 1 to N
  zxsum += zx(ii);
  xsum += ii * zx(ii);
next ii
xmean = xsum / zxsum;

ysum = 0;
zysum = 0;
for jj = 1 to M
  zysum += zy(jj);
  ysum += jj * zy(ii);
next jj
ymean = ysum / zysum;

答案 1 :(得分:1)

This Wikipedia entry可能会有所帮助;标题为“粒子系统”的部分就是您所需要的。只需了解您需要为每个维度进行一次计算,其中您显然有两个维度。

这是一个完整的Scala 2.10程序,用于生成一个充满随机整数的网格(使用命令行中指定的维度)并找到重心(行和列从1开始编号):

object Ctr extends App {
  val Array( nRows, nCols ) = args map (_.toInt)
  val grid = Array.fill( nRows, nCols )( util.Random.nextInt(10) )
  grid foreach ( row => println( row mkString "," ) )
  val sum = grid.map(_.sum).sum
  val xCtr = ( ( for ( i <- 0 until nRows; j <- 0 until nCols )
    yield (j+1) * grid(i)(j) ).sum :Float ) / sum
  val yCtr = ( ( for ( i <- 0 until nRows; j <- 0 until nCols )
    yield (i+1) * grid(i)(j) ).sum :Float ) / sum
  println( s"Center is ( $xCtr, $yCtr )" )
}

你可以修改一个函数来保持计算DRYer,但我想尽可能地保持它。无论如何,我们在这里运行了几次:

$ scala Ctr 3 3
4,1,9
3,5,1
9,5,0
Center is ( 1.8378378, 2.0 )

$ scala Ctr 6 9
5,1,1,0,0,4,5,4,6
9,1,0,7,2,7,5,6,7
1,2,6,6,1,8,2,4,6
1,3,9,8,2,9,3,6,7
0,7,1,7,6,6,2,6,1
3,9,6,4,3,2,5,7,1
Center is ( 5.2956524, 3.626087 )