创建一个二维Numpy数组,距离中心的欧几里德距离

时间:2014-09-25 08:14:52

标签: python arrays numpy scipy euclidean-distance

我正在尝试在Scipy / Numpy中创建一个二维数组,其中每个值代表距离中心的欧氏距离。它应该具有与三维数组的前两个维度相同的形状(图像,通过 scipy.misc.fromimage 创建)。

这是一种有效的方法:

def get_distance_1(y, x):
    mid_x, mid_y = (scipy.array(image_array.shape[:2]) - 1) / float(2)
    return ((y - mid_y) ** 2 + (x - mid_x) ** 2) ** 0.5

distances = scipy.fromfunction(get_distance_1, image_array.shape[:2])

这种方法相当快,但我对Scipy很新,并且想知道是否有一种更优雅,惯用的方法来做同样的事情。我找到了 scipy.spatial.distance.cdist 函数,这似乎很有希望,但我对如何使它适应这个问题感到茫然。

def get_distance_2(y, x):
    mid = ...  # needs to be a array of the shape (rows, cols, 2)?
    return scipy.spatial.distance.cdist(scipy.dstack((y, x)), mid)

只是为了澄清,我正在寻找的是这样的(对于6 x 6阵列)

[[ 3.53553391  2.91547595  2.54950976  2.54950976  2.91547595  3.53553391]
 [ 2.91547595  2.12132034  1.58113883  1.58113883  2.12132034  2.91547595]
 [ 2.54950976  1.58113883  0.70710678  0.70710678  1.58113883  2.54950976]
 [ 2.54950976  1.58113883  0.70710678  0.70710678  1.58113883  2.54950976]
 [ 2.91547595  2.12132034  1.58113883  1.58113883  2.12132034  2.91547595]
 [ 3.53553391  2.91547595  2.54950976  2.54950976  2.91547595  3.53553391]]

2 个答案:

答案 0 :(得分:2)

我会说惯用的方法是对它进行矢量化。

原始函数get_distance_1可能设计时考虑了标量参数(单个数字),但实际上也适用于Numpy数组,无需修改。这意味着您可以使用x和y索引传递数组,它将提供所需的结果。

import numpy as np

m, n = image_array.shape[:2]
x_inds = np.arange(m)
y_inds = np.arange(n)

distances = get_distance_1(x_inds[:,None], y_inds)

使用None建立索引(相当于使用np.newaxis建立索引)将轴添加到一维向量并有效地转置它。这是参与broadcasting的必要条件。

稍微短一些:

x_inds, y_inds = np.ogrid[:m, :n]

distances = get_distance_1(x_inds, y_inds)

请注意,您必须撤消xyget_distance_1的定义,才能获得与中心相关的距离:

def get_distance_1(x, y):
    mid_x, mid_y = (scipy.array(image_array.shape[:2]) - 1) / float(2)
    return ((y - mid_y) ** 2 + (x - mid_x) ** 2) ** 0.5

答案 1 :(得分:1)

cdist是正确的功能。给定两组积分XY,它会为x和{{1}中的所有y返回xX之间的距离在y中。在这种情况下,其中一组是单身:

Y

这是一个二维数组,因此您可能希望>>> X = np.random.randn(10, 3) # random 3-d points >>> center = np.random.randn(3) >>> scipy.spatial.distance.cdist(X, np.atleast_2d(center)) # both must be 2-d array([[ 2.72130005], [ 1.62765189], [ 1.14245608], [ 2.55279445], [ 2.43727709], [ 3.20647709], [ 1.65028127], [ 0.79044422], [ 1.8180881 ], [ 2.38094952]])

ravel