简体   繁体   English

2D 二进制数组中每个像素到最近 0 值的距离

[英]Distance to Nearest 0 Value for every pixel in 2D Binary Array

Given a 2D binary array (only 1s or 0s), for the pixels that have a value of 1, I want to find the distance from that pixel to the nearest 0-valued pixel, and replace the 1-valued pixel with that distance.给定一个二维二进制数组(只有 1 或 0),对于值为 1 的像素,我想找到从该像素到最近的 0 值像素的距离,并用该距离替换 1 值像素。 If you're familiar with the game Minesweeper, you can imagine that the 0-valued pixels are mines, and we want to assign proximity values to all other pixels.如果您熟悉扫雷游戏,您可以想象 0 值像素是地雷,我们希望将接近度值分配给所有其他像素。 Exact precision is not necessarily important;精确的精度不一定重要; Minesweeper will assign a pixel that is diagonal to a mine as valued as 1 (as opposed to sqrt(2)). Minesweeper 将分配一个与地雷对角线的像素,其值为 1(与 sqrt(2) 相反)。 So whatever is fastest/easiest.所以无论是最快/最简单的。 So for example:例如:

[[1, 1, 1, 1, 1],
 [1, 1, 1, 1, 1],
 [1, 1, 0, 1, 1],
 [1, 1, 1, 1, 1],
 [1, 1, 1, 1, 1],
 ]

would become:会成为:

[[2, 2, 2, 2, 2],
 [2, 1, 1, 1, 2],
 [2, 1, 0, 1, 2],
 [2, 1, 1, 1, 2],
 [2, 2, 2, 2, 2],
 ]

A naive way would be to get the 2D indices of all 0-valued pixels and 1-valued pixels, calculate the euclidean distance matrix between the two, find the minimum value for each 1-valued pixel, then assign those values to the corresponding indices.一种天真的方法是获取所有 0 值像素和 1 值像素的 2D 索引,计算两者之间的欧几里德距离矩阵,找到每个 1 值像素的最小值,然后将这些值分配给相应的索引.

import numpy as np
# example sample
maze = np.ones((100, 100))
maze[40:60, 40:60] = 0

# find indices
mask_z = maze == 0
idx_z = np.nonzero(mask_z)
idx_nz = np.nonzero(~mask_z)
idx_z = np.stack(idx_z, axis=-1)
idx_nz = np.stack(idx_nz, axis=-1)

# calculate distance matrix
dist_matrix = np.linalg.norm(idx_nz.reshape(-1, 1, 2) - idx_z, axis=-1)
dists = np.min(dist_matrix, axis=-1)

# assign distances
mapped = np.zeros(floorplan.shape[:2], dtype=int)
mapped[idx_nz] = dists.squeeze()

However, the issue is that for large matrices (2k by 2k) I run out of memory and speed is pretty poor.然而,问题是对于大型矩阵(2k x 2k)我用完了 memory 并且速度很差。 Is there a better way to do this?有一个更好的方法吗?

You can either use scipy's distance_transform_cdt or opencv's distanceTransform .您可以使用 scipy 的distance_transform_cdt或 opencv 的distanceTransform

A personal note, I just ran into a weird case where distanceTransform was buggy and had to use distance_transform_edt , so I'd recommend the latter.个人说明,我刚刚遇到了一个奇怪的情况,其中distanceTransform有问题并且不得不使用distance_transform_edt ,所以我推荐后者。

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

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