PGFPlots:通过转换为 RGB 颜色值将 CIELab 颜色空间映射到球体

PGFPlots:通过转换为 RGB 颜色值将 CIELab 颜色空间映射到球体

在已经发布了关于绘制球体并将 CIELab 颜色空间映射到它(即通常事先询问是否pgfplots允许基于轴的颜色映射),我搜索了我需要的有关 CIELab 颜色空间的所有微积分和理论内容,以便获得(可能的)颜色映射所需的方程。

我现在的想法是获取x,y,z我的球体的值(参见下面的 MWE),其中,对于 CIELab 颜色空间,我认为我的球体坐标(所有以球面坐标计算,包括sincos)为x=ay=bz=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(色域)的三个值不能完全填满整个色彩空间XYZLab这对每家生产电视、智能手机等色彩的公司来说也是一个非常讨厌的伙伴),这就是为什么在将 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和),并用可能不太复杂的和组合替换了复杂的。然后它就起作用了。myBifthenelseminmax

\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}

在此处输入图片描述

编辑:修复了我引入的拼写错误和错误变量。至少我希望我做到了。

相关内容