简体   繁体   English

在 3D numpy 数组中绘制和/或获取 2D 平面的索引

[英]Draw and/or get indices for a 2D plane in a 3D numpy array

I have a 3D numpy array, eg of shape (200,200,200) .我有一个 3D numpy 数组,例如形状(200,200,200)

I also have a 2D plane, which I can express either in the form ax + by + cz + d = 0 or a (x,y,z) point and a direction vector in terms of the three x,y,z axes.我还有一个 2D 平面,我可以用ax + by + cz + d = 0(x,y,z)点和三个x,y,z轴的方向向量的形式表示。

I want to "plot" this plane on the 3D numpy array, by essentially changing the value of all points that lie on this plane to a constant value.我想在 3D numpy 数组上“绘制”这个平面,方法是将位于这个平面上的所有点的值更改为一个常数值。

Like this, but with only a single colour:像这样,但只有一种颜色:

在此处输入图片说明

The most versatile solution to this (I think) is to get all the integer indices of points that lie along this line.对此(我认为)最通用的解决方案是获取沿这条线的所有点的整数索引。 I can then just use this to index the numpy array.然后我可以使用它来索引 numpy 数组。 However, if a library offered the ability to plot a plane directly, without providing the indices, then this would be fine.然而,如果一个库提供了直接绘制平面的能力,而不提供索引,那么这会很好。

I have seen problems on this site that seem superficially similar to my problem, such as approaches of finding the values that lie along an x,y,z vector using scipy.ndimage.map_coordinates , but of course I am dealing with a plane not a line (also this just returned the values, not the indices).我在这个网站上看到过一些表面上与我的问题相似的问题,例如使用scipy.ndimage.map_coordinates找到沿x,y,z向量的值的方法,但当然我正在处理一个平面而不是一个行(这也只是返回值,而不是索引)。

Another approach I considered, but seems difficult (and maybe slow) is something similar to this question where the reply shows how to draw a 2D triangle in a 3D space.我考虑过的另一种方法,但似乎很难(而且可能很慢)类似于这个问题,其中回复显示了如何在 3D 空间中绘制 2D 三角形。 I could instead draw a square in 3D space, but this shows that filling this square is not trivial, and also the square will only fill the entire plane if at least one axis is parallel to x, y or z (or a "corner" will remain unfilled).我可以改为在 3D 空间中绘制一个正方形,但这表明填充这个正方形并非微不足道,而且如果至少有一个轴平行于 x、y 或 z(或“角”),则正方形只会填充整个平面将保持未填充)。

Has anyone got any idea how I might achieve this?有没有人知道我如何实现这一目标?

If the plane is near horizontal, you can give values to x and y and calculate z:如果平面接近水平,您可以为 x 和 y 赋值并计算 z:

a, b, c, d = 1, 2, 3, -600                     # Plane parameters
v = np.arange(200)
x, y = np.meshgrid(v, v)                       # All xy combinations
z = np.rint((a*x + b*y + d) / -c).astype(int)  # Rounded
plane_voxels = np.dstack([x,y,z]).reshape(-1,3)
print(plane_voxels)

Results in:结果是:

[[  0   0 200]
 [  1   0 200]
 [  2   0 199]
 ...
 [197 199   2]
 [198 199   1]
 [199 199   1]]

For the general case you need to find the dimension with less variability, that will be the calculated variable, and give values to the other two:对于一般情况,您需要找到可变性较小的维度,这将是计算变量,并为其他两个提供值:

a, b, c, d = 1, 2, 3, -600
v = np.arange(200)
dim = np.argmax(np.abs((a, b, c)))
if dim == 0:
    y, z = np.meshgrid(v, v)
    x = np.rint((b*y + c*z + d) / -a).astype(int)
elif dim == 1:
    x, z = np.meshgrid(v, v)
    y = np.rint((a*x + c*z + d) / -b).astype(int)
elif dim == 2:
    x, y = np.meshgrid(v, v)
    z = np.rint((a*x + b*y + d) / -c).astype(int)
plane_voxels = np.dstack([x,y,z]).reshape(-1,3)

Here is an idea.这是一个想法。 First let's say you have a (3,3,3) of one.首先假设你有一个(3,3,3) Then define your function of the plane equal to 0. create your coordinates with meshgrid and use it in your plane function.然后定义等于 0 的平面函数。使用meshgrid创建坐标并在平面函数中使用它。 Finally in case you want some tolerance, use isclose to 0 as a mask of your array to change the values最后,如果您想要一些容差,请使用isclose to 0 作为数组的掩码来更改值

n = 3 # change to 200 for your real case or arr.shape[0]

# just for the example
arr =  np.ones([n]*3)

# plane function = 0
f = lambda x,y,z: 2*x + 3*y**2 + 4*z - 3

# create the mask
mask = np.isclose(f(*np.meshgrid(*[np.arange(n)]*3)), 
                  0, # because your plane function is equal to 0
                  atol=1) # this is if you want some tolerance to catch nearby points

# change the value to whatever
arr[mask] = 5

print(arr)
[[[1. 5. 1.]
  [5. 1. 1.]
  [5. 1. 1.]]

 [[5. 1. 1.]
  [1. 1. 1.]
  [1. 1. 1.]]

 [[1. 1. 1.]
  [1. 1. 1.]
  [1. 1. 1.]]]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM