使用C#将温度显示为颜色?

15

有人知道一个算法,可以将开尔文/摄氏温度转换为RGB颜色值吗?

就像热成像相机一样。

我找到了一些链接:

http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_T.html

http://www.fourmilab.ch/documents/specrend/specrend.c

enter image description here

但是我不知道什么是XYZ颜色?

enter image description here

我只有以摄氏度表示的温度..

我可以将其转换为任何温度 Temperature Conversion Formulas

更新: Blackbody Color Datafile 我找到了这个.. 但那些开尔文数值看起来很奇怪.. 我的意思是 红色应该代表热.. 那么为什么8000K是蓝色,而1000K是红色..


6
第二个链接包含一个完整的实现。阅读代码应该就足够了。 - Daniel Hilgarth
2
请原谅我的无知:但是temperature不是一个单一的值,可以直接映射到简单预定义的渐变色条上的单个点吗? - Bobby
@Bobby 这正是我想要做的事情... 但是我应该去哪里获取或如何制作预定义的渐变呢? - Danpe
1
8000K -> 蓝色,1000K -> 红色是色温。而蓝色的能量确实比红色高。 - Oliver Charlesworth
1
我认为值得指出的是,热成像相机显示的颜色实际上并不是“真实的颜色”。它们有些是任意选择的,并且仅用于可视化而非测量。 - carlpett
5个回答

10

最好的选项是使用带有GetPixel的图像:

Temperature Gradient

private void UpdateTemp()
{
    Bitmap temps = (Bitmap)Properties.Resources.temp;
    if (curTemp >= 0)
    {
        int i = curTemp;
        if (i < 0)
            i = 0;
        if (i > temps.Width-1)
            i = temps.Width-1;
        this.BackColor = temps.GetPixel(i, 10);
    }
}

或者构建一个数组。 来源

    private static Color[] colors = 
    {
        Color.FromArgb(155, 188, 255), //    40000
        Color.FromArgb(155, 188, 255), //    39500
        Color.FromArgb(155, 188, 255), //    39000
        Color.FromArgb(155, 188, 255), //    38500
        Color.FromArgb(156, 188, 255), //    38000
        Color.FromArgb(156, 188, 255), //    37500
        Color.FromArgb(156, 189, 255), //    37000
        Color.FromArgb(156, 189, 255), //    36500
        Color.FromArgb(156, 189, 255), //    36000
        Color.FromArgb(157, 189, 255), //    35500
        Color.FromArgb(157, 189, 255), //    35000
        Color.FromArgb(157, 189, 255), //    34500
        Color.FromArgb(157, 189, 255), //    34000
        Color.FromArgb(157, 189, 255), //    33500
        Color.FromArgb(158, 190, 255), //    33000
        Color.FromArgb(158, 190, 255), //    32500
        Color.FromArgb(158, 190, 255), //    32000
        Color.FromArgb(158, 190, 255), //    31500
        Color.FromArgb(159, 190, 255), //    31000
        Color.FromArgb(159, 190, 255), //    30500
        Color.FromArgb(159, 191, 255), //    30000
        Color.FromArgb(159, 191, 255), //    29500
        Color.FromArgb(160, 191, 255), //    29000
        Color.FromArgb(160, 191, 255), //    28500
        Color.FromArgb(160, 191, 255), //    28000
        Color.FromArgb(161, 192, 255), //    27500
        Color.FromArgb(161, 192, 255), //    27000
        Color.FromArgb(161, 192, 255), //    26500
        Color.FromArgb(162, 192, 255), //    26000
        Color.FromArgb(162, 193, 255), //    25500
        Color.FromArgb(163, 193, 255), //    25000
        Color.FromArgb(163, 193, 255), //    24500
        Color.FromArgb(163, 194, 255), //    24000
        Color.FromArgb(164, 194, 255), //    23500
        Color.FromArgb(164, 194, 255), //    23000
        Color.FromArgb(165, 195, 255), //    22500
        Color.FromArgb(166, 195, 255), //    22000
        Color.FromArgb(166, 195, 255), //    21500
        Color.FromArgb(167, 196, 255), //    21000
        Color.FromArgb(168, 196, 255), //    20500
        Color.FromArgb(168, 197, 255), //    20000
        Color.FromArgb(169, 197, 255), //    19500
        Color.FromArgb(170, 198, 255), //    19000
        Color.FromArgb(171, 198, 255), //    18500
        Color.FromArgb(172, 199, 255), //    18000
        Color.FromArgb(173, 200, 255), //    17500
        Color.FromArgb(174, 200, 255), //    17000
        Color.FromArgb(175, 201, 255), //    16500
        Color.FromArgb(176, 202, 255), //    16000
        Color.FromArgb(177, 203, 255), //    15500
        Color.FromArgb(179, 204, 255), //    15000
        Color.FromArgb(180, 205, 255), //    14500
        Color.FromArgb(182, 206, 255), //    14000
        Color.FromArgb(184, 207, 255), //    13500
        Color.FromArgb(186, 208, 255), //    13000
        Color.FromArgb(188, 210, 255), //    12500
        Color.FromArgb(191, 211, 255), //    12000
        Color.FromArgb(193, 213, 255), //    11500
        Color.FromArgb(196, 215, 255), //    11000
        Color.FromArgb(200, 217, 255), //    10500  
        Color.FromArgb(204, 219, 255), //    10000
        Color.FromArgb(208, 222, 255), //    9500
        Color.FromArgb(214, 225, 255), //    9000
        Color.FromArgb(220, 229, 255), //    8500
        Color.FromArgb(227, 233, 255), //    8000
        Color.FromArgb(235, 238, 255), //    7500
        Color.FromArgb(245, 243, 255), //    7000
        Color.FromArgb(255, 249, 253), //    6500
        Color.FromArgb(255, 243, 239), //    6000
        Color.FromArgb(255, 236, 224), //    5500
        Color.FromArgb(255, 228, 206), //    5000
        Color.FromArgb(255, 219, 186), //    4500
        Color.FromArgb(255, 209, 163), //    4000
        Color.FromArgb(255, 196, 137), //    3500
        Color.FromArgb(255, 180, 107), //    3000
        Color.FromArgb(255, 161,  72), //    2500
        Color.FromArgb(255, 137,  18), //    2000
        Color.FromArgb(255, 109,   0), //    1500 
        Color.FromArgb(255,  51,   0), //    1000
    };

6
我知道这是一个两年前的帖子,但我也遇到了同样的问题。
我使用Python中的Numpy.polyfit将颜色表中的数据进行分段5次多项式拟合。通过这些系数,我能够得出下面的C#函数。适合度R平方值接近或超过0.999。在其大部分定义域内误差小于0.01%,但有几个点的误差接近3%。不过,对于大多数情况来说应该足够好了。
private Color blackBodyColor(double temp)
{
    float x = (float)(temp / 1000.0);
    float x2 = x * x;
    float x3 = x2 * x;
    float x4 = x3 * x;
    float x5 = x4 * x;

    float R, G, B = 0f;

    // red
    if (temp <= 6600)
        R = 1f;
    else
        R = 0.0002889f * x5 - 0.01258f * x4 + 0.2148f * x3 - 1.776f * x2 + 6.907f * x - 8.723f;

    // green
    if (temp <= 6600)
        G = -4.593e-05f * x5 + 0.001424f * x4 - 0.01489f * x3 + 0.0498f * x2 + 0.1669f * x - 0.1653f;
    else
        G = -1.308e-07f * x5 + 1.745e-05f * x4 - 0.0009116f * x3 + 0.02348f * x2 - 0.3048f * x + 2.159f;

    // blue
    if (temp <= 2000f)
        B = 0f;
    else if (temp < 6600f)
        B = 1.764e-05f * x5 + 0.0003575f * x4 - 0.01554f * x3 + 0.1549f * x2 - 0.3682f * x + 0.2386f;
    else
        B = 1f;

    return Color.FromScRgb(1f, R, G, B);
}

1
你可以使用Color.FromArgb吗? 显然,从ScRgb到Argb的映射不是线性的:http://stackoverflow.com/questions/13096933/fromargb-vs-fromscrgb - Dan W

3

如果我理解正确,您正在寻找关于XYZ颜色空间的理论背景。


2

色温是基于发出光的实际颜色(理论上,一个“理想黑体”)的,该黑体仅根据其温度发出光。

这种光源的一些例子:如果你有一个发出红光的电炉元件,它可能在1000K左右。常规白炽灯泡丝绸在2700K左右,太阳大约在5700K左右。所有三者都是“黑体”的公平近似值;它们根据其实际温度发射特定光谱的光。

许多人工光源实际上并不是它们发射的光的“温度”(它们的光谱通常也不是黑体谱...)。相反,它们的“温度”评级是理论上的黑体必须具有的温度,才能发出那种颜色的光。还有一些颜色是黑体无法产生的:与更“自然”的黑体照明相比,呈绿色或紫色的光。

正如其中一条评论中所提到的,您可能正在考虑的热成像显示都是伪彩色。在伪彩色显示中,颜色仅出于方便而选择:因此,对于热成像相机,他们可能会选择看起来“热”的红色用于温暖,“冷”的蓝色用于寒冷。但是,他们也可以轻松地选择从黑到白或紫红到绿色的范围。

由于伪彩色显示是任意的,如果您想估计温度(科学图像通常应具有某种颜色键),则确实需要检查特定图像或系统的颜色键。如果没有颜色键,也没有关于图像生成方式的文档,则无法进行估算。


0
上述函数在温度大于10000K时高估了红色。当温度大于14000时,颜色变为紫色。我使用7阶多项式重新拟合了数据。系数应该是:
def temp_to_rgb(temp):
    t = temp/1000.

    # calculate red
    if t < 6.527:
        red = 1.0
    else:
        coeffs = [  4.93596077e+00,  -1.29917429e+00,
                    1.64810386e-01,  -1.16449912e-02,
                    4.86540872e-04,  -1.19453511e-05,
                    1.59255189e-07,  -8.89357601e-10]
        tt = min(t,40)
        red = poly(coeffs,tt)
    red = max(red,0)
    red = min(red,1)

    # calcuate green
    if t < 0.85:
        green = 0.0
    elif t < 6.6:
        coeffs = [ -4.95931720e-01,   1.08442658e+00,
                   -9.17444217e-01,   4.94501179e-01,
                   -1.48487675e-01,   2.49910386e-02,
                   -2.21528530e-03,   8.06118266e-05]
        green = poly(coeffs,t)
    else:
        coeffs = [  3.06119745e+00,  -6.76337896e-01,
                    8.28276286e-02,  -5.72828699e-03,
                    2.35931130e-04,  -5.73391101e-06,
                    7.58711054e-08,  -4.21266737e-10]
        tt = min(t,40)
        green = poly(coeffs,tt)
    green = max(green,0)
    green = min(green,1)

    # calculate blue
    if t < 1.9:
        blue = 0.0
    elif t < 6.6:
        coeffs = [  4.93997706e-01,  -8.59349314e-01,
                    5.45514949e-01,  -1.81694167e-01,
                    4.16704799e-02,  -6.01602324e-03,
                    4.80731598e-04,  -1.61366693e-05]
        blue = poly(coeffs,t)
    else:
        blue = 1.0
    blue = max(blue,0)
    blue = min(blue,1)

    return (red,green,blue)

在这里,poly(coeffs,x)= coeffs [0] + coeffs [1] * x + coeffs [2] * x ** 2 + ...

抱歉,我不熟悉C#,但您可以轻松阅读代码。

对于大多数情况,误差仅为0.5%,对于温度为6600 K的红色最多为1.2%。这里采用了高阶多项式,因此对于temp> 40000 K,红色和绿色必须保持恒定,否则会发生奇怪的事情。


1
很抱歉看到6500K不是R、G、B的最大值(1,1,1)。它最终变成了(1,0.955,0.985)。如果您有时间进行适当的调整,使每个最大值都达到最大值将是一个不错的功能。顺便说一下,我已经将您的伪代码转换为C#。 - Dan W
这个答案在底部,链接为:http://n4te.com/x/4178-LQvA.png,而顶部的链接为:https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html(2000-7000K)。除非我搞错了,否则这个答案不太好(Java代码链接为:http://n4te.com/x/4179-qRLn.txt)。 - NateS
1
@DanW 尝试使用 6600K 来调整 1,1,1 RGB。 - NateS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接