这段 Python/numpy 代码如何实现 XYZ->rgb 颜色 space 变换的白色缩放?
How does this Python/numpy code achieve white scaling for XYZ->rgb colour space transformation?
我正在阅读 this guide 关于将光谱转换为 rgb 颜色坐标的内容。
我基本上明白代数是做什么的,但是作者并没有真正解释处理白点的代数,我看不懂Python/numpy完成这项工作的代码
import numpy as np
class ColourSystem:
def __init__(self, red, green, blue, white):
self.red, self.green, self.blue = red, green, blue
self.white = white
# The chromaticity matrix (rgb -> xyz) and its inverse
self.M = np.vstack((self.red, self.green, self.blue)).T
self.MI = np.linalg.inv(self.M)
# White scaling array
self.wscale = self.MI.dot(self.white)
# xyz -> rgb transformation matrix
self.T = self.MI / self.wscale[:, np.newaxis]
最后两行让我很困惑。我的解释是 self.white
是一个列向量,所以 self.MI.dot(self.white)
是一个矩阵向量乘法产生另一个列向量。
但在这种解释中,最后一行读起来像用向量除矩阵,这对我来说毫无意义。
通过修改 rgb->xyz 矩阵的逆来生成 xyz->rgb 矩阵的最后一行是做什么的?
抱歉回答晚了,这更像是对评论的回答,而不是对原始问题的回答,但是很长并且有一些代码,所以它不适合放在那里。让我重写一个独立的代码片段,它可以完成您所要求的相同事情(初始化编号取自您提供的 link):
import numpy as np
def xyz_from_xy(x, y):
"""Return the vector (x, y, 1-x-y)."""
return np.array((x, y, 1-x-y))
red=xyz_from_xy(0.67, 0.33)
green=xyz_from_xy(0.21, 0.71)
blue=xyz_from_xy(0.15, 0.06)
white=xyz_from_xy(0.3127, 0.3291)
# The chromaticity matrix (rgb -> xyz) and its inverse
M = np.vstack((red, green, blue)).T
MI = np.linalg.inv(M)
# White scaling array
wscale = MI.dot(white)
# xyz -> rgb transformation matrix
T = MI / wscale[:, np.newaxis]
写入 T 的值是以下矩阵:
array([[ 6.20584986, -1.71746142, -1.04788582],
[-2.71554014, 5.51336937, 0.09687197],
[ 0.19384968, -0.39357359, 2.9841102 ]])
现在,这是如何计算的以及如何涉及广播?
正如名字 "vstack" 所暗示的那样,M
只是将红色、绿色和蓝色向量一个堆叠在另一个上:
array([[ 6.70000000e-01, 2.10000000e-01, 1.50000000e-01],
[ 3.30000000e-01, 7.10000000e-01, 6.00000000e-02],
[-5.55111512e-17, 8.00000000e-02, 7.90000000e-01]])
(其中,根据函数 xyz_from_xy,最后一个分量始终只是 1 减去前两个分量之和)。 MI 是它的倒数:
array([[ 1.72809198, -0.47824736, -0.29179615],
[-0.81013052, 1.64481044, 0.02889994],
[ 0.08203853, -0.16656308, 1.26289621]])
而且,正如您正确提到的,wscale
只是一个矢量(一维),作为 MI
与 white=array([0.3127, 0.3291, 0.3582])
:
的标量积获得
array([0.27846178, 0.29833126, 0.42320696])
现在开始广播。首先,wscale[:, np.newaxis]
与 wscale 是一回事,但用形状 (3,1)
:
重塑了
array([[0.27846178],
[0.29833126],
[0.42320696]])
(写成wscale.reshape(3,1)
也可以达到同样的效果)。当您在 MI
(形状为 (3,3))和另一个对象(形状为 (3,1))之间进行算术运算时,无论是求和、乘法、除法,甚至是一些看起来更奇怪的东西**,它只是在元素方面这样做。但是由于维度不同,它尝试 "broadcast",即通过多次重复相同的向量,使每个等于 1 的维度等于另一个对象中的相应维度(在本例中为 3) .明确地说,您将 MI 按元素除以通过水平重复 wscale 三次获得的矩阵。您将通过以下方式以更详细的方式获得相同的结果:
T = MI / np.hstack((wscale.reshape(3,1), wscale.reshape(3,1), wscale.reshape(3,1)))
如果你想像点积一样进行矩阵运算,你需要显式地写 MI.dot(wscale[:, np.newaxis])
(在这种情况下会 return 一个 (3,1) 形张量)。但这不是完成的:T = MI / wscale[:, np.newaxis]
的结果是:
array([[ 6.20584986, -1.71746142, -1.04788582],
[-2.71554014, 5.51336937, 0.09687197],
[ 0.19384968, -0.39357359, 2.9841102 ]])
这只是将 MI
的任意列按元素除以 wscale
的结果。例如,看第一个,如果我们做 MI[:,0] / wscale
我们确实得到:
array([ 6.20584986, -2.71554014, 0.19384968])
即第一列。
我正在阅读 this guide 关于将光谱转换为 rgb 颜色坐标的内容。
我基本上明白代数是做什么的,但是作者并没有真正解释处理白点的代数,我看不懂Python/numpy完成这项工作的代码
import numpy as np
class ColourSystem:
def __init__(self, red, green, blue, white):
self.red, self.green, self.blue = red, green, blue
self.white = white
# The chromaticity matrix (rgb -> xyz) and its inverse
self.M = np.vstack((self.red, self.green, self.blue)).T
self.MI = np.linalg.inv(self.M)
# White scaling array
self.wscale = self.MI.dot(self.white)
# xyz -> rgb transformation matrix
self.T = self.MI / self.wscale[:, np.newaxis]
最后两行让我很困惑。我的解释是 self.white
是一个列向量,所以 self.MI.dot(self.white)
是一个矩阵向量乘法产生另一个列向量。
但在这种解释中,最后一行读起来像用向量除矩阵,这对我来说毫无意义。
通过修改 rgb->xyz 矩阵的逆来生成 xyz->rgb 矩阵的最后一行是做什么的?
抱歉回答晚了,这更像是对评论的回答,而不是对原始问题的回答,但是很长并且有一些代码,所以它不适合放在那里。让我重写一个独立的代码片段,它可以完成您所要求的相同事情(初始化编号取自您提供的 link):
import numpy as np
def xyz_from_xy(x, y):
"""Return the vector (x, y, 1-x-y)."""
return np.array((x, y, 1-x-y))
red=xyz_from_xy(0.67, 0.33)
green=xyz_from_xy(0.21, 0.71)
blue=xyz_from_xy(0.15, 0.06)
white=xyz_from_xy(0.3127, 0.3291)
# The chromaticity matrix (rgb -> xyz) and its inverse
M = np.vstack((red, green, blue)).T
MI = np.linalg.inv(M)
# White scaling array
wscale = MI.dot(white)
# xyz -> rgb transformation matrix
T = MI / wscale[:, np.newaxis]
写入 T 的值是以下矩阵:
array([[ 6.20584986, -1.71746142, -1.04788582],
[-2.71554014, 5.51336937, 0.09687197],
[ 0.19384968, -0.39357359, 2.9841102 ]])
现在,这是如何计算的以及如何涉及广播?
正如名字 "vstack" 所暗示的那样,M
只是将红色、绿色和蓝色向量一个堆叠在另一个上:
array([[ 6.70000000e-01, 2.10000000e-01, 1.50000000e-01],
[ 3.30000000e-01, 7.10000000e-01, 6.00000000e-02],
[-5.55111512e-17, 8.00000000e-02, 7.90000000e-01]])
(其中,根据函数 xyz_from_xy,最后一个分量始终只是 1 减去前两个分量之和)。 MI 是它的倒数:
array([[ 1.72809198, -0.47824736, -0.29179615],
[-0.81013052, 1.64481044, 0.02889994],
[ 0.08203853, -0.16656308, 1.26289621]])
而且,正如您正确提到的,wscale
只是一个矢量(一维),作为 MI
与 white=array([0.3127, 0.3291, 0.3582])
:
array([0.27846178, 0.29833126, 0.42320696])
现在开始广播。首先,wscale[:, np.newaxis]
与 wscale 是一回事,但用形状 (3,1)
:
array([[0.27846178],
[0.29833126],
[0.42320696]])
(写成wscale.reshape(3,1)
也可以达到同样的效果)。当您在 MI
(形状为 (3,3))和另一个对象(形状为 (3,1))之间进行算术运算时,无论是求和、乘法、除法,甚至是一些看起来更奇怪的东西**,它只是在元素方面这样做。但是由于维度不同,它尝试 "broadcast",即通过多次重复相同的向量,使每个等于 1 的维度等于另一个对象中的相应维度(在本例中为 3) .明确地说,您将 MI 按元素除以通过水平重复 wscale 三次获得的矩阵。您将通过以下方式以更详细的方式获得相同的结果:
T = MI / np.hstack((wscale.reshape(3,1), wscale.reshape(3,1), wscale.reshape(3,1)))
如果你想像点积一样进行矩阵运算,你需要显式地写 MI.dot(wscale[:, np.newaxis])
(在这种情况下会 return 一个 (3,1) 形张量)。但这不是完成的:T = MI / wscale[:, np.newaxis]
的结果是:
array([[ 6.20584986, -1.71746142, -1.04788582],
[-2.71554014, 5.51336937, 0.09687197],
[ 0.19384968, -0.39357359, 2.9841102 ]])
这只是将 MI
的任意列按元素除以 wscale
的结果。例如,看第一个,如果我们做 MI[:,0] / wscale
我们确实得到:
array([ 6.20584986, -2.71554014, 0.19384968])
即第一列。