说我用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]]
收集属于每个标签的坐标的快速方法是什么?即类似的东西:
{ 1: [[0, 1], [1, 1], [2, 1]],
2: [[4, 0], [4, 1], [5, 0], [5, 1]],
3: [[3, 4]] }
我正在处理大小约为15,000 x 5000像素的图像,并且每个图像的大约一半像素都被标记(即非零)。
不是使用nditer
遍历整个图像,而是为每个标签执行np.where(img == label)
之类的操作会更快吗?
编辑:
哪种算法最快取决于标记图像与标记图像的数量相比有多大。 Warren Weckesser和Salvador Dali / BHAT IRSHAD的方法(基于np.nonzero
和np.where
)似乎都与标签的数量成线性比例,而用{{迭代每个图像元素1}}显然与标记图像的大小成线性比例。
小测试的结果:
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
的标签图像,有一种算法来收集标签坐标,这比迭代每个图像元素(即使用sqrt(size(image))
)更快? / p>
答案 0 :(得分:4)
这是一种可能性:
get_label_indices.py
我调用了这个脚本In [97]: import pprint
In [98]: run get_label_indices.py
In [99]: pprint.pprint(res)
{1: array([[0, 1],
[1, 1],
[2, 1]]),
2: array([[4, 0],
[4, 1],
[5, 0],
[5, 1]]),
3: array([[3, 4]])}
。这是一个示例运行:
alldata.txt
答案 1 :(得分:1)
你可以做这样的事情(让img
是你原来的nd.array)
res = {}
for i in np.unique(img)[1:]:
x, y = np.where(a == i)
res[i] = zip(list(x), list(y))
会给你你想要的东西:
{
1: [(0, 1), (1, 1), (2, 1)],
2: [(4, 0), (4, 1), (5, 0), (5, 1)],
3: [(3, 4)]
}
是否会更快 - 取决于基准确定。
根据Warren的建议,我不需要使用独特的,只能做
res = {}
for i in range(1, num_labels + 1)
x, y = np.where(a == i)
res[i] = zip(list(x), list(y))
答案 2 :(得分:0)
试试这个:
>>> z
array([[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]])
>>> {i:zip(*np.where(z==i)) for i in np.unique(z) if i}
{1: [(0, 1), (1, 1), (2, 1)], 2: [(4, 0), (4, 1), (5, 0), (5, 1)], 3: [(3, 4)]}
答案 3 :(得分:0)
这基本上是一个argsort
操作,还有一些额外的工作来获得所需的格式:
def sorting_based(img, nlabels):
img_flat = img.ravel()
label_counts = np.bincount(img_flat)
lin_idx = np.argsort(img_flat)[label_counts[0]:]
coor = np.column_stack(np.unravel_index(lin_idx, img.shape))
ptr = np.cumsum(label_counts[1:-1])
out = dict(enumerate(np.split(coor, ptr), start=1))
return out
正如您所发现的,对每个标签执行np.where(img == label)
会产生二次运行时O(m*n)
,m=n_pixels
和n=n_labels
。基于排序的方法将复杂性降低到O(m*log(m) + n)
。
可以在线性时间内执行此操作,但我不认为可以使用Numpy进行矢量化。你可以滥用类似于this answer的scipy.sparse.csr_matrix
,但此时你可能最好还是编写真正有意义的代码,在Numba,Cython等中。