2011-11-04 98 views
3

我有装入经由PIL一个numpy的阵列的RGB图像。我得到了一个行x cols x 3数组。修补后,我得到了下面的代码。我想学习如何在没有循环的情况下做这样的数组/矩阵操作。3x3矩阵转换而不循环(RGB颜色转换)

# Note using matrix not array. 
rgb_to_ycc = np.matrix(
    (0.2990, 0.5870, 0.1140, 
    -0.1687, -0.3313, 0.5000, 
    0.5000, -0.4187, -0.0813,) 
).reshape(3,3) 

ycc_to_rgb = np.matrix(
    (1.0, 0.0, 1.4022, 
     1.0, -0.3456, -0.7145, 
     1.0, 1.7710, 0,) 
).reshape(3, 3) 

def convert_ycc_to_rgb(ycc) : 
    # convert back to RGB 
    rgb = np.zeros_like(ycc) 
    for row in range(ycc.shape[0]) : 
     rgb[row] = ycc[row] * ycc_to_rgb.T 
    return rgb 

def convert_rgb_to_ycc(rgb) : 
    ycc = np.zeros_like(rgb) 
    for row in range(rgb.shape[0]): 
     ycc[row] = rgb[row] * rgb_to_ycc.T 
    return ycc 

我可以使用http://pypi.python.org/pypi/colormath(通过Using Python to convert color formats?),但我用这个作为一个练习学习numpy的。

上述Colormath库使用的点积。

# Perform the adaptation via matrix multiplication. 
result_matrix = numpy.dot(var_matrix, rgb_matrix) 

我的数学不是它应该在的地方。 np.dot()是我最好的选择吗?

编辑。更深层次的阅读colormath的apply_RGB_matrix()之后 - color_conversions.py,我发现np.dot如果转换3x3s是矩阵()的作品。奇怪的。

def convert_rgb_to_ycc(rgb) : 
    return np.dot(rgb, np.asarray(rgb_to_ycc).T) 

回答

4

我不知道您使用的是convert RGB to YCC公式,所以我不想声称这是完整的计算,而是以简化功能你发布,是的,使用np.dot与numpy数组而不是numpy矩阵。

np.dot*与numpy的矩阵更普遍。当使用*与numpy的矩阵,两个矩阵必须是2维的。 但np.dot可以产生具有不同形状的阵列的结果。这对您的应用很重要,因为rgb是三维的(例如,当它具有形状(1470,2105,5))时。

np.dot文档说:

For N dimensions it is a sum product over the last axis of `a` and 
    the second-to-last of `b`:: 

     dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m]) 

这是正规矩阵乘法的推广。


我建议你调用最终功能rgb_to_ycc,而不是给那个指定的常数矩阵。 (它更短,并说明你想要的功能。)

所以下面,rgb_to_ycc是我的建议功能,我做了一些小的修改,以使convert_rgb_to_ycc不会引发异常并进行我认为您的计划。

最后一行np.allclose(...)显示这两个函数返回相同的结果。

import numpy as np 

def rgb_to_ycc(rgb): 
    M = np.array(
     (0.2990, 0.5870, 0.1140, 
     -0.1687, -0.3313, 0.5000, 
     0.5000, -0.4187, -0.0813,) 
     ).reshape(3,3) 
    return np.dot(rgb, M.T) 

def convert_rgb_to_ycc(rgb) : 
    M = np.matrix(
     (0.2990, 0.5870, 0.1140, 
     -0.1687, -0.3313, 0.5000, 
     0.5000, -0.4187, -0.0813,) 
     ).reshape(3,3) 
    shape=rgb.shape 
    rgb=rgb.reshape((-1,3)) 
    ycc = np.zeros_like(rgb) 
    for i in range(len(rgb)): 
     ycc[i] = rgb[i] * M.T 
    return ycc.reshape(shape) 

rgb=np.random.random((100,100,3)) 
assert np.allclose(rgb_to_ycc(rgb),convert_rgb_to_ycc(rgb)) 
+1

啊!实际上,使用3x3作为阵列而不是矩阵是解决方案。并且内联转换矩阵的确会使代码更好看。谢谢!而np.allclose()是学习的新东西。 –

3
def convert_ycc_to_rgb(ycc): 
    return ycc * ycc_to_rgb.T 

def convert_rgb_to_ycc(rgb): 
    return rgb * rgb_to_ycc.T 

那样简单,记住矩阵乘法是如何以行和列的内积来定义。

编辑:

我假定RGB和YCC矩阵只是一个矩阵,该矩阵有尽可能多的行作为像素和每个颜色分量的列。所以,我们首先需要做的是给他们再次重塑一个(rows*cols,3)再到(rows, cols, 3)

因此,代码总算是:

def convert_ycc_to_rgb(ycc): 
    shape = ycc.shape 
    return np.array(ycc.reshape(-1,3) * ycc_to_rgb.T).reshape(shape) 

def convert_rgb_to_ycc(rgb): 
    shape = rgb.shape 
    return np.array(rgb.reshape(-1,3) * rgb_to_ycc.T).reshape(shape) 
+0

我原本试过。例如,rgb.shape就是(1470,2105,3)。 rgb_to_ycc是(3,3)。 ValueError:形状太大而不能成为矩阵。 –

+0

哦,我明白了,我正在考虑序列化的像素颜色......让我劈开一点;-) – fortran

+1

+1帮助我想到以新的方式重塑! –