【问题标题】:How to extract the first element of a 2d array in python?如何在python中提取二维数组的第一个元素?
【发布时间】:2019-01-23 19:50:40
【问题描述】:

假设我在 python 中有一个 3d 数组,看起来像这样 [[[3, 4, 9], [5, 3, 1], [6, 4, 2]], [[2, 3, 6 ], [7, 9, 10], [5, 12, 4]], [[7, 5, 1], [3, 1, 2], [6, 5, 2]]]。我想提取每个条目的第一个元素并将它们全部放入一个像这样的一维数组 [3, 5, 6, 2, 7, 5, 7, 3, 6]。我正在使用一个 hsv 图像,其中每个像素都有一个 3 个元组,其中每个条目对应于色调、饱和度和值。我想只提取每个像素的色调值并将其放入一维数组中。这是我的代码的样子。

import numpy as np
import colorsys
from skimage import color
from skimage.color import rgb2hsv

img = cv2.imread("input.jpg", 1)
img_hsv = color.rgb2hsv(img)
b = []
for i in img_hsv:
    b.append(i[0][0])

问题是我正在读取的图像是 640x480,而 b 的形状只有 640,这让我觉得我没有得到图像中的所有像素。所以我的两个问题是,我的 for 循环是否正确,我什至需要一个 for 循环来执行此操作,还是 python 有一个可以执行此操作的库?

【问题讨论】:

  • img_hsv[:, 0] 有什么问题?
  • 这会产生预期的结果吗?我是 python 新手,所以我不知道这些东西是如何工作的。
  • 假设 img_hsv 是一个二维数组,是的。这是正在发生的事情,通过调用 img_hsv[:, 0],您将切出第一列 ("0") 中的所有值 (":"),产生一个值为 [3, 2, 7] 的一维数组。或者,如果您调用 img_hsv[0, :] (即第一行中的所有值),您将得到一个值为 [3, 5, 6] 的一维数组。
  • img_hsv 是一种二维数组。基本上像 img_hsv[10][12] 这样的东西会产生一条像 [153, 25, 142] 这样的线,它代表色调、饱和度和值。我只想要每个像素的第一个值并放入一维数组中。
  • 你确定数组是 2d 而不是 3d? img.shape 返回什么?

标签: python image numpy hsv


【解决方案1】:

切片数组是迄今为止最快的方法。您要导入的数组本质上是 3 维的,例如,让我们从域 0-10 的随机数创建一个 3d 数组:

import numpy as np
img = np.random.randint(0, 10, (5, 3, 3))

img.shape
Out[36]:
(5, 3, 3)

Out[37]: 
array([[[8, 0, 8],
    [9, 0, 5],
    [9, 0, 4]],

   [[5, 2, 5],
    [3, 3, 1],
    [3, 4, 0]],

   [[1, 2, 2],
    [9, 0, 6],
    [2, 5, 9]],

   [[8, 6, 2],
    [4, 5, 1],
    [3, 3, 6]],

   [[8, 0, 7],
    [0, 6, 0],
    [5, 2, 3]]])

现在,您要通过以下方式选择第一个值(在您的情况下为色调):

hue = img[:, :, 0]

hue
Out[43]: 
array([[8, 9, 9],
       [5, 3, 3],
       [1, 9, 2],
       [8, 4, 3],
       [8, 0, 5]])

这将产生一个 2d 数组,但你想要一个 1d:将其展平

hue = hue.flatten()

hue
Out[44]: array([8, 9, 9, 5, 3, 3, 1, 9, 2, 8, 4, 3, 8, 0, 5])

瞧,一维数组。阅读 flatten 的工作原理,了解它如何对输出进行排序。

虽然切片是这里最快的选择,但您会问如何改进您的 for 循环。你的循环的问题是你只遍历行。由于您在 3d 数组的前两个维度上进行操作,因此您需要有两个 for 循环(警告,这非常慢......阅读“Big O notation”可能会有帮助)。对循环进行以下更改就足够了

b = []
for row in img_hsv.shape[0]:
    for col in img_hsv.shape[1]:
        b.append(hsv[row, col, 0])

还有一件事,你说你希望你的输出 (b) 是一个数组。您目前已将其定义为列表,您可以通过

将其转换为数组
b = np.array(b)

编辑

只是为了好玩,并且为了说明循环有多慢,我对每个选项都进行了计时。

import datetime as dt
import numpy as np

img = np.random.randint(0, 100, (640, 480, 3))
iterations = 100

d1 = dt.datetime.now()
for i in range(iterations):
    hue = img[:, :, 0]
print('Slicing total time: ', dt.datetime.now() - d1)



d1 = dt.datetime.now()
for i in range(iterations):
    hue = []
    for row in range(img.shape[0]):
        for col in range(img.shape[1]):
            hue.append(img[row, col, 0])

print('Multiple total looping time: ', dt.datetime.now() - d1)

Slicing total time:  0:00:00.002107
Multiple total looping time:  0:00:08.860522

或每个文件 20 微秒与每个文件 80 毫秒(快 4200 倍)。

【讨论】:

    【解决方案2】:

    假设: two_D = [[3, 5, 6], [2, 7, 5], [7, 3, 6]] 我通常也将这些数组称为列表列表。 如果您打印 two_D[0] 您可以看到它将打印出您的第一个列表。 如果您想到达第一个列表的第一个元素: two_D[0][0]。

    在您的问题中填充一维数组:

    one_d = []
    for i in range(len(two_D)):
        one_d.append(two_D[i][0])
    

    我没有处理像素和图像,无法帮助您解决其他问题,抱歉!

    【讨论】:

    • 这适用于小型阵列,但速度非常慢。最好进行切片而不是循环遍历数组。根据数组大小,切片可以快一到两个(也许是三个!)数量级。
    【解决方案3】:
    from array import *
    a = [[[3, 4, 9], [5, 3, 1], [6, 4, 2]], [[2, 3, 6], [7, 9, 10], [5, 12, 4]], [[7, 5, 1], [3, 1, 2], [6, 5, 2]]]
    b=[]
    j=0
    m=0
    print(a[0][0])
    while j<len(a):
        print("J:",j)
        l=0
        for k in a[j]:
             print(j,l)
             b.insert(m, a[j][l][0])
             l+=1
             m+=2
        j+=1 
    print(b)
    

    j 和 m 变量用于跟踪数组 (a) 内的嵌套迭代,j 在第一个嵌套内递增,而 m 在第二个嵌套内递增 2,从而可以得到每个嵌套数组的所有第 0 个元素并插入到数组中(b)

    【讨论】:

    • 仅供参考,虽然这可能有效(我没有测试过),但它会非常慢。检查我的答案以进行时间比较。
    【解决方案4】:

    您可以zip列表的列表,使用next获取第一项作为元组,并使用list构造函数将元组转换为列表(如果您不这样做,列表转换是可选的) t需要将结果作为列表):

    list(next(zip(*img_hsv)))
    

    编辑:您修改后的问题现在有一个列表列表(如您所说的 3d 数组),因此您可以先使用生成器表达式展平列表并应用上述相同的逻辑:

    list(next(zip(*(t for s in img_hsv for t in s))))
    

    【讨论】:

    • 我不认为这符合 OP 的要求。此解决方案将从每个子数组中提取第一行,而 OP 想要第三维的第一级。
    • 请检查 OP 的编辑历史和时间戳。在我给出答案后,OP改变了问题。在更改之前它是一个二维数组。如您所见,新浪 Safarabadi 给出的第一个答案也是基于 OP 的原始问题。
    • 你是对的。 FWIW,我很欣赏你的解决方案(虽然切片仍然更快),我没有拒绝你。如果我有,我会把它改成赞成票。来自我的 +1。
    猜你喜欢
    • 2019-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-27
    • 1970-01-01
    相关资源
    最近更新 更多