将 2D 数组的 1D 索引的最近邻映射到更小的 2D 数组

发布于 2024-08-15 19:03:20 字数 1238 浏览 13 评论 0原文

这是用 C 语言编写的。

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

只是尝试定义一些变量: ArrayA:SizeAX by SizeAY,通过位置 posAX、posAY 的索引 A 进行索引 ArrayB:SizeBX by SizeAY,通过位置 posBX、posBY 的索引 B 进行索引

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

所以我需要从给定的索引A设置索引B,使其成为最近邻样本,以与索引A的值关联。

这就是我所在的位置(请更正任何错误!请注意,我从索引 0 开始): 如果 ArrayA 为 9x9,ArrayB 为 3x3: (位置X,位置Y) 位置 0,0;索引A = 0 posB 0,0;索引B = 0

posA 8,0; indexA = 8(第一行末尾) 位置 B 2,0;索引B = 2

posA 0,1;索引A = 9 posB 0,0; indexB = 0(仍然接近底部点)

posA 0,3;索引A = 27 位置 B 0,1;索引B = 3

posA 8,8;索引A = 80(最后一点) 位置B 2,2; indexB = 8

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

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

我无法访问 posAY 或 posAX,只能访问 indexA,但我应该能够使用 mod 和余数将其分解,正确的?或者有更有效更快的方法吗? A

我也尝试过这个:

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

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

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

This is in C.

I have two 2D arrays, ArrayA and ArrayB, that sample the same space. B samples a different attribute than ArrayA less frequently than ArrayA, so it is smaller than A.

Just to try to define some variables:
ArrayA: SizeAX by SizeAY, indexed by indexA for a position posAX, posAY
ArrayB: SizeBX by SizeAY, indexed by indexB for a position posBX, posBY

ArrayA and ArrayB are pointers to the start of the array, where the row of X's is stored first, then Y is incremented, and the next row of X's is stored (Y=1)

So I need to set indexB from a given indexA, such that it is a nearest neighbor sample, to associate with indexA's value.

Here's where I am (correct any errors please! Note that I am starting at index 0):
If ArrayA is 9x9 and ArrayB is 3x3:
(posX,posY)
posA 0,0; indexA = 0
posB 0,0; indexB = 0

posA 8,0; indexA = 8 (end of first row)
posB 2,0; indexB = 2

posA 0,1; indexA = 9
posB 0,0; indexB = 0 (still closer to the bottom point)

posA 0,3; indexA = 27
posB 0,1; indexB = 3

posA 8,8; indexA = 80 (last point)
posB 2,2; indexB = 8

so far I have:
indexA = posAX + (posAY * SizeAX)

what I've tried (and of course failed):
indexB = (int) (indexA * (SizeBX * SizeBY / (SizeAX * SizeAY)) + 0.5) // Only appears to work for the first row and last value.. but this clearly doesn't work - but I am curious as to how exactly it maps the two together, but I'll look into that after I fix it..

I didn't have access to posAY or posAX, just indexA, but I should be able to break it down using mod and remainder, right? or is there a more efficient faster way? A

I also tried this:

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

I think the problem is that I need to round the X and Y indexes separate then use SizeBX and SizeBY afterwards?

An extra caveat is that ArrayA and ArrayB come from larger data set that both sample a larger space. Since the rectangle is arbitrary, either ArrayA or ArrayB could have the point closest to the bounds of the rectangle, leading to other issues as to which way the nearest neighbor is really grabbing. I am not sure about how to address this, either.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

巴黎夜雨 2024-08-22 19:03:20

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

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

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

的方案

这是从索引 A -> (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<=fracBX<=SizeBX 和 0<=fracBY<=SizeBY:

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

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

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 中的四个相邻点为界。

Those are some revolting names you've chosen, but at least they're defined.

I think you want to go through (x,y) in [0...1]x[0...1] real coordinate space; that is, the lower right of A should grab the value from the lower right of B, and likewise for mid-upper-left, etc. This means that you should think of the outside edges of points in your array as the 0-width point samples values at the edges of the [0...1]x[0...1] box; i.e. if you have a 3x3 array, there's one point at (0.5,0.5) and the rest are along an edge.

I'll assume your 2d B array has real values in it, so that it makes sense to interpolate; because the arrays are of different sizes

Here's the scheme for going from a

indexA -> (posAX,posAY) -> (x,y) -> (fracBX,fracBY) ->(by nearest neighbor interpolation) value from ArrayB

Important: (fracBX,fracBY) are real-valued coordinates in the box [0...SizeBX-1]x[0...SizeBY-1].

Let's take it one step at a time. Assuming I understood you, values are in memory in left->right, top->bottom (english reading) order, just like standard C arrays. Then:

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

Now, let's map to (x,y):

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

Now, to (fracBX,fracBY), where 0<=fracBX<=SizeBX and 0<=fracBY<=SizeBY:

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

Now, to interpolate between the (up to 4) nearest integral points in the B array:

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;

value is your answer. The checks for the fractional positions aBX and aBY being 0 are needed to prevent accessing values off the end of the array (which can cause a segfault even though the values are ignored by multiplying by 0). Or you can simplify things by allocating 1 more row/column than you need.

bv[0] is the ArrayB[intBX][intBY], bv[1] is one to the right, bv[sizeBY] is one down, and bv[sizeBY+1] is one down and to the right. (aBX,aBY) is another point in [0...1]x[0...1], but this time bounded by those four adjacent points in ArrayB.

紫南 2024-08-22 19:03:20

您的本质意思是,您有两个具有不同间距的网格覆盖同一区域,并且给定其中一个网格点的索引,您希望在第二个网格中找到最接近的网格点。像这样:

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;

What you essentially mean is that you have two grids with different spacing covering the same area and given an index of a gridpoint in one of them you want to find the closest one in the second. Like this:

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;

To get posAX and posAY from indexA:

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

To do bilinear interpolation:

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文