使用数组进行 Numpy 过滤
Posted
技术标签:
【中文标题】使用数组进行 Numpy 过滤【英文标题】:Numpy filtering using array 【发布时间】:2021-04-17 05:05:01 【问题描述】:我知道之前有人问过这个问题,但对于我的特定用例似乎没有任何内容。
我有一个 numpy 数组 obs
,它代表彩色图像,形状为 (252, 288, 3)
。
我想将不是纯黑色的每个像素都转换为纯白色。
我尝试过的是obs[obs != [0, 0, 0]] = [255, 255, 255]
,但它给出了以下异常:
ValueError: NumPy boolean array indexing assignment cannot assign 3 input values to the 807 output values where the mask is true
结果与obs[obs[:, :] != [0, 0, 0]] = [255, 255, 255]
相同。另外,(obs[:, :] != [0, 0, 0]).shape
是 (252, 288, 3)
,我不明白为什么它不是简单的 (252, 288)
(布尔矩阵)。
我考虑过使用obs[obs != 0] = 255
,但这不会产生我想要的效果,因为纯绿色的像素 ([0, 255, 0]
) 将被处理组件明智并且在过滤后仍然是[0, 255, 0]
,而不是实际上是白色的 ([255, 255, 255]
)。
为什么我到现在为止尝试过的方法都不起作用,我应该怎么做?
【问题讨论】:
这不是你想要的吗? obs[obs != 0] = 255 @Stepan 我已经在问题中解释了这一点。我已经更正了一些错字,现在应该更清楚了。 毫无疑问,单通道(灰度)甚至布尔(真/假)结果足以代表您所需的黑白输出,而不需要 3 倍的 RAM,而 RGB 结果只包含黑白的? 我的回答或其他人是否解决了您的问题?如果是这样,请考虑接受它作为您的答案 - 通过单击计票旁边的空心对勾/复选标记。如果没有,请说出什么不起作用,以便我或其他人可以进一步帮助您。谢谢。 meta.stackexchange.com/questions/5234/… 【参考方案1】:根据您实际想要做什么,有多种可能性。让我们先编写设置代码(所有可能性都通用),这样您就可以明白我的意思了。
#!/usr/bin/env python3
import numpy as np
# Make a repeatable random image
np.random.seed(764)
obs = np.random.randint(0,32,(252,288,3), dtype=np.uint8)
出于测试目的,此图像在以下位置恰好有纯黑色像素:
obs[ 21, 267]
obs[ 28, 252]
obs[ 69, 127]
obs[ 98, 0]
obs[124, 210]
obs[133, 98]
obs[160, 81]
obs[167, 48]
obs[217, 237]
现在,假设您想要一个新的纯真/假黑色像素布尔掩码,您可以使用:
mask = obs.any(axis=-1)
该解决方案具有以下特点:
time: 876 µs
mask.shape: (252,288)
mask.nbytes: 72576
mask.dtype: 'bool'
您随后可以像这样使用和重复使用该掩码:
# Make masked pixels red
obs[mask,:] = [255,0,0]
# Make unmasked pixels cyan
obs[~mask,:] = [0,255,255]
现在假设您想要一个新的灰度图像,具有黑白像素,您可以使用:
grey = obs.any(axis=-1) * np.uint8(255)
该解决方案具有以下特点:
time: 887 µs
grey.shape: (252,288)
grey.nbytes: 72576
grey.dtype: np.uint8
现在假设您想要将现有的“obs”就地更改为纯黑白(但仍然是 RGB):
obs[obs.any(axis=-1),:] = [255,255,255]
该解决方案具有以下特点:
time: 1.98 ms
obs.shape: (252,288,3)
obs.nbytes: 217728
obs.dtype: np.uint8
【讨论】:
【参考方案2】:像obs[obs != [0, 0, 0]]
这样的布尔索引返回一个一维数组,其中包含obs
中满足给定条件的所有元素。
看下面的例子:
obs = np.array([
[[88, 0,99],
[ 0, 0, 0]],
[[ 0, 0, 0],
[88,77,66]]
])
obs != [0, 0, 0]
返回一个布尔数组:
array([[[ True, False, True],
[False, False, False]],
[[False, False, False],
[ True, True, True]]])
然后obs[obs != [0, 0, 0]]
返回一个一维数组,其中包含掩码为True
的所有元素:array([88, 99, 88, 77, 66])
。
所以你需要where
来测试是否有any
颜色分量不等于0:
np.where(obs.any(axis=-1, keepdims=True), 255, obs)
结果:
array([[[255, 255, 255],
[ 0, 0, 0]],
[[ 0, 0, 0],
[255, 255, 255]]])
请注意,您需要keepdims=True
才能启用广播到obs
的原始形状。否则,您必须通过 np.where(obs.any(-1)[...,np.newaxis], 255, obs)
或 np.where(np.atleast_3d(obs.any(-1)), 255, obs)
添加丢失的维度,这不太优雅。
【讨论】:
以上是关于使用数组进行 Numpy 过滤的主要内容,如果未能解决你的问题,请参考以下文章