NumPy 2D数组:选择圆形范围内的索引

14

对于一些矩形,我们可以非常高效地选择2D数组中的所有索引:

arr[y:y+height, x:x+width]

...其中(x, y)是矩形的左上角,heightwidth则分别代表矩形选择区域的行数和列数。

现在,假设我们想要选择位于某个圆内的二维数组中的所有索引,给定圆心坐标(cx, cy)和半径r。是否有一种numpy函数可以高效地实现这个目标?

目前,我正在通过手动Python循环计算索引,将索引添加到缓冲区(列表)中来预先计算。因此,对于大型2D数组而言,这相当低效,因为我需要将位于某个圆内的每个整数都放入队列中。

# buffer for x & y indices
indices_x = list()
indices_y = list()

# lower and upper index range
x_lower, x_upper = int(max(cx-r, 0)), int(min(cx+r, arr.shape[1]-1))
y_lower, y_upper = int(max(cy-r, 0)), int(min(cy+r, arr.shape[0]-1))
range_x = range(x_lower, x_upper)
range_y = range(y_lower, y_upper)

# loop over all indices
for y, x in product(range_y, range_x):
    # check if point lies within radius r
    if (x-cx)**2 + (y-cy)**2 < r**2:
        indices_y.append(y)
        indices_x.append(x)

# circle indexing
arr[(indices_y, indices_x)]

如前所述,对于较大的数组/圆形,这种方法效率会变得相当低下。有没有加速的好方法?

如果有更好的索引圆形的方式,那么是否也适用于“任意”的2D形状?例如,我是否可以通过传递一个表示任意形状点成员资格的函数来获取数组相应的numpy索引?


'y'是左上角还是左下角?因为如果我们把高度加到左上角,我们会超出边界,对吧? - undefined
2个回答

19

你可以定义一个包含圆形的遮罩。下面是我为圆形演示的代码,但你也可以在mask中编写任意函数。字段mask具有arr的尺寸,并且如果满足右侧条件,则值为True,否则为False。这个掩码可以与索引运算符结合使用,仅将值分配给选择的索引,就像arr[mask] = 123.一样。

import numpy as np
import matplotlib.pyplot as plt

x = np.arange(0, 32)
y = np.arange(0, 32)
arr = np.zeros((y.size, x.size))

cx = 12.
cy = 16.
r = 5.

# The two lines below could be merged, but I stored the mask
# for code clarity.
mask = (x[np.newaxis,:]-cx)**2 + (y[:,np.newaxis]-cy)**2 < r**2
arr[mask] = 123.

# This plot shows that only within the circle the value is set to 123.
plt.figure(figsize=(6, 6))
plt.pcolormesh(x, y, arr)
plt.colorbar()
plt.show()

4
干得好。我在我的电脑上计时,结果比我的方法快了不到5倍。对于更大的数组,差异会变得更大(因为Python循环在迭代次数非常大时变慢),这是预期的。但是,您能详细解释一下 mask = (x[np.newaxis,:]-cx)**2 + (y[:,np.newaxis]-cy)**2 < r**2 吗?我们为什么需要/使用 np.arange 作为 xy 的初始值?顺便说一句:利用 np.newaxis 这种方式来进行加法操作以获得一个二维数组的想法非常好。Translated: 干得好。我在电脑上测试了一下,发现你的方法比我的运行速度快了不到5倍。并且,针对更大的数组,优势会变得更明显(这是因为 Python 循环在迭代次数非常大时会变慢)。然而,您能详细解释一下 mask = (x[np.newaxis,:]-cx)**2 + (y[:,np.newaxis]-cy)**2 < r**2 吗?为什么我们需要/使用 np.arange 作为 xy 的起始值?还有,非常棒的 np.newaxis 使用方式,可以获得添加后的二维数组。 - daniel451
我需要生成两个坐标xy,才能计算圆。你可以使用任何函数来实现,arange只是我方便的选择。 - Chiel
@Chiel 你能解释一下123是什么吗? - undefined
只是一个随机值,用来设置掩码中的值。也可以是2384745 - undefined

-1

感谢Chiel的回答,但我在输出中看不到半径为5。(输出中直径为9而不是10)

可以从cx和cy中减去0.5以产生直径为10。

import numpy as np
import matplotlib.pyplot as plt

x = np.arange(0, 32)
y = np.arange(0, 32)
arr = np.zeros((y.size, x.size))

cx = 12.-.5
cy = 16.-.5
r = 5.

# The two lines below could be merged, but I stored the mask
# for code clarity.
mask = (x[np.newaxis,:]-cx)**2 + (y[:,np.newaxis]-cy)**2 < r**2
arr[mask] = 123.

# This plot shows that only within the circle the value is set to 123.
plt.figure(figsize=(6, 6))
plt.pcolormesh(x, y, arr)
plt.colorbar()
plt.show()

difference


这并没有回答问题。一旦您拥有足够的声望,您将能够评论任何帖子;相反,提供不需要询问者澄清的答案。- 来自审核 - Alexander

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接