Python 3x3无循环矩阵转换(RGB颜色转换)

Python 3x3无循环矩阵转换(RGB颜色转换),python,image-processing,numpy,Python,Image Processing,Numpy,我有一个RGB图像通过PIL加载到numpy数组中。我得到一个行x列x 3数组。经过修补,我得到了以下代码。我想学习如何在没有循环的情况下进行这样的数组/矩阵操作 # 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 )

我有一个RGB图像通过PIL加载到numpy数组中。我得到一个行x列x 3数组。经过修补,我得到了以下代码。我想学习如何在没有循环的情况下进行这样的数组/矩阵操作

# 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
我可以使用(via),但我把它作为学习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之后,我发现如果我的转换3x3不是矩阵,那么np.dot()就可以工作。奇怪

def convert_rgb_to_ycc( rgb ) :
    return np.dot( rgb, np.asarray( 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)

我不确定您使用的公式,所以我不想声称这是完整的计算,但为了简化您发布的函数,可以使用
np.dot
与numpy数组而不是numpy矩阵结合使用

np.dot
比使用numpy矩阵的
*
更通用。当将
*
与numpy矩阵一起使用时,这两个矩阵必须是二维的。 但是,
np.dot
可以使用不同形状的数组生成结果。这对于您的应用程序非常重要,因为
rgb
是三维的(例如,当它具有形状时(14702105,3))

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\u调用>;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))

我最初试过了。比如说,形状是(14702105,3)。rgb_至ycc为(3,3)。ValueError:形状太大,无法成为矩阵。哦,我明白了,我在考虑序列化像素颜色。。。让我稍微修改一下;-)啊!!使用3x3作为阵列而不是矩阵确实是解决方案。内联转换矩阵确实有助于更好地查看代码。谢谢而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))