首页 > 解决方案 > 如何使用 E-308 作为算法将 SRM 转换为 L*a*b*?

问题描述

我正在努力思考如何将 ASTM E-308 应用于啤酒的 SRM 测量。我正在工作的问题域要求我们通过转换为 L a进行从 SRM 到 RGB(或 sRGB)的体面转换 b* 进行从 SRM 到 RGB(或 sRGB)的体面转换。似乎我用来创建啤酒配方的每个网站都有自己的从 SRM 到 RGB 的转换,这是有道理的,因为这是一个棘手的问题。也就是说,我正在寻找一个开源的 js 库来解决这个问题。

基本上,我使用的是这里描述的算法:https://www.homebrewtalk.com/forum/threads/on-the-calculation-of-srm-rgb-values-in-the-srgb-color-space。 413581/#post-5232912

我相信这是 E-308 算法的简化。我遇到困难的地方是该帖子中提到的电子表格(http://wetnewf.org/pdfs/Brewing_articles/MOAWorkbook.xls)中提到的电子表格对我来说没有多大意义。该帖子说要根据电子表格中的观察者角度选择一个 XYZ 向量。如果我选择 10 度的观察角度,那么我希望 XYZ 向量应该是:(82.82, 3.48, 61.86)。这个对吗?

现在,选择光源光谱也有些混乱。如果我想要光源 C(我相信它是 6774K),我应该从该电子表格中提取哪些值来添加作为光谱的组件?此外,我如何计算这些组件?

我在色彩理论方面的背景有限,但我真正想要的是能够有一些输入标准,比如观察者角度和光源色温,以及 SRM 值,并计算 L a b*价值。

标签: javascriptcolors

解决方案


这个问题确实需要一个可能不适合 Stack Overflow 格式的答案。

ASTM E308 本身是一个 50 页的复杂标准,其主体是关于从光谱分布到 CIE XYZ 三色值的转换。它还涉及转换为 CIE Lab 和 CIE Luv。

您链接的电子表格没有完全实现 ASTM E308,并且方便地使用积分方法进行 5 nm 测量间隔,如果光谱数据经过带通校正,则没有技术上需要的三色加权因子表。对于实际目的来说这很好,但如果需要精度,重要的是要知道 ASTM E308 非常严格。

电子表格非常复杂,因为它似乎使用了带有特征向量的增强 SRM 计算来处理一百左右的啤酒。

假设要使用ASBC 方法,流程应该如下:

  • 使用以下等式计算给定 SRM 和路径长度的啤酒透射光谱分布:

在此处输入图像描述

  • 使用 CIE 1964 10 度标准观察者和光源 C 的积分方法将光谱分布转换为 CIE XYZ 三色值
  • 将 CIE XYZ 三色值转换为 CIE Lab
  • 更进一步,将它们也转换为 sRGB
  • 喝啤酒 :)

如果您不介意阅读 Python,我制作了一个Colab 笔记本,它使用Color并为 SRM 网格和路径长度计算啤酒颜色:

import colour
import colour.plotting
import numpy as np

colour.utilities.describe_environment()

colour.plotting.colour_style()

ASBC_SHAPE = colour.SpectralShape(380, 780, 5)

OBSERVER = colour.CMFS['CIE 1964 10 Degree Standard Observer']
ILLUMINANT = colour.ILLUMINANTS_SDS['C']
ILLUMINANT_XY = colour.ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['C']


def beer_transmission_sd(SRM, path=1, shape=ASBC_SHAPE):
    e = np.exp(1)
    wl = shape.range()
    values = np.exp(
        -(SRM / 12.7) * (0.018747 * e**(-(wl - 430) / 13.374) + 0.98226 * e**
                        (-(wl - 430) / 80.514)) * path)

    return colour.SpectralDistribution(
        values, wl, name='Beer - SRM {0} - Path {1}'.format(SRM, path))


PATHS = np.linspace(10, 1, 10)
SRM = np.linspace(1, 50, 50)
XYZ = []

for i in PATHS:
    for j in SRM:
        XYZ.append(
            colour.sd_to_XYZ(
                beer_transmission_sd(i, j),
                cmfs=OBSERVER,
                illuminant=ILLUMINANT) / 100.0)

# The Lab values for CIE Illuminant C are computed here:
Lab = colour.XYZ_to_Lab(XYZ, ILLUMINANT_XY)

# But we will be going further :)
RGB = colour.XYZ_to_sRGB(XYZ, illuminant=ILLUMINANT_XY)

figure, axes = colour.plotting.plot_multi_colour_swatches(
    [colour.plotting.ColourSwatch(RGB=np.clip(i, 0, 1)) for i in RGB],
    columns=len(SRM),
    **{
        'standalone': False,
        'x_label': 'SRM',
        'y_label': 'Path (cm)',
        'xtick.bottom': True,
        'ytick.left': True,
    })

# Ugly ticks massaging that will not be needed in future versions.
axes.set_xticks(SRM)
axes.set_yticks(-PATHS + 2)
axes.set_yticklabels(reversed(PATHS))

colour.plotting.render(standalone=True);

啤酒颜色

请注意,通过 Flask 在后端的容器中运行 Color 并从 Javascript 调用它应该很简单。我们有一个先进的 3D 可视化器,如果您想走这条路,它会很有帮助。


推荐阅读