如何使用numpy将R,G,B值提取到分开的数组中

21
假设我有一张图片,其尺寸为(1920, 1080, 3),我想将其中的R、G、B值分别提取到单独的数组中,即R, G, B。我尝试过下面的方法:
for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            B = np.append(B, image[i, j][0])
            G = np.append(G, image[i, j][1])
            R = np.append(R, image[i, j][2])

但是如预期的那样这很慢,我该如何使用numpy内置函数来完成这个任务?


1
这是基本的索引:B = image[:,:,0]; G = image[:,:,1]; R = image[:,:,2]。请参考几乎任何numpy教程。 - Warren Weckesser
1
或者只需滚动轴,然后取简单的切片... rolled = np.rollaxis(rgb,-1) ... r = rolled[0], g = rolled[1], b = rolled[2] - NaN
我建议您在vs code中安装此扩展程序 - https://marketplace.visualstudio.com/items?itemName=gsGupta.opencv-snippets&ssr=false 它直接为您提供这些内容的代码片段。 - Gauri Shankar Gupta
3个回答

31

如果您希望以OpenCV的方式使用它,则可以使用cv2.split(),记住您的图像通道:

b, g, r    = cv2.split(image) # For BGR image
b, g, r, a = cv2.split(image) # for BGRA image

或者,如果您喜欢直接使用numpy格式,那么可以直接使用[根据@igaurav的评论似乎更有效]

b, g, r    = image[:, :, 0], image[:, :, 1], image[:, :, 2] # For RGB image
b, g, r, a = image[:, :, 0], image[:, :, 1], image[:, :, 2], image[:, :, 3] # for BGRA image

您可以使用np.shape[2]来检查所给图像中的通道数。


1
注意:python -m timeit -s "import urllib.request as r; import cv2; from os.path import exists as ex; b='bench.jpg'; r.urlretrieve('https://i.imgur.com/7vGjNmZ.jpg',b) if not ex(b) else False; x=cv2.imread(b)" "b,g,r = cv2.split(x)" 的执行时间为 33.1 毫秒,而 "b,g,r = x[:,:,0], x[:,:,1], x[:,:,2]" 的执行时间为 803 纳秒(0.000803 毫秒)。很奇怪!后者使用了numpy索引,调用了3次numpy C扩展函数,而OpenCV方法只调用了1次C函数,应该是优化过的,但实际上并没有。除非我们做错了什么,否则似乎OpenCV在分离方面要慢得多。这是一个好消息! - Mitch McMabers
2
没事了,我已经搞定了。Numpy方法使用Numpy切片,它创建一个新的(非常低效的)Numpy数组“视图”,指向旧的RAM并说“读取每3个字节,跳过第1个和第2个字节”以仅查看单个通道。这是“伪拆分”通道,但在图像处理方面极其低效。每次您将通过此方式创建的假r、g或b传递给OpenCV或其他库函数时,您都会导致每个函数调用30毫秒的延迟,因为它必须将“作弊”的Numpy数据重新创建为实际的图像对象。与此同时,OpenCV split创建3个真正的img。 - Mitch McMabers
这是一篇关于通过Numpy作弊的代价的文章。使用索引(“哦,通过numpy分割只需要0.000803毫秒,而不是通过OpenCV分割需要33.1毫秒”)看起来很快,但这都是谎言——如果你滥用Numpy技巧,没有数据被分割;在RAM中也没有真正的“分割”图像被创建——而且Numpy技巧在现实中非常慢,因为每次将这样的“虚假分割”提供给OpenCV函数和其他库时,数据都必须被修复:https://answers.opencv.org/question/219040/fastest-way-to-convert-bgr-rgb-aka-do-not-use-numpy-magic-tricks/(`cv2.split()`是真正的分割)。 - Mitch McMabers
1
你的评论非常有帮助,伙计 @MitchMcMabers。 - ZdaR

15

dsplit 分割它。

import numpy as np

def channelSplit(image):
    return np.dsplit(image,image.shape[-1])

[B,G,R]=channelSplit(image)

这适用于RGB或RGBA图像。


3
这对我很有用:
def split_channels(im: np.ndarray):
    assert len(im.shape) == 3 and im.shape[-1] == 3
    return np.squeeze(np.split(im, im.shape[-1], -1), axis=-1)

请注意,np.split本身是不够的,它会留下一个(M, N, 1)的图像。但如果你想要(M, N),那么使用squeeze函数即可。
如果有其他情况,则可以删除assert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接