【问题标题】:Slicing a box of certain width along arbitrary line through 3d array通过 3d 数组沿任意线切割一定宽度的盒子
【发布时间】:2018-01-01 16:30:18
【问题描述】:

我有一个大的 (600,600,600) numpy 数组,其中填充了我的数据。现在我想从中提取区域,在通过框的任意线周围具有给定宽度。

对于这条线,我在单独的 numpy 数组中拥有每个点的 x、y 和 z 坐标。所以假设这条线在数据框中有 35 个点,那么 x、y 和 z 数组的长度也都是 35。我可以通过使用这样的索引来提取沿线本身的点

extraction = data[z,y,x]

现在理想情况下,我想通过执行以下操作在其周围提取一个框

extraction = data[z-3:z+3,y-3:y+3,z-3:z+3]

但是因为 x、y 和 z 是数组,所以这是不可能的。我能想到的唯一方法是通过每个点的for循环,所以

extraction = np.array([])
for i in range(len(x)):
    extraction = np.append(extraction,data[z[i]-3:z[i]+3,y[i]-3:y[i]+3,z[i]-3:z[i]+3])

然后再对提取数组进行整形。但是,这非常慢,并且我想防止这个 for 循环中的每个切片之间存在一些重叠。

有没有一种简单的方法可以不使用 for 循环直接执行此操作?

编辑: 让我通过我想出的另一个想法来重新表述这个问题,这个想法也很慢。我有一条线穿过数据立方体。我有一个包含定义线的所有点的 x、y 和 z 坐标列表(坐标是数据立方体数组中的索引)。 例如,这些列表如下所示:

 x_line: [345 345 345 345 342 342 342 342 342 342 342 342 342 342 342 342]
 y_line: [540 540 540 543 543 543 543 546 546 546 549 549 549 549 552 552]
 z_line: [84 84 84 87 87 87 87 87 90 90 90 90 90 93 93 93]

如您所见,其中一些坐标是相同的,因为这些线是在不同的坐标中定义的,然后根据数据框的分辨率进行分箱。 现在我想屏蔽数据立方体中距离大于 3 个单元格的所有单元格。 对于沿线的单个点 (x_line[i], y_line[i], z_line[i]),这相对容易。我为数据立方体中的坐标创建了一个网格网格,然后创建了一个零掩码数组并将所有内容都满足条件为1:

data = np.random.rand(600,600,600)
x_box,y_box,z_box = np.meshgrid(n.arange(600),n.arange(600),n.arange(600))
mask = np.zeros(np.shape(data))

for i in range(len(x_line)):
    distance = np.sqrt((x_box-x_line[i])**2 + (y_box-y_line[i])**2 + (z_box-z_line[i])**2)
    mask[distance <= 3] = 1.

extraction = data[mask == 1.]

这样做的好处是掩码数组消除了重复提取的问题。但是,meshgrid 和距离计算都非常慢。那么是否可以直接在整条线上进行距离计算,而不必在每个线点上进行 for 循环,以便它直接掩盖距离任何线点 3 个单元格范围内的所有单元格?

【问题讨论】:

  • ... there will be some overlap between each of the slices in this for-loop I'd like to prevent。我们在谈论哪些重叠?
  • 例如,如果直线沿 z 轴方向行进,则点的间距将小于我在示例代码中使用的宽度为 6 的切片,因此 for 循环将包含某些沿 z 轴多次输入。解决这个问题的一种方法是先找出主轴,然后只沿其他两个轴切片,但我必须这样做很多次,所以有一种自动方式直接沿线切片会更方便.
  • 我建议添加一个最小的示例案例并向我们展示预期的输出并对其进行解释。
  • 我添加了一些具体的代码示例
  • 您是要遮盖一个 6x6x6 的立方体,还是一个半径为 3 的球体?您的两个示例选择了不同的选项

标签: python-2.7 numpy multidimensional-array slice


【解决方案1】:

这个怎么样?

# .shape = (N,)
x, y, z = ...

# offsets in [-3, 3), .shape = (6, 6, 6)
xo, yo, zo = np.indices((6, 6, 6)) - 3

# box indices, .shape = (6, 6, 6, N)
xb, yb, zb = x + xo[...,np.newaxis], y + yo[...,np.newaxis], z + zo[...,np.newaxis]

# .shape = (6, 6, 6, N)
extractions = data[xb, yb, zb]

这会提取一系列 6x6x6 的立方体,每个立方体都以 xyz 中的坐标为“中心”

这将产生重复的坐标,并在靠近边界的情况下失败

如果您将 xyz 保留在一个数组中,这会变得不那么冗长,并且您可以删除重复项:

# .shape = (N,3)
xyz = ...

# offsets in [-3, 3), .shape = (6, 6, 6, 3)
xyz_offset = np.moveaxis(np.indices((6, 6, 6)) - 3, 0, -1)

# box indices, .shape = (6, 6, 6, N, 3)
xyz_box = xyz + xyz_offset[...,np.newaxis,:]

if remove_duplicates:
    # shape (M, 3)
    xyz_box = xyz_box.reshape(-1, 3)
    xyz_box = np.unique(xyz_box, axis=0)

xb, yb, zb = xyz_box
extractions = data[xb, yb, zb]

【讨论】:

  • 感谢您的建议。由于我的 numpy 版本尚未将轴参数添加到 np.unique,我无法完全测试您的方法。不幸的是,我无法在需要运行此代码的机器上升级到 1.11.3 版以上的 numpy。我在原始问题中添加了更多信息,希望能更清楚地说明我的意思
  • @Mizuti:那你能处理重复吗?
  • 我需要确定所有蒙面单元格中的平均值等属性,因此存在重复是一个真正的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-29
  • 2013-06-25
  • 1970-01-01
  • 2019-09-18
  • 2015-04-24
  • 1970-01-01
相关资源
最近更新 更多