如何在ndarray python中创建球体?

时间:2018-11-15 19:21:37

标签: python numpy

我的ndarray大小为32x32x32。我想在阵列内部创建一个球体,其中心为(x,y),半径为4像素。 sphere的值为1,而array的值为0。如何在python中做呢?非常感谢

这是生成数组的代码

import numpy as np
A = np.zeros((32,32,32))
print (A)

5 个答案:

答案 0 :(得分:3)

很好的问题。您可以尝试以下代码。在下面提到的代码AA中,您需要使用矩阵。 =)

import numpy as np
from copy import deepcopy

''' size : size of original 3D numpy matrix A.
    radius : radius of circle inside A which will be filled with ones. 
'''
size, radius = 5, 2

''' A : numpy.ndarray of shape size*size*size. '''
A = np.zeros((size,size, size)) 

''' AA : copy of A (you don't want the original copy of A to be overwritten.) '''
AA = deepcopy(A) 

''' (x0, y0, z0) : coordinates of center of circle inside A. '''
x0, y0, z0 = int(np.floor(A.shape[0]/2)), \
        int(np.floor(A.shape[1]/2)), int(np.floor(A.shape[2]/2))


for x in range(x0-radius, x0+radius+1):
    for y in range(y0-radius, y0+radius+1):
        for z in range(z0-radius, z0+radius+1):
            ''' deb: measures how far a coordinate in A is far from the center. 
                    deb>=0: inside the sphere.
                    deb<0: outside the sphere.'''   
            deb = radius - abs(x0-x) - abs(y0-y) - abs(z0-z) 
            if (deb)>=0: AA[x,y,z] = 1

以下是size=5radius=2(形状为2的numpy数组内半径为5*5*5像素的球体)的输出示例:

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

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

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

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

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

我没有按照您要求的大小和半径(size=32radius=4)打印输出,因为输出会很长。

答案 1 :(得分:3)

由于数组索引仅具有一定程度的特异性(即,您只能细分为宽度,在这种情况下为32),因此没有一种完美的方法来表示数组中的球体。相反,我们可以将每个数组索引视为立方区域的空间,其中索引的[x][y][z]索引表示立方区域的中心坐标。要创建球体,我们将评估该球体在该空间区域中的存在是否满足某些条件。

我们从球体方程开始。来自Wikipedia

  

在解析几何中,具有中心( x0 y0 z0 )和半径 r 的球面为所有点( x y z )的轨迹,使得

     

x - x0 )^ 2 +( y - y0 )^ 2 +( z - z0 )^ 2 <= r ^ 2。

对于尺寸为N的数组,中心将具有所有尺寸的坐标(N-1)/ 2。 (因为对于偶数尺寸,中心应该在两个中心点之间,对于奇数尺寸,中心应该是整数。)半径的大小可以根据您确定边界的位置而变化。相对于我们想象的三次阵列表示形式的球体;重新阅读问题,我注意到您已经给出了所需的半径:4。

我可以想到两个评估标准:

简单方法

在这种方法中,我们将简单地使用一个检验数组索引的立方区域中心是否位于圆方程中。

使用这种方法,您可以看到Siddharth Satpathy's answer的一些代码。

复杂的方法

对我来说,理想的情况是,该方程将通过评估该立方区域的球体比例是否大于50%来确定指标是否在球体内。但是,不幸的是,这种方法超出了我目前的数学知识。


关于我在评论中进行的讨论,两种方法都不比另一种更好,因为它们代表了不同的观点:我个人认为数组实际上代表每个索引的立方面积,而其他人可能认为索引是这些立方区域的中心点。

答案 2 :(得分:1)

事件虽然有点晚-我最近也遇到了同样的问题,并像Mstaino所设想的解决方案一样解决了它。此外,Mstainos解决方案不适用于大小不等的数组,因为在计算距离时形状将不匹配。

所以这是我在3D中的方法,它在阵列的中心产生一个球体。 :

# define array size and sphere radius
size = [size_x, size_y, size_z]
radius = sphere_radius

# compute center index of array
center = [int(size[0]/2), int(size[1]/2), int(size[2]/2)]

# create index grid for array
ind_0, ind_1, ind_2 = np.indices((size[0], size[1], size[2]))

# calculate "distance" of indices to center index
distance = ((ind_0 - center[0])**2 + (ind_1 - center[1])**2 + (ind_2 - center[2])**2)**.5

# create output
output = np.ones(shape = (size[0], size[1], size[2])) * (distance <= radius)

答案 3 :(得分:0)

结合使用索引,距离计算和遮罩(全部使用numpy):

import numpy as np
center = (31/2, 31/2, 31/2)  # if it is centered
size = (32, 32, 32)
max_dist = 4
distance = np.linalg.norm(np.subtract(np.indices(size).T, np.asarray(center)), axis=2)
#print(distance)
mask = np.ones(size) * (distance < max_dist)
print(mask)

np.indices创建一个[[[(i, j, k)]]]形式的索引,np.substract计算到您中心的向量差,np.linalg.norm计算向量范数。其余的只是对距离数组使用掩码操作。

行得通吗?

编辑:为清晰起见,带有(3,3,3)的示例

center = (1, 1, 1)
size = (3, 3, 3)
distance = np.linalg.norm(np.subtract(np.indices(size).T,np.asarray(center)), axis=len(center))
mask = np.ones(size) * (distance<=1)
print(mask)

>>[[[0. 0. 0.]
  [0. 1. 0.]
  [0. 0. 0.]]

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

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

答案 4 :(得分:0)

以上都不适合我,所以有我的尝试:

def create_bin_sphere(arr_size, center, r):
    coords = np.ogrid[:arr_size[0], :arr_size[1], :arr_size[2]]
    distance = np.sqrt((coords[0] - center[0])**2 + (coords[1]-center[1])**2 + (coords[2]-center[2])**2) 
    return 1*(distance <= r)

其中:

  • arr_size是具有numpy数组形状的元组
  • center是具有球心坐标的元组
  • r是球体的半径

示例:

arr_size = (30,30,30)
sphere_center = (15,15,15)
r=10
sphere = create_bin_sphere(arr_size,sphere_center, r)

#Plot the result
fig =plt.figure(figsize=(6,6))
ax = fig.gca(projection='3d')
ax.voxels(sphere, facecolors=colors, edgecolor='k')
plt.show()

Vizualization rezult