在已经发布了关于绘制球体并将 CIELab 颜色空间映射到它(即通常事先询问是否pgfplots
允许基于轴的颜色映射),我搜索了我需要的有关 CIELab 颜色空间的所有微积分和理论内容,以便获得(可能的)颜色映射所需的方程。
我现在的想法是获取x,y,z
我的球体的值(参见下面的 MWE),其中,对于 CIELab 颜色空间,我认为我的球体坐标(所有以球面坐标计算,包括sin
和cos
)为x=a
,y=b
和z=L
。
从 CIELab 颜色空间开始,计算应按如下方式进行:L,a,b --> X,Y,Z --> R,G,B
。
使用这个,我首先定义了必要的函数手册,第 1032 / 1033 页和
declare function = {<function definitions>}
附加ifthenelse
(相同套餐)
<statement> ? <yes> : <no>
计算xr,yr,zr
需要执行的一些系数L,a,b --> X,Y,Z
,如下所示:
declare function={% Coefficients xr,yr,zr for X,Y,Z calculation
xr(\L,\a) = ( (\a/500) + ((\L+16)/116) )^3 > 0.008856 ?%
( ((\a/500) + ((\L + 16) / 116))^3 ) :%
( 116 * ((\a/500) + ((\L + 16) / 116)) - 16 ) / 903.3;
yr(\L) = \L > ( 0.008856 * 903.3 ) ?%
((\L + 16)/116)^3 :%
\L / 903.3;
zr(\L,\b) = ( ((\L + 16) / 116) - (\b/200) )^3 > 0.008856 ?%
((((\L + 16) / 116) - (\b/200))^(3)) :%
( 116 * (((\L + 16) / 116) - (\b/200)) - 16 ) / 903.3;
}
通过这样做,我X,Y,Z
通过将这些系数xr,yr,zr
与一些系数相乘来获得(三刺激)值illuminant constants Xn,Yn,Zn
,以实现
X = xr(\L,\a) * Xn
Y = yr(\L) * Yn
Z = zr(\L,\b) * Zn
接下来,一个矩阵(矩阵元素 Mij)
[M11 M12 M13] --> gives R value
M = [M21 M22 M23] --> gives G value
[M31 M32 M33] --> gives B value
对于XYZ --> RGB
(两个 3x1 向量)转换可用于获取最终结果(函数R,G,B
,取决于\L,\a,\b
):
R(\L,\a,\b) = xr(\L,\a) * Xn * M11
+ yr(\L) * Yn * M12
+ zr(\L,\b) * Zn * M13;
G(\L,\a,\b) = xr(\L,\a) * Xn * M21
+ yr(\L) * Yn * M22
+ zr(\L,\b) * Zn * M23;
B(\L,\a,\b) = xr(\L,\a) * Xn * M31
+ yr(\L) * Yn * M32
+ zr(\L,\b) * Zn * M33;
有了这个,应该(理论上/正如我认为的)可以简单地插入我的球体的坐标x=\a
[-100; 100],y=\b
[-100; 100]和z=\L
[0; 100]以获得每个point meta
结果\addplot3
:
\addplot3[point meta = {symbolic = {<R>,<G>,<B>}}] (% Define sphere to be mapped on, incl. limited domains
{100*cos(azimuth)*sin(polar)},% x
{100*sin(azimuth)*sin(polar)},% y
{50*cos(polar)+50}% z
);
不幸的是,CIELab 模型并不准确地表示一个球体(而是一个椭圆体,因为RGB
(色域)的三个值不能完全填满整个色彩空间XYZ
,Lab
这对每家生产电视、智能手机等色彩的公司来说也是一个非常讨厌的伙伴),这就是为什么在将 RGB 映射到球体时也必须设置例外的原因。
在这里,我简单地定义了来point meta = {symbolic = {<R>,<G>,<B>}}
替换值< 0 --> 0
和> 1 --> 1
,以防止编译过程崩溃(使用嵌套ifthenelse
):
point meta={%
symbolic={%
% R Values in [0;1]
ifthenelse( R(z,x,y) < 0 , 0.0 , ifthenelse( R(z,x,y) > 1 , 1.0 , R(z,x,y) ) ),%
% G Values [0;1]
ifthenelse( G(z,x,y) < 0 , 0.0 , ifthenelse( G(z,x,y) > 1 , 1.0 , G(z,x,y) ) ),%
% B Values [0;1]
ifthenelse( B(z,x,y) < 0 , 0.0 , ifthenelse( B(z,x,y) > 1 , 1.0 , B(z,x,y) ) )%
}%
}
接下来是这样的:它无法成功编译,弹出类似Sorry, an internal routine of the floating point got an ill-formatted floating point number
和甚至的错误(由于某种原因)Unknown function 'Y' in 'xr(1,Y)'
(可能是起源?)这让我无助,因为我缺乏修复它的经验,也不确切知道如何pgfplots
处理中的数据mathparse
。
有什么想法可以解决这个问题/使其成功运行吗?
这是我的代码*到目前为止(包括插入的具体值和注释的mesh/colorspace explicit color input=rgb255
-option,因为虽然我有文献,但还不确定R(\L,\a,\b)
,G(\L,\a,\b)
和B(\L,\a,\b)
是否会弹出[0; 1]或[0; 255]中的值;不过我期望[0; 1]):
\documentclass[tikz,border=3mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\usepgfplotslibrary{patchplots}
\begin{document}
\begin{tikzpicture}[%
declare function={%
% Calculation scheme: Lab --> XYZ --> RGB [0;1]
% Math, formulas and values based on
% - https://en.wikipedia.org/wiki/Illuminant_D65
% - https://en.wikipedia.org/wiki/CIELAB_color_space
% - https://en.wikipedia.org/wiki/Adobe_RGB_color_space
% - http://brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
% - http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html
% - http://brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html (with XYZ -> sRGB)
%
% Declaring Functions to calculate CIE XYZ values --> RGB from the following variables:
% \L = L-value of CIE Lab space
% \a = a-value of CIE Lab space
% \b = b-value of CIE Lab space
% xr, yr, zr = Coefficients required to get XYZ (from L,a,b)
%
% D65 illuminant tristimulus values (T = 6504 K;)
% Xn = 0.968774;
% Yn = 1.0;
% Zn = 1.121774;
%
% CIE constants (E = epsilon, K = kappa)
% E = 0.008856;
% K = 903.3;
%
% XYZ -> sRGB matrix:
% [3.2404542 -1.5371385 -0.4985314] --> R Value
% M = [-0.9692660 1.8760108 0.0415560] --> G Value
% [0.0556434 -0.2040259 1.0572252] --> B Value
%
% Coefficients xr,yr,zr for X,Y,Z calculation
xr(\L,\a) = ( (\a/500) + ((\L+16)/116) )^3 > 0.008856 ?% > E?
( ( (\a/500) + ((\L+16) / 116) )^3 ) :%
( 116 * ((\a/500) + ((\L+16)/116)) - 16 ) / 903.3;
%
yr(\L) = \L > ( 0.008856 * 903.3 ) ?% < (E * K)?
( (\L+16)/116 )^3 :%
\L / 903.3;
%
zr(\L,\b) = ( ((\L+16)/116) - (\b/200) )^3 > 0.008856 ?% > E?
( ( ((\L+16)/116) - (\b/200) )^3 ) :%
( 116 * (((\L+16)/116) - (\b/200)) - 16 ) / 903.3;%
% Calculation of R,G,B via illuminant properties and matrix values (XYZ -> sRGB)
R(\L,\a,\b) = xr(\L,\a) * 0.968774 * 3.2404542 + yr(\L) * 1.0 * (-1.5371385) + zr(\L,\b) * 1.121774 * (-0.4985314); % Including Xn, Yn, Zn, first matrix row
G(\L,\a,\b) = xr(\L,\a) * 0.968774 * (-0.9692660) + yr(\L) * 1.0 * 1.8760108 + zr(\L,\b) * 1.121774 * 0.0415560; % Including Xn, Yn, Zn, second matrix row
B(\L,\a,\b) = xr(\L,\a) * 0.968774 * 0.0556434 + yr(\L) * 1.0 * (-0.2040259) + zr(\L,\b) * 1.121774 * 1.0572252; % Including Xn, Yn, Zn, third matrix row
}
]
\begin{axis}[axis equal,
width = 10cm,
height = 10cm,
axis lines = center,
xmin = -120,
xmax = 120,
ymin = -120,
ymax = 120,
zmin = 0,
zmax = 100,
ticks = none,
enlargelimits = 0.3,
z buffer = sort,
view/h = 45,
scale uniformly strategy = units only]
\addplot3 [%
patch,
patch type=bilinear,
variable = \azimuth,
variable y = \polar,
domain = 0:360,
y domain = 0:180,
fill opacity = 0.5,
draw opacity = 1,
line width = 0.001 pt,
samples = 10, % only for faster compilation
mesh/color input=explicit mathparse,
% mesh/colorspace explicit color input=rgb255, % if RGB values are calculated in [0 ; 255]
point meta={%
symbolic={%
% R Values [0;1]
ifthenelse( R(z,x,y) < 0 , 0.0 , ifthenelse( R(z,x,y) > 1 , 1.0 , R(z,x,y) ) ),% check r < 0 and r > 1
% G Values [0;1]
ifthenelse( G(z,x,y) < 0 , 0.0 , ifthenelse( G(z,x,y) > 1 , 1.0 , G(z,x,y) ) ),% check g < 0 and g > 1
% B Values [0;1]
ifthenelse( B(z,x,y) < 0 , 0.0 , ifthenelse( B(z,x,y) > 1 , 1.0 , B(z,x,y) ) )% check b < 0 and b > 1
}%
},
] (% Define sphere to be mapped on
{100*cos(azimuth)*sin(polar)},% x
{100*sin(azimuth)*sin(polar)},% y
{50*cos(polar)+50}% z
);
\end{axis}
\end{tikzpicture}
\end{document}
非常感谢您的想法!:) - Marius。
*改编Schrödinger's cat
自上一个问题。
答案1
有两个问题有点(?)不明显。我将您的变量\L
、\a
和替换\b
为\u
、\v
和\w
。我知道这应该不会有什么不同,但根据我的发现,它确实有区别。然后我在函数周围添加了括号(为了更安全myR
,我还将其重命名为 、myG
和),并用可能不太复杂的和组合替换了复杂的。然后它就起作用了。myB
ifthenelse
min
max
\documentclass[tikz,border=3mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\usepgfplotslibrary{patchplots}
\begin{document}
\begin{tikzpicture}[%
declare function={%
% Calculation scheme: Lab --> XYZ --> RGB [0;1]
% Math, formulas and values based on
% - https://en.wikipedia.org/wiki/Illuminant_D65
% - https://en.wikipedia.org/wiki/CIELAB_color_space
% - https://en.wikipedia.org/wiki/Adobe_RGB_color_space
% - http://brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
% - http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html
% - http://brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html (with XYZ -> sRGB)
%
% Declaring Functions to calculate CIE XYZ values --> RGB from the following variables:
% \L = L-value of CIE Lab space
% \a = a-value of CIE Lab space
% \b = b-value of CIE Lab space
% xr, yr, zr = Coefficients required to get XYZ (from L,a,b)
%
% D65 illuminant tristimulus values (T = 6504 K;)
% Xn = 0.968774;
% Yn = 1.0;
% Zn = 1.121774;
%
% CIE constants (E = epsilon, K = kappa)
% E = 0.008856;
% K = 903.3;
%
% XYZ -> sRGB matrix:
% [3.2404542 -1.5371385 -0.4985314] --> R Value
% M = [-0.9692660 1.8760108 0.0415560] --> G Value
% [0.0556434 -0.2040259 1.0572252] --> B Value
%
% Coefficients xr,yr,zr for X,Y,Z calculation
xr(\u,\v) = ( (\v/500) + ((\u+16)/116) )^3 > 0.008856 ?% > E?
( ( (\v/500) + ((\u+16) / 116) )^3 ) :%
( 116 * ((\v/500) + ((\u+16)/116)) - 16 ) / 903.3;
%
yr(\u) = \u > ( 0.008856 * 903.3 ) ?% < (E * K)?
( (\u+16)/116 )^3 :%
\u / 903.3;
%
zr(\u,\w) = ( ((\u+16)/116) - (\w/200) )^3 > 0.008856 ?% > E?
( ( ((\u+16)/116) - (\w/200) )^3 ) :%
( 116 * (((\u+16)/116) - (\w/200)) - 16 ) / 903.3;%
% Calculation of R,G,B via illuminant properties and matrix values (XYZ -> sRGB)
myR(\u,\v,\w) = xr(\u,\v) * 0.968774 * 3.2404542 + yr(\u) * 1.0 * (-1.5371385) + zr(\u,\v) * 1.121774 * (-0.4985314); % Including Xn, Yn, Zn, first matrix row
myG(\u,\v,\w) = xr(\u,\v) * 0.968774 * (-0.9692660) + yr(\u) * 1.0 * 1.8760108 + zr(\u,\v) * 1.121774 * 0.0415560; % Including Xn, Yn, Zn, second matrix row
myB(\u,\v,\w) = xr(\u,\v) * 0.968774 * 0.0556434 + yr(\u) * 1.0 * (-0.2040259) + zr(\u,\v) * 1.121774 * 1.0572252; % Including Xn, Yn, Zn, third matrix row
}
]
\begin{axis}[axis equal,
width = 10cm,
height = 10cm,
axis lines = center,
xmin = -120,
xmax = 120,
ymin = -120,
ymax = 120,
zmin = 0,
zmax = 100,
ticks = none,
enlargelimits = 0.3,
z buffer = sort,
view/h = 45,
scale uniformly strategy = units only]
\addplot3 [%
patch,
patch type=bilinear,
variable = \azimuth,
variable y = \polar,
domain = 0:360,
y domain = 0:180,
fill opacity = 0.5,
draw opacity = 1,
line width = 0.001 pt,
samples = 10, % only for faster compilation
mesh/color input=explicit mathparse,
% mesh/colorspace explicit color input=rgb255, % if RGB values are calculated in [0 ; 255]
point meta={%
symbolic={%
% R Values [0;1]
{min(max(myR(z,x,y),0),1)},%min(max(myR(z,x,z),0),1),% check r < 0 and r > 1
% G Values [0;1]
{min(max(myG(z,x,y),0),1)},%min(max(myG(z,x,y),0),1),% check g < 0 and g > 1
% B Values [0;1]
{min(max(myB(z,x,y),0),1)}%min(max(myB(z,x,y),0),1)% check b < 0 and b > 1
}%
},
] (% Define sphere to be mapped on
{100*cos(azimuth)*sin(polar)},% x
{100*sin(azimuth)*sin(polar)},% y
{50*cos(polar)+50}% z
);
\end{axis}
\end{tikzpicture}
\end{document}
编辑:修复了我引入的拼写错误和错误变量。至少我希望我做到了。