【问题标题】:nearest neighbor mapping of 1D index for 2D array into a smaller 2D array将 2D 数组的 1D 索引最近邻映射到较小的 2D 数组
【发布时间】:2009-12-18 20:39:24
【问题描述】:

这是在 C 中。

我有两个二维数组,ArrayA 和 ArrayB,它们对相同的空间进行采样。 B 对与 ArrayA 不同的属性进行采样的频率低于 ArrayA,因此它比 A 小。

只是尝试定义一些变量: ArrayA:SizeAX by SizeAY,由 indexA 索引位置 posAX, posAY ArrayB:SizeBX by SizeAY,由 indexB 索引位置 posBX, posBY

ArrayA 和 ArrayB 是指向数组开头的指针,其中先存储 X 的行,然后 Y 递增,然后存储下一行 X (Y=1)

所以我需要从给定的 indexA 中设置 indexB,使其成为最近邻样本,以与 indexA 的值相关联。

这是我所在的位置(请更正任何错误!请注意,我从索引 0 开始): 如果 ArrayA 是 9x9 而 ArrayB 是 3x3: (posX,posY) 位置 0,0;索引A = 0 POSB 0,0; indexB = 0

posA 8,0; indexA = 8(第一行结束) posB 2,0; indexB = 2

posA 0,1;指数A = 9 POSB 0,0; indexB = 0(仍然更接近底部)

posA 0,3;指数A = 27 位置 0,1; indexB = 3

posA 8,8; indexA = 80(最后一点) posB 2,2;指数B = 8

到目前为止,我有: indexA = posAX + (posAY * SizeAX)

我尝试过的(当然失败了): indexB = (int) (indexA * (SizeBX * SizeBY / (SizeAX * SizeAY)) + 0.5) // 似乎只适用于第一行和最后一个值..但这显然不起作用 - 但我很好奇到底它是如何将两者映射在一起的,但我会在修复它之后进行研究..

我无法访问 posAY 或 posAX,只能访问 indexA,但我应该可以使用 mod 和余数将其分解,对吧?还是有更有效更快的方法?一个

我也试过这个:

indexB = (posAY * SizeBY / SizeAY) * SizeBY + (posAX * SizeBX / SizeAX)

我认为问题是我需要将 X 和 Y 索引分开,然后使用 SizeBX 和 SizeBY?

一个额外的警告是 ArrayA 和 ArrayB 来自更大的数据集,它们都采样了更大的空间。由于矩形是任意的,因此 ArrayA 或 ArrayB 的点可能最接近矩形的边界,从而导致其他问题,即最近邻居真正抓取的方式。我也不确定如何解决这个问题。

【问题讨论】:

    标签: c pointers indexing multidimensional-array nearest-neighbor


    【解决方案1】:

    这些是你选择的一些令人反感的名字,但至少它们是被定义的。

    我想你想在 [0...1]x[0...1] 真实坐标空间中经过 (x,y) ;也就是说,A 的右下角应该从 B 的右下角获取值,同样对于左上角的中间等。这意味着您应该将数组中点的外边缘视为 0 宽度point 在 [0...1]x[0...1] 框的边缘采样值;即,如果您有一个 3x3 数组,则在 (0.5,0.5) 处有一个点,其余点位于边缘。

    我假设您的 2d B 数组中有实数值,因此插值是有意义的;因为数组的大小不同

    这是从a开始的方案

    indexA -> (posAX,posAY) -> (x,y) -> (fracBX,fracBY) ->(通过最近邻插值)来自 ArrayB 的值

    重要提示:(fracBX,fracBY) 是 [0...SizeBX-1]x[0...SizeBY-1] 框中的实值坐标。

    让我们一步一步来。假设我理解你,值在内存中的顺序是左-> 右、上-> 下(英文阅读),就像标准 C 数组一样。那么:

    unsigned posAX=indexA%SizeAX;
    unsigned posAY=indexA/SizeAX;
    

    现在,让我们映射到 (x,y):

    double x=posAX/(SizeAX-1.0); // we get double division when we subtract by 1.0
    double y=posAY/(SizeAY-1.0);
    

    现在,到 (fracBX,fracBY),其中 0

    double fracBX=x*(SizeBX-1);
    double fracBY=y*(SizeBY-1);
    

    现在,在 B 数组中(最多 4 个)最近的积分点之间进行插值:

    unsigned intBX=(unsigned)fracBX;
    double aBX=fracBX-intBX;
    unsigned intBY=(unsigned)fracBY;
    double aBY=fracBY-intBY;
    double *bv=ArrayB+(intBX*sizeBY)+intBY;
    #define INTERP(alpha,v1,v2) ((1-alpha)*v1+alpha*v2)
    #define INTERPI(alpha,i1,i2) (alpha>0 ? INTERP(alpha,bv[i1],bv[i2] : bv[i1])
    double v0=INTERPI(aBX,0,1);
    double value=fracBY>0 ? INTERP(aBY,v0,INTERPI(aBX,sizeBY,sizeBY+1)) : v0;
    

    价值就是你的答案。需要检查小数位置 aBX 和 aBY 是否为 0,以防止访问数组末尾的值(即使这些值乘以 0 会被忽略,这也可能导致段错误)。或者,您可以通过分配比您需要的多 1 行/列来简化事情。

    bv[0] 是 ArrayB[intBX][intBY],bv[1] 是右一,bv[sizeBY] 是下一,bv[sizeBY+1] 是右下一。 (aBX,aBY) 是 [0...1]x[0...1] 中的另一个点,但这次以 ArrayB 中的四个相邻点为界。

    【讨论】:

    • 感谢您的回答,双线性插值可能是我的下一步!
    • 如果unsigned intBY=(unsigned)fracBY 最终与(SizeBY-1) 完全相同(posAY 在边界上),则此插值不起作用。在这种情况下,您将对数组外部的行 SizeBY 进行采样。
    • (查看我的答案以获取另一个版本)
    • 在这种情况下,alpha 将为 0,因此只会使用上/左地址。我同意这需要小心,但我已经小心了。
    【解决方案2】:

    你的意思是你有两个不同间距的网格覆盖相同的区域,并在其中一个中给出一个网格点的索引,你想在第二个中找到最近的一个。像这样:

    int posBX = (int)floorf((float(posAX) / float(sizeAX - 1)) * float(sizeBX - 1) + 0.5f);
    int posBY = (int)floorf((float(posAY) / float(sizeAY - 1)) * float(sizeBY - 1) + 0.5f);
    int indexB = posBX + posBY * sizeBX;
    

    indexA获取posAXposAY

    posAX = indexA % sizeAX;
    posAY = indexA / sizeAX;
    

    做双线性插值:

    float bx = (float(posAX) / float(sizeAX - 1)) * float(sizeBX - 1);
    float by = (float(posAY) / float(sizeAY - 1)) * float(sizeBY - 1);
    int x = min(int(floorf(bx)), sizeBX - 2); //x + 1 must be <= sizeBX - 1
    int y = min(int(floorf(by)), sizeBY - 2); //y + 1 must be <= sizeBY - 1
    float s = bx - float(x);
    float t = by - float(y);
    float v[4];
    v[0] = arrayB[x + y * sizeBX];
    v[1] = arrayB[x + 1 + y * sizeBX];
    v[2] = arrayB[x + (y + 1) * sizeBX];
    v[3] = arrayB[x + 1 + (y + 1) * sizeBX];
    float result = (v[0] * (1.0f - s) + v[1] * s) * (1.0f - t) +
                   (v[2] * (1.0f - s) + v[3] * s) * t;
    

    【讨论】:

    • 我快到了,但在决定将 -1 放在哪里时遇到了问题!谢谢!关于如何处理最后一部分的任何线索?我担心它在某些情况下可能会选择错误的点,但也许它实际上会以这种方式自动处理自己?
    • 下面我稍微复杂一点的答案执行最近邻插值,并且应该同意 SizeBX 划分 SizeAX 并且 SizeBY 平均划分 SizeAY 的情况。
    • 嗯,你的意思是A区域和B区域的边界不一定对齐?
    • 我假设你的答案是正确的(我没有检查);你只是四舍五入到最近的位置。我正在取B 中四个最近点的平均值。例如,A 为 3 x 4 数组,B 为 11 x 5。换句话说,我认为B 的水平和垂直分辨率与A 相比可能会有不同的比率。
    • @wrang-wrang 我理解你的双线性插值,我的评论是针对 OP 的评论。
    猜你喜欢
    • 1970-01-01
    • 2013-05-03
    • 1970-01-01
    • 2018-08-06
    • 2021-08-21
    • 1970-01-01
    • 1970-01-01
    • 2016-09-12
    • 1970-01-01
    相关资源
    最近更新 更多