简单而暴力的方法就是使用numpy.where。
例如,如果您只想要边界框:
import numpy as np
x = np.array([[1,1,2,2],
[1,1,2,2],
[3,3,4,4],
[3,3,4,4]])
for val in np.unique(x):
rows, cols = np.where(x == val)
rowstart, rowstop = np.min(rows), np.max(rows)
colstart, colstop = np.min(cols), np.max(cols)
print val, (rowstart, colstart), (rowstop, colstop)
这也适用于带有零的示例。
如果数组很大,并且您已经有scipy,您可以考虑使用scipy.ndimage.find_objects,正如@unutbu 建议的那样。
在您的示例的特定情况下,您的唯一值是连续整数,您可以直接使用find_objects。它需要一个数组,其中每个非 0 的连续整数代表一个需要返回其边界框的对象。 (完全按照您的意愿忽略 0。)但是,通常,您需要进行一些预处理以将任意唯一值转换为连续整数。
find_objects 返回slice 对象的元组列表。老实说,如果您想要边界框,这些可能正是您想要的。但是,打印出开始和停止标记看起来会有点混乱。
import numpy as np
import scipy.ndimage as ndimage
x = np.array([[1, 0, 1, 2, 2],
[1, 0, 1, 2, 2],
[3, 0, 3, 4, 4],
[3, 0, 3, 4, 4]])
for i, item in enumerate(ndimage.find_objects(x), start=1):
print i, item
这看起来与您预期的略有不同。这些是slice 对象,因此“max”值将始终比前面示例中的“max”值高一个。这样您就可以简单地使用给定的元组进行切片以获取相关数据。
例如
for i, item in enumerate(ndimage.find_objects(x), start=1):
print i, ':'
print x[item], '\n'
如果您真的想要开始和停止,只需执行以下操作:
for i, (rowslice, colslice) in enumerate(ndimage.find_objects(x), start=1):
print i,
print (rowslice.start, rowslice.stop - 1),
print (colslice.start, colslice.stop - 1)
如果您的唯一值不是连续整数,您需要进行一些预处理,正如我之前提到的。你可以这样做:
import numpy as np
import scipy.ndimage as ndimage
x = np.array([[1.1, 0.0, 1.1, 0.9, 0.9],
[1.1, 0.0, 1.1, 0.9, 0.9],
[3.3, 0.0, 3.3, 4.4, 4.4],
[3.3, 0.0, 3.3, 4.4, 4.4]])
ignored_val = 0.0
labels = np.zeros(data.shape, dtype=np.int)
i = 1
for val in np.unique(x):
if val != ignored_val:
labels[x == val] = i
i += 1
# Now we can use the "labels" array as input to find_objects
for i, item in enumerate(ndimage.find_objects(labels), start=1):
print i, ':'
print x[item], '\n'