简体   繁体   English

返回给定numpy数组的探照灯向量

[英]Return searchlight vectors for a given numpy array

Consider a 3D numpy array D of dimension, say, (30 x 40 x 50). 考虑一个尺寸为(30 x 40 x 50)的3D numpy数组D For each voxel D[x,y,z] I want to store a vector that contains neighboring voxels within a certain radius (including the D[x,y,z] itself). 对于每个体素D[x,y,z]我想存储一个向量,该向量包含特定半径内的相邻体素(包括D[x,y,z]本身)。

(As an example here is a picture of such a sphere of radius 2: https://puu.sh/wwIYW/e3bd63ceae.png ) (例如,下面是一个半径为2的球体的图片: https : //puu.sh/wwIYW/e3bd63ceae.png

Is there a simple and fast way to code this? 有没有简单快速的方法来编写此代码?

I have written a function for it, but it is painfully slow and IDLE eventually crashes because the data structure I store the vectors in becomes too large. 我已经为此编写了一个函数,但是它非常缓慢,并且IDLE最终崩溃,因为我将向量存储在其中的数据结构变得太大。

Current code: 当前代码:

def searchlight(M_in):
    radius = 4
    [m,n,k] = M_in.shape
    M_out = np.zeros([m,n,k],dtype=object)
    count = 0
    for i in range(m):
        for j in range(n):
            for z in range(k):
                i_interval = list(range((i-4),(i+5)))
                j_interval = list(range((j-4),(j+5)))
                z_interval = list(range((z-4),(z+5)))                
                coordinates = list(itertools.product(i_interval,j_interval,z_interval))
                coordinates = [pair for pair in coordinates if ((abs(pair[0]-i)+abs(pair[1]-j)+abs(pair[2]-z))<=radius)]
                coordinates = [pair for pair in coordinates if ((pair[0]>=0) and (pair[1]>=0) and pair[2]>=0) and (pair[0]<m) and (pair[1]<n) and (pair[2]<k)]
                out = []
                for pair in coordinates:
                    out.append(M_in[pair[0],pair[1],pair[2]])
                M_out[i,j,z] = out
                count = count +1
    return M_out

Since you say the data structure is too large, you'll likely have to compute the vector on the fly for a given voxel. 由于您说的数据结构太大,因此您可能必须为给定的体素动态计算向量。 You can do this pretty quickly though: 不过,您可以很快完成此操作:

class SearchLight(object):
    def __init__(self, M_in, radius):
        self.M_in = M_in
        m, n, k = self.M_in.shape

        # compute the sphere coordinates centered at (0,0,0)
        # just like in your sample code
        i_interval = list(range(-radius,radius+1))
        j_interval = list(range(-radius,radius+1))
        z_interval = list(range(-radius,radius+1))
        coordinates = list(itertools.product(i_interval,j_interval,z_interval))
        coordinates = [pair for pair in coordinates if ((abs(pair[0])+abs(pair[1])+abs(pair[2]))<=radius)]

        # store those indices as a template
        self.sphere_indices = np.array(coordinates)

    def get_vector(self, i, j, k):

        # offset sphere coordinates by the requested centre.
        coordinates = self.sphere_indices + [i,j,k]
        # filter out of bounds coordinates
        coordinates = coordinates[(coordinates >= 0).all(1)]
        coordinates = coordinates[(coordinates < self.M_in.shape).all(1)]

        # use those coordinates to index the initial array.
        return self.M_in[coordinates[:,0], coordinates[:,1], coordinates[:,2]]

To use the object on a given array you can simply do: 要在给定数组上使用对象,您可以简单地执行以下操作:

sl = SearchLight(M_in, 4)
# get vector of values for voxel i,j,k
vector = sl.get_vector(i,j,k)

This should give you the same vector you would get from 这应该给你相同的向量

M_out[i,j,k]

in your sample code, without storing all the results at once in memory. 在您的示例代码中,而无需一次将所有结果存储在内存中。

This can also probably be further optimized, particularly in terms of the coordinate filtering, but it may not be necessary. 这也可能可以进一步优化,特别是在坐标过滤方面,但是可能没有必要。 Hope that helps. 希望能有所帮助。

Here a way to do that. 这是一种方法。 For efficiency, you need therefore to use ndarrays : This only take in account complete voxels. 为了提高效率,因此需要使用ndarrays:仅考虑完整的体素。 Edges must be managed "by hand". 边缘必须“手动”管理。

from pylab import *
a=rand(100,100,100) # the data
r=4
ra=range(-r,r+1)

sphere=array([[x,y,z] for x in ra for y in ra for z in ra if np.abs((x,y,z)).sum()<=r]) 
# the unit "sphere"

indcenters=array(meshgrid(*(range(r,n-r) for n in a.shape),indexing='ij'))
# indexes of the centers of the voxels. edges are cut.

all_inds=(indcenters[newaxis].T+sphere.T).T
#all the indexes.

voxels=np.stack([a[tuple(inds)] for inds in all_inds],-1)
# the voxels.
#voxels.shape is (92, 92, 92, 129)

All the costly operations are vectorized. 所有昂贵的操作均已向量化。 Comprehension lists are prefered for clarity in external loop. 为了使外部循环更清晰,首选理解列表。

You can now perform vectorized operations on voxels. 现在,您可以在体素上执行矢量化操作。 for exemple the brightest voxel : 例如最亮的体素:

light=voxels.sum(-1)
print(np.unravel_index(light.argmax(),light.shape))
#(33,72,64)

All of this is of course extensive in memory. 所有这些当然在内存中是广泛的。 you must split your space for big data or voxels. 您必须为大数据或体素分配空间。

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

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