Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/302.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 查找地图中每个像素的最近邻居_Python_Opencv_Image Processing_Computer Vision_Nearest Neighbor - Fatal编程技术网

Python 查找地图中每个像素的最近邻居

Python 查找地图中每个像素的最近邻居,python,opencv,image-processing,computer-vision,nearest-neighbor,Python,Opencv,Image Processing,Computer Vision,Nearest Neighbor,我试图在python中找到一个简单的方法,在这个方法中,对于2dim掩码中的每个像素,我可以得到最近的非零邻居的索引。在Matlab中,有一个bwdist,它返回的正是这个值。 例如:如果我的输入是: array [[0 0 0 0 0 0 0] [0 1 0 0 0 0 0] [0 0 0 0 0 1 0] [0 0 0 0 0 0 0]] 我的输出应该是: array [[(1,1) (1,1) (1,1) (1,1) (2,5) (2,5) (2

我试图在python中找到一个简单的方法,在这个方法中,对于2dim掩码中的每个像素,我可以得到最近的非零邻居的索引。在Matlab中,有一个bwdist,它返回的正是这个值。 例如:如果我的输入是:

array [[0 0 0 0 0 0 0]
       [0 1 0 0 0 0 0]
       [0 0 0 0 0 1 0]
       [0 0 0 0 0 0 0]]
我的输出应该是:

array [[(1,1) (1,1) (1,1) (1,1) (2,5) (2,5) (2,5)]
       [(1,1) (1,1) (1,1) (1,1) (2,5) (2,5) (2,5)]
       [(1,1) (1,1) (1,1) (2,5) (2,5) (2,5) (2,5)]
       [(1,1) (1,1) (1,1) (2,5) (2,5) (2,5) (2,5)]]
该函数还可以像Matlab中的bwdist一样返回绝对索引(对于1dim数组)

谢谢

编辑:到目前为止,我已经尝试了一些与scipy相关的潜在解决方案,如distance_transform_edt,但它只查找到最近像素的距离,而不是像素本身。 如果相关的话,我还在代码的其他地方使用OpenCV和VLfeat

从文档中: OpenCV有
distanceTransform()
distanceTransformWithLabels()
函数,它们的工作方式类似,但与此Matlab函数有一些不同。从:

D=bwdist(BW)
计算二值图像BW的欧几里德距离变换。对于
BW
中的每个像素,距离变换指定一个数字,该数字是该像素与
BW
的最近非零像素之间的距离

将此与以下内容进行比较:

计算源图像每个像素到最近零像素的距离

因此,Matlab给出了到最近非零像素的距离,而OpenCV给出了到最近零像素的距离。因此,您需要反转OpenCV的图像。此外,带有标签的Matlab可选输出给出了与最近像素对应的线性索引:

[D,idx]=bwdist(BW)
还以索引数组的形式计算最近的像素贴图,
idx
。idx的每个元素都包含
BW
的最近非零像素的线性索引。最近的像素贴图也称为特征贴图、特征变换或最近邻变换

使用OpenCV,获取输出的标签既不是图像的坐标,也不是索引。相反,它只是一个数字标签,类似于连接的组件标签,与像素位置/索引完全无关

该函数的这种变体不仅计算每个像素(x,y)的最小距离,而且还识别由零像素(
labelType==DIST\u LABEL\u CCOMP
)或最近的零像素(
labelType==DIST\u LABEL\u pixel
)组成的最近连接组件

这意味着您必须使用这个带标签的图像来屏蔽您的输入,并找到对应于该标签的像素(据我所知,这至少是最好的方法)

解决方案: 所以,我们来看看如何得到我们想要的地方,让我们来看看这个函数在哪里得到的(用倒置的图像作为输入之前):< /P> 好吧,如果我们只是循环标签中的唯一值,为每个标签创建一个遮罩,遮罩原始图像…然后找到标签区域内的白色像素,我们将得到索引:

In [146]: for l in np.unique(labels):
     ...:     mask = label == l
     ...:     i = np.where(img * mask)
     ...:     print(i)
     ...:
(array([1]), array([1]))
(array([2]), array([5]))
这不是您要求的确切输出,但它是一个索引列表,并且您有标签。所以现在我们只需要绘制这些。我要做的是创建一个空的双通道矩阵来保存索引值,然后根据标签中的掩码填充它:

In [177]: index_img = np.zeros((*img.shape, 2), dtype=np.intp)

In [178]: for l in np.unique(labels):
     ...:     mask = label == l
     ...:     index_img[mask] = np.dstack(np.where(img * mask))
这是一个双通道阵列,包含你想要的信息。结构稍有不同(每个条目不使用元组),但它通常是其他OpenCV函数(双通道数组)所需的结构:

把它们放在一起 这里有一个函数可以实现这一点,它可以选择输出这个双通道输出,或者像Matlab那样输出线性输出:

def bwdist(img, metric=cv2.DIST_L2, dist_mask=cv2.DIST_MASK_5, label_type=cv2.DIST_LABEL_CCOMP, ravel=True):
    """Mimics Matlab's bwdist function.

    Available metrics:
        https://docs.opencv.org/3.4/d7/d1b/group__imgproc__misc.html#gaa2bfbebbc5c320526897996aafa1d8eb
    Available distance masks:
        https://docs.opencv.org/3.4/d7/d1b/group__imgproc__misc.html#gaaa68392323ccf7fad87570e41259b497
    Available label types:
        https://docs.opencv.org/3.4/d7/d1b/group__imgproc__misc.html#ga3fe343d63844c40318ee627bd1c1c42f
    """
    flip = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY_INV)[1]
    dist, labeled = cv2.distanceTransformWithLabels(flip, metric, dist_mask)

    # return linear indices if ravel == True (default)
    if ravel:  
        idx = np.zeros(img.shape, dtype=np.intp)  # np.intp type is for indices
        for l in np.unique(labeled):
            mask = labeled == l
            idx[mask] = np.flatnonzero(img * mask)
        return dist, idx

    # return two-channel indices if ravel == False
    idx = np.zeros((*img.shape, 2), dtype=np.intp)  
    for l in np.unique(labeled):
        mask = labeled == l
        idx[mask] = np.dstack(np.where(img * mask))
    return dist, idx
通过Matlab在文档中给出的示例:

In [241]: bw = np.zeros((5, 5), dtype=np.uint8)
     ...: bw[1, 1] = 1
     ...: bw[3, 3] = 1
     ...: print(bw)
     ...:
[[0 0 0 0 0]
 [0 1 0 0 0]
 [0 0 0 0 0]
 [0 0 0 1 0]
 [0 0 0 0 0]]

In [244]: d, idx = bwdist(bw)

In [245]: print(d)
[[1.3999939 1.        1.3999939 2.1968994 3.1968994]
 [1.        0.        1.        2.        2.1968994]
 [1.3999939 1.        1.3999939 1.        1.3999939]
 [2.1968994 2.        1.        0.        1.       ]
 [3.1968994 2.1968994 1.3999939 1.        1.3999939]]

In [246]: print(idx)
[[ 6  6  6  6 18]
 [ 6  6  6  6 18]
 [ 6  6  6 18 18]
 [ 6  6 18 18 18]
 [ 6 18 18 18 18]]

使用scipy时,这实际上是一个单行程序

如果您的输入矩阵是mat,则最接近的非零值的坐标如下所示:

import scipy.ndimage

nearest_neighbor = scipy.ndimage.morphology.distance_transform_edt(
    mat==0, return_distances=False, return_indices=True)
对于问题中给出的矩阵,这将生成以下索引矩阵,这是正确答案:

[[[1 1 1 1 2 2 2]
  [1 1 1 1 2 2 2]
  [1 1 1 2 2 2 2]
  [1 1 1 2 2 2 2]]

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

“你使用的是OpenCV还是scikit图像?”AlexanderReynolds是的,我编辑过。这是一个与我用OpenCVPerfect处理的图像相关的numpy掩码!我将添加OpenCV作为标签,并很快写出答案。您帮了我很多,我非常感谢。谢谢!:)@不用担心,这是一个有趣的问题。总是乐于帮助人们从Matlab过渡到Python!
import scipy.ndimage

nearest_neighbor = scipy.ndimage.morphology.distance_transform_edt(
    mat==0, return_distances=False, return_indices=True)
[[[1 1 1 1 2 2 2]
  [1 1 1 1 2 2 2]
  [1 1 1 2 2 2 2]
  [1 1 1 2 2 2 2]]

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