我对numpy多维数组是陌生的,并且陷入似乎应该是一个“简单”的概念。
在下面的代码中,fakepng
代表numpy数组内部的RGBA图像。我想将图像的每个纯黑色像素0
的alpha通道设置为[0,0,0]
,以使其透明。我可以使用嵌套的for循环来做到这一点:
fakepng = np.array([[[0,0,0,255],[0,255,255,255]],[[255,255,0,255],[255,255,255,255]]])
rows, cols, channels = fakepng.shape
for x in range(0, rows):
for y in range(0, cols):
if (fakepng[x, y, 0] == 0 and fakepng[x, y, 1] == 0 and fakepng[x, y, 2] == 0):
fakepng[x, y] = [0, 0, 0, 0]
但是,我迷失了寻找“正确的” numpy函数和/或语法以使其成为1行高效操作的迷路。我不确定这是索引还是掩码问题,是否需要向量化函数,或者最好的概念是什么。
为了避免烦人的for循环,您可以执行以下操作:
# 1. Create an auxiliary 2D array
aux_fakepng = fakepng.reshape(-1, 4)
# 2. Find all the rows in which all the elements but the last are 0
idx_rows = np.all(aux_fakepng[:, :-1] == 0, axis=1)
# 3. Set the alpha channel of those rows to 0
aux_fakepng[idx_rows, -1] = 0
注意,您正在修改aux_fakepng
。由于您有两个引用指向同一数组,因此您对aux_fakepng
所做的每次修改也会影响fakepng
。
编辑
由于某些人可能并不熟悉numpy
和多维数组,因此我将尽我所能尽力解释这里发生的事情。
首先,我们首先创建一个指向fakepng
的新引用。在此过程中,我们还将重塑数组,因此使用它更容易:
aux_fakepng = fakepng.reshape(-1, 4)
重塑数组时,我们指定新形状将为(-1, 4)
。这意味着我们的新引用将具有4列,并且它将尝试考虑原始数组的其他维数以使其尽可能适合行数。请注意,如果该操作无法适合完美的数组(该数组中的所有行都有4列),则该操作可能会失败。
如果通道的值或多或少而不是4,我们可以执行以下操作:
aux_fakepng = fakepng.reshape(-1, fakepng.shape[-1])
通过这样做,我们使用的是fakepng
值的最后一个值(指通道数)。
如前所述,此分配创建对原始数组的新引用。这意味着对aux_fakepng
所做的每个修改也将影响fakepng
,因为它们是同一对象。此分配不是深层副本(np.copy()
之类的函数可以创建数组的深层副本。
一旦有了二维数组,我们需要找到所有RGB值都等于0的行。要找到这些行,我们可以执行以下操作:
idx_rows = np.all(aux_fakepng[:, :-1] == 0, axis=1)
但是,这是怎么回事? aux_fakepng[:, :-1]
应该做什么?让我们先退后一步。
当前,这是aux_fakepng
:
array([[ 0, 0, 0, 255],
[ 0, 255, 255, 255],
[255, 255, 0, 255],
[255, 255, 255, 255]])
在这里,我们选择ALL ROWS(:part),在每一行中,我们选择除最后一个之外的所有列(:-1部分)。因此,我们正在访问的是以下数组:
array([[ 0, 0, 0],
[ 0, 255, 255],
[255, 255, 0],
[255, 255, 255]])
现在,我们通过执行aux_fakepng[:, :-1] == 0
比较每个元素是否等于0。这将返回以下数组:
array([[ True, True, True],
[ True, False, False],
[False, False, True],
[False, False, False]])
但是,我们要查找所有元素均为0的行,而不是数组等于0的行。为此,我们使用np.all()
函数,并将其沿axis=1
应用。这意味着该函数将检查行中的所有元素是否均为0。如果要更好地理解this page轴,请参考numpy
。该函数产生以下输出并将其分配给idx_rows
:
array([ True, False, False, False])
最后,我们将在([0, 0, 0]
值)中发现黑色像素的那些行的alpha通道值更改为0:
aux_fakepng[idx_rows, -1] = 0
通过这样做,我们正在访问其索引对应于找到idx_rows
值的True
位置的行。在这些行内,我们访问与alpha通道相对应的最后一个元素(-1索引),并将其值设置为0。