【问题标题】:How to extract R,G,B values with numpy into seperate arrays如何使用 numpy 将 R、G、B 值提取到单独的数组中
【发布时间】:2017-05-20 22:00:57
【问题描述】:

假设我有一个尺寸为 (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 来做到这一点?

【问题讨论】:

  • 这是基本索引:B = image[:,:,0]; G = image[:,:,1]; R = image[:,:,2]。查看几乎所有 numpy 教程。
  • 或者只是滚动你的轴,然后取简单的切片 ...rolled = np.rollaxis(rgb,-1) ... r = rolling[0], g = rolling[1], b =滚动[2]
  • 我建议你在你的vs代码中安装这个扩展——marketplace.visualstudio.com/…它直接为你提供了这样的sn-ps。

标签: python image opencv numpy


【解决方案1】:

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

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

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

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] 来检查给定图像中的通道数。

【讨论】:

  • 来自 OpenCV 网站:Warning cv2.split() is a costly operation (in terms of time). So do it only if you need it. Otherwise go for Numpy indexing. 来源:docs.opencv.org/3.0-beta/doc/py_tutorials/py_core/py_basic_ops/…
  • 谢谢,编辑@igaurav
  • 注意: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 ms"b,g,r = x[:,:,0], x[:,:,1], x[:,:,2]" 给出803 nsec (0.000803 ms)。诡异的!带有 numpy 索引的后者对 numpy C 扩展进行 3 次函数调用,而 OpenCV 方法仅进行 1 次 C 调用,应该进行优化,但事实并非如此。除非我们做错了什么,否则 OpenCV 的分裂似乎要慢得多。很高兴知道这一点!
  • 没关系,我已经想通了。 Numpy 方法使用 Numpy 切片,它创建了一个新的(非常低效的)Numpy 数组“视图”,它指向旧 RAM,并说“读取每 3 个字节,跳过第 1 个和第 2 个字节”以仅查看单个通道。这是“假分割”通道,但在图像处理方面效率极低。每次将假 r,g 或 b(以这种方式创建)传递给 OpenCV 或其他库函数时,都会导致每个函数调用有 30 毫秒的延迟,因为它必须将“作弊”的 Numpy 数据重新创建为真实的图像对象。同时,OpenCV split 会创建 3 个真实的 img。
  • 来自您身边好友@MitchMcMabers 的好帮手。
【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2011-04-14
      • 1970-01-01
      • 2020-01-24
      • 1970-01-01
      • 2020-12-24
      • 2015-09-11
      • 1970-01-01
      • 2020-04-25
      • 1970-01-01
      相关资源
      最近更新 更多