给定一个具有形状(height, width, 3)
的2D numpy图像阵列,而BGR元组作为元素,我想将每个元素乘以一个内核来单独提取B/G/R通道。例如,蓝色内核将是(1, 0, 0)
。这样的东西:
# extact color channel
def extract_color_channel(image, kernel):
channel = np.copy(image)
height, width = image.shape[:2]
for y in range(0, height):
for x in range(0, width):
channel[y,x] = image[y, x] * kernel
return channel
# extract blue channel
def extract_blue(image):
return extract_color_channel(image, (1, 0, 0))
这样做的最有效的" numpy方法"是什么?
带有样本数组:
In [220]: arr = np.arange(5*5*3).reshape(5,5,3)
基本索引是最有效的方法(这将是view
)
In [221]: arr[:,:,0]
Out[221]:
array([[ 0, 3, 6, 9, 12],
[15, 18, 21, 24, 27],
[30, 33, 36, 39, 42],
[45, 48, 51, 54, 57],
[60, 63, 66, 69, 72]])
[1,0,0]
列表不是您想要的。但是您可以将其作为Bool阵列。
In [222]: kernel = np.array([1,0,0],dtype=bool)
In [223]: kernel
Out[223]: array([ True, False, False], dtype=bool)
In [224]: arr[:,:,kernel].shape
Out[224]: (5, 5, 1)
In [225]: arr[:,:,kernel].squeeze()
Out[225]:
array([[ 0, 3, 6, 9, 12],
[15, 18, 21, 24, 27],
[30, 33, 36, 39, 42],
[45, 48, 51, 54, 57],
[60, 63, 66, 69, 72]])
请注意,布尔值的形状仍然是3D。如果您不想要那个,那么您需要重塑或挤出最后的尺寸。此索引较慢,因为它使copy
。
此布尔索引等效于
In [226]: arr[:,:,[0]].shape
Out[226]: (5, 5, 1)
其中 [0]
是 kernel
中的" true"值的位置。
您也可以使用dot
(矩阵产品):
In [228]: np.dot(arr,[1,0,0])
Out[228]:
array([[ 0, 3, 6, 9, 12],
[15, 18, 21, 24, 27],
[30, 33, 36, 39, 42],
[45, 48, 51, 54, 57],
[60, 63, 66, 69, 72]])
它比索引要慢。
元素乘法:
在[232]中:arr*np.array([1,0,0])出去[232]:阵列([[[[0,0,0], [3,0,0], [6,0,0], [9,0,0], [12,0,0]],
[[15, 0, 0],
[18, 0, 0],
....
[66, 0, 0],
[69, 0, 0],
[72, 0, 0]]])
在此乘法中,[1,0,0]的行为似乎是(1,1,3)数组,并且用(n,n,3)播放(n,n,3)恰好。