快速将标记图像转换为{label:[coordinates]}的字典

ben*_*ich 6 python numpy image-processing scipy

假设我用scipy.ndimage.measurements.label标记了一个图像,如下所示:

[[0, 1, 0, 0, 0, 0],
 [0, 1, 0, 0, 0, 0],
 [0, 1, 0, 0, 0, 0],
 [0, 0, 0, 0, 3, 0],
 [2, 2, 0, 0, 0, 0],
 [2, 2, 0, 0, 0, 0]]
Run Code Online (Sandbox Code Playgroud)

什么是收集属于每个标签的坐标的快速方法?就像这样:

{ 1: [[0, 1], [1, 1], [2, 1]],
  2: [[4, 0], [4, 1], [5, 0], [5, 1]],
  3: [[3, 4]] }
Run Code Online (Sandbox Code Playgroud)

我正在处理大小约为15,000 x 5000像素的图像,并且每个图像像素的大约一半被标记(即非零).

而不是迭代整个图像nditer,np.where(img == label)为每个标签做一些事情会更快吗?

编辑:

哪种算法最快取决于标记图像的大小与其所具有的标签数量相比.Warren Weckesser和Salvador Dali/BHAT IRSHAD的方法(基于np.nonzeronp.where)似乎都与标签的数量呈线性关系,而迭代通过每个图像元素,nditer显然与标记图像的大小成线性比例.

小测试的结果:

size: 1000 x 1000, num_labels: 10
weckesser ... 0.214357852936s 
dali ... 0.650229930878s 
nditer ... 6.53645992279s 


size: 1000 x 1000, num_labels: 100
weckesser ... 0.936990022659s 
dali ... 1.33582305908s 
nditer ... 6.81486487389s 


size: 1000 x 1000, num_labels: 1000
weckesser ... 8.43906402588s 
dali ... 9.81333303452s 
nditer ... 7.47897100449s 


size: 1000 x 1000, num_labels: 10000
weckesser ... 100.405524015s 
dali ... 118.17239809s 
nditer ... 9.14583897591s
Run Code Online (Sandbox Code Playgroud)

所以问题变得更加具体:

对于其中标签数量大小的标记图像,sqrt(size(image))是否存在一种收集标签坐标的算法,该算法比迭代每个图像元素(即具有nditer)更快?

Sal*_*ali 2

你可以做这样的事情(让img你原来的nd.array)

res = {}
for i in np.unique(img)[1:]:
  x, y = np.where(a == i)
  res[i] = zip(list(x), list(y))
Run Code Online (Sandbox Code Playgroud)

这会给你你想要的:

{
 1: [(0, 1), (1, 1), (2, 1)],
 2: [(4, 0), (4, 1), (5, 0), (5, 1)],
 3: [(3, 4)]
}
Run Code Online (Sandbox Code Playgroud)

是否会更快 - 由基准来确定。

根据沃伦的建议,我不需要使用 unique 并且可以这样做

res = {}
for i in range(1, num_labels + 1)
    x, y = np.where(a == i)
    res[i] = zip(list(x), list(y))
Run Code Online (Sandbox Code Playgroud)