[英]Find consecutive unmasked values
我有一个很大的3维(时间,经度,纬度)输入数组。 大多数条目被屏蔽。 我需要找到那些掩码为False的条目的时间长于特定数量的连续时间步长(在此将其称为threshold
)。 结果应该是与输入蒙版具有相同形状的蒙版。
这是一些伪代码,希望可以使我的意思更清楚:
new_mask = find_consecutive(mask, threshold=3)
mask[:, i_lon, i_lat]
# [1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0]
new_mask[:, i_lon, i_lat]
# [1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1]
编辑:
我不确定到目前为止我的方法是否有意义。 它在性能方面做得很好,并为我提供了一个带标签的数组以及有关我想要哪些标签的知识。 我只是想不出一种将labels
再次转换为蒙版的有效方法。
from scipy.ndimage import measurements
structure = np.zeros((3, 3, 3))
structure[:, 1, 1] = 1
labels, nr_labels = measurements.label(1 - mask, structure=structure)
_, counts = np.unique(labels, return_counts=True)
labels_selected = [i_count for i_count, count in enumerate(counts)
if count >= threshold]
这是binary closing operation in image-processing
中binary closing operation in image-processing
的经典情况。 为了解决这个问题,您可以从scipy模块寻求帮助,特别scipy.ndimage.morphology.binary_closing
在我们喂入了所有ONES
和长度threshold
的适当一维内核后, scipy.ndimage.morphology.binary_closing
。 同样,Scipy的binary closing
功能仅给我们提供了关闭的遮罩。 因此,要获得所需的输出,我们需要将其与输入掩码进行“ OR
。 因此,实现看起来像这样-
from scipy.ndimage import binary_closing
out = mask | binary_closing(mask, structure=np.ones(threshold))
NumPy版本的二进制关闭怎么样?
现在,关闭操作基本上是image-dilation
和image-erosion
,因此我们可以使用可信赖的卷积操作来模拟该行为,并且在NumPy中确实将其作为np.convolve
。 与scipy的二进制关闭操作类似,我们在这里也需要相同的内核,并且将其用于扩张和腐蚀。 实施将是-
def numpy_binary_closing(mask,threshold):
# Define kernel
K = np.ones(threshold)
# Perform dilation and threshold at 1
dil = np.convolve(mask,K,mode='same')>=1
# Perform erosion on the dilated mask array and threshold at given threshold
dil_erd = np.convolve(dil,K,mode='same')>= threshold
return dil_erd
样品运行-
In [133]: mask
Out[133]:
array([ True, False, False, False, False, True, True, False, False,
True, False], dtype=bool)
In [134]: threshold = 3
In [135]: binary_closing(mask, structure=np.ones(threshold))
Out[135]:
array([False, False, False, False, False, True, True, True, True,
True, False], dtype=bool)
In [136]: numpy_binary_closing(mask,threshold)
Out[136]:
array([False, False, False, False, False, True, True, True, True,
True, False], dtype=bool)
In [137]: mask | binary_closing(mask, structure=np.ones(threshold))
Out[137]:
array([ True, False, False, False, False, True, True, True, True,
True, False], dtype=bool)
In [138]: mask| numpy_binary_closing(mask,threshold)
Out[138]:
array([ True, False, False, False, False, True, True, True, True,
True, False], dtype=bool)
运行时测试(Scipy与Numpy!)
案例1:均匀稀疏
In [163]: mask = np.random.rand(10000) > 0.5
In [164]: threshold = 3
In [165]: %timeit binary_closing(mask, structure=np.ones(threshold))
1000 loops, best of 3: 582 µs per loop
In [166]: %timeit numpy_binary_closing(mask,threshold)
10000 loops, best of 3: 178 µs per loop
In [167]: out1 = binary_closing(mask, structure=np.ones(threshold))
In [168]: out2 = numpy_binary_closing(mask,threshold)
In [169]: np.allclose(out1,out2) # Verify outputs
Out[169]: True
情况2:稀疏且阈值更大
In [176]: mask = np.random.rand(10000) > 0.8
In [177]: threshold = 11
In [178]: %timeit binary_closing(mask, structure=np.ones(threshold))
1000 loops, best of 3: 823 µs per loop
In [179]: %timeit numpy_binary_closing(mask,threshold)
1000 loops, best of 3: 331 µs per loop
In [180]: out1 = binary_closing(mask, structure=np.ones(threshold))
In [181]: out2 = numpy_binary_closing(mask,threshold)
In [182]: np.allclose(out1,out2) # Verify outputs
Out[182]: True
胜利者是个Numpy
!
边界条件
似乎边界也需要关闭,如果1s
距离生境足够近的话。 要解决这些情况,可以在输入布尔数组的开头和结尾分别填充一个1
,使用发布的代码,然后在末尾取消选择第一个和最后一个元素。 因此,使用scipy的binary_closing方法的完整实现将是-
mask_ext = np.pad(mask,1,'constant',constant_values=(1))
out = mask_ext | binary_closing(mask_ext, structure=np.ones(threshold))
out = out[1:-1]
样品运行-
In [369]: mask
Out[369]:
array([False, False, True, False, False, False, False, True, True,
False, False, True, False], dtype=bool)
In [370]: threshold = 3
In [371]: mask_ext = np.pad(mask,1,'constant',constant_values=(1))
...: out = mask_ext | binary_closing(mask_ext, structure=np.ones(threshold))
...: out = out[1:-1]
...:
In [372]: out
Out[372]:
array([ True, True, True, False, False, False, False, True, True,
True, True, True, True], dtype=bool)
只是为了完整起见,这里还是我在EDIT中概述的方法的解决方案。 在性能上,它确实比Divakars两种解决方案都要差(与numpy_binary_closing相比,大约是系数10),但允许处理3D数组。 此外,它还提供了写出群集位置的可能性(这不是问题的一部分,但它可能是有趣的信息)
import numpy as np
from scipy.ndimage import measurements
def select_consecutive(mask, threshold):
structure = np.zeros((3, 3, 3))
structure[:, 1, 1] = 1
labels, _ = measurements.label(1 - mask, structure=structure)
# find positions of all unmasked values
# object_slices = measurements.find_objects(labels)
_, counts = np.unique(labels, return_counts=True)
labels_selected = [i_count for i_count, count in enumerate(counts)
if count >= threshold and i_count != 0]
ind = np.in1d(labels.flatten(), labels_selected).reshape(mask.shape)
mask_new = np.ones_like(mask)
mask_new[ind] = 0
return mask_new
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.