Python - NumPy - 作为数组元素的元组

15
我是一名计算机专业的大学生,正在为我的Calc III课程开展一个涉及奇异值分解的编程项目。基本思路是将m x n大小的图像转换成一个m x n矩阵,其中每个元素都是一个元组,表示点(m, n)处像素的颜色通道(r, g, b)。我选择使用Python来实现,因为这是我目前唯一真正熟悉的语言。
据我所知,Python通常不支持将元组作为数组的元素。但我自己进行了一些研究,并找到了一个解决方法,即预先分配数组如下:
def image_to_array(): #converts an image to an array  
    aPic = loadPicture("zorak_color.gif")  
    ph = getHeight(aPic)  
    pw = getWidth(aPic)  
    anArray = zeros((ph,pw), dtype='O')  
    for h in range(ph):  
         for w in range(pw):             
            p = getPixel(aPic, w, h)  
            anArray[h][w] = (getRGB(p))  
    return anArray

对于任务的第一部分,即仅将图像转换为矩阵(不涉及线性代数),这个方法是正确的。

然而,使用SVD时就会变得更加棘手。当我使用从我的图像构建的数组(其中每个元素都是一个元组)调用内置的numPy svd函数时,会出现以下错误:

Traceback (most recent call last):
  File "<pyshell#5>", line 1, in -toplevel-
    svd(x)
  File "C:\Python24\Lib\site-packages\numpy\linalg\linalg.py", line 724, in svd
    a = _fastCopyAndTranspose(t, a)
  File "C:\Python24\Lib\site-packages\numpy\linalg\linalg.py", line 107, in _fastCopyAndTranspose
    cast_arrays = cast_arrays + (_fastCT(a.astype(type)),)
ValueError: setting an array element with a sequence.

这是我最初遇到的相同错误,在做了一些研究后,我发现可以预分配数组以允许元组作为元素。
现在的问题是,我只是大学(编程水平)的第一个学期,这些由专业程序员编写的numPy函数对我来说有点黑盒子(尽管我相信对有经验的人来说它们会更清晰)。因此,编辑这些函数以允许元组比我自己的函数更加复杂。我需要从这里开始做什么?我想我应该将相关的numPy函数复制到我的程序中,并相应地进行修改?
提前感谢您的帮助。

3
SVD 只适用于矩阵。您是否打算对每个 RGB 通道进行 SVD?换句话说,即使您形成了一个 m x n x 3 数组,也不能将其直接传递给 SVD 函数,因为 SVD 仅适用于矩阵,而不是任意大小的张量。 - Justin Peel
2个回答

15

与其将数组元素类型设置为 'O'(对象),你应该将其设置为元组。请参见SciPy手册中的一些示例。

在您的情况下,最简单的方法是使用类似以下代码:

a = zeros((ph,pw), dtype=(float,3))

假设你的RGB值是由3个浮点数构成的元组。

这类似于创建一个三维数组(如Steve所建议的),实际上,元组元素可以被访问为a[n,m][k]z[n,m,k],其中k是元组中的元素。

当然,SVD是针对二维矩阵而不是三维数组定义的,因此您不能使用linalg.svd(a)。 您需要决定哪个矩阵(R、G和B中的三个可能矩阵之一)需要进行SVD。

例如,如果您想要“R”矩阵的SVD(假设它是元组的第一个元素),请使用以下代码:

linalg.svd(a[:,:,1])

3

我认为你需要一个 ph×pw×3的numpy数组。

anArray = zeros((ph,pw,3))  
for h in range(ph):  
     for w in range(pw):             
        p = getPixel(aPic, w, h)  
        anArray[h][w] = getRGB(p)

您只需要确保getRGB返回一个由3个元素组成的列表而不是元组。


当然,这很容易,我只需要在getRGB周围加上list()。但是在按照您的更改后,我开始收到一个新错误:File "C:\Python24\Lib\site-packages\numpy\linalg\linalg.py", line 720, in svd _assertRank2(a) File "C:\Python24\Lib\site-packages\numpy\linalg\linalg.py", line 116, in _assertRank2 raise LinAlgError, '%d-dimensional array given. Array must be
LinAlgError: 给出了3维数组。必须是二维数组所以我仍然需要一种方法来拥有一个可与numPy一起使用的元组"2-d"矩阵...
- Thomas
转念一想,这似乎根本就没有意义。我认为你无法找到一个由元组组成的二维矩阵的SVD,如果有一个三维矩阵的SVD,那肯定超出了我的课程和这个项目的范围。我需要弄清楚如何针对每个颜色通道进行此操作,然后以某种方式将这三个矩阵合并。感谢您的回复。 - Thomas
有SVD的3D版本[DeLathauwer 2000] [Mesgarani 2004],但我怀疑这不是你想要的。对于像人脸识别这样的任务,人们经常将整个图像向量化,然后将这些向量连接成大小为(hw)-by-(num images)的大矩阵X然后*在X上执行PCA,这相当于X X^T的SVD。我在这里回答了一个相关问题:https://dev59.com/11HTa4cB1Zd3GeqPVNuk#4176400 - Steve Tjoa

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