星等B-V颜色指数转换为视觉RGB颜色

28
我正在尝试将星星的B-V颜色指数转换为明显的RGB颜色。除了查找表和颜色渐变之外,似乎没有众所周知的算法可以做到这一点。
什么是B-V颜色指数?
这是天文学家分配给星星的数字,用于指示其明显的颜色。热星(低B-V)为蓝/紫色,而冷星(高B-V)为红色,中间为白/橙色的星星。
初始算法
B-V到开尔文的转换

enter image description here

var t = 4600 * ((1 / ((0.92 * bv) + 1.7)) +(1 / ((0.92 * bv) + 0.62)) );

开尔文转xyY

如果您将星体建模为黑体,则可以使用普朗克辐射定律的数值近似来计算xy坐标(CIE色度)。

enter image description here

enter image description here

enter image description here

// t to xyY
var x, y = 0;

if (t>=1667 && t<=4000) {
  x = ((-0.2661239 * Math.pow(10,9)) / Math.pow(t,3)) + ((-0.2343580 * Math.pow(10,6)) / Math.pow(t,2)) + ((0.8776956 * Math.pow(10,3)) / t) + 0.179910;
} else if (t > 4000 && t <= 25000) {
  x = ((-3.0258469 * Math.pow(10,9)) / Math.pow(t,3)) + ((2.1070379 * Math.pow(10,6)) / Math.pow(t,2)) + ((0.2226347 * Math.pow(10,3)) / t) + 0.240390;
}

if (t >= 1667 && t <= 2222) {
  y = -1.1063814 * Math.pow(x,3) - 1.34811020 * Math.pow(x,2) + 2.18555832 * x - 0.20219683;
} else if (t > 2222 && t <= 4000) {
  y = -0.9549476 * Math.pow(x,3) - 1.37418593 * Math.pow(x,2) + 2.09137015 * x - 0.16748867;
} else if (t > 4000 && t <= 25000) {
  y = 3.0817580 * Math.pow(x,3) - 5.87338670 * Math.pow(x,2) + 3.75112997 * x - 0.37001483;
}

xyY 转 XYZ (Y = 1)

enter image description here

enter image description here

// xyY to XYZ, Y = 1
var Y = (y == 0)? 0 : 1;
var X = (y == 0)? 0 : (x * Y) / y;
var Z = (y == 0)? 0 : ((1 - x - y) * Y) / y;

XYZ转RGB

enter image description here

var r = 0.41847 * X - 0.15866 * Y - 0.082835 * Z;
var g = -0.091169 * X + 0.25243 * Y + 0.015708 * Z;
var b = 0.00092090 * X - 0.0025498 * Y + 0.17860 * Z;

问题

我使用B-V颜色指数运行了这个算法:1.2、1.0、0.59、0.0、-0.29。以下是输出结果。

enter image description here

为什么输出结果这么奇怪?热星是蓝色的,但冷星是棕色的,似乎没有白色/橙色中间颜色的恒星。
更新
根据Ozan的评论,我使用了错误的矩阵将XYZ转换为RGB。由于sRGB是Web上的默认色彩空间(或者不是吗?),我现在使用正确的矩阵,然后跟着进行伽马校正函数(a = 0.055)。

enter image description here

enter image description here

我现在得到了这个漂亮的颜色渐变,

enter image description here

但在两极仍然没有红色/紫色。

演示

现在还有一个fiddle,您可以尝试一下。

更新2

如果使用0.5的Gamma值,并将B-V颜色指数的范围扩展到4.7至-0.5,则可以在一个极端获得红色,但仍无法获得紫色。这是更新后的fiddle链接。

enter image description here


你的RGB值是在0到1之间还是在0到255之间? - Ozan
0和1,我将其乘以255以获得输出图像。 - melhosseiny
2
你的kelvinToXyY似乎是正确的,我得到了2500K的0.476,y: 0.414。我认为你的XYZ转RGB使用了错误的矩阵,我在http://www.cs.rit.edu/~ncs/color/t_convert.html#RGB%20to%20XYZ%20&%20XYZ%20to%20RGB找到了另一个矩阵,请试一试。 - Ozan
@melhosseiny 我在我的回答末尾添加了temp <--> BV(包括开尔文和摄氏度)之间的转换例程,以及RGB -> BV的转换例程... - Spektre
8个回答

17

我使用表格插值。几年前,在某个地方找到了这张表:

     type     r   g   b    rrggbb        B-V

     O5(V)   155 176 255  #9bb0ff       -0.32 blue
     O6(V)   162 184 255  #a2b8ff
     O7(V)   157 177 255  #9db1ff
     O8(V)   157 177 255  #9db1ff
     O9(V)   154 178 255  #9ab2ff
   O9.5(V)   164 186 255  #a4baff
     B0(V)   156 178 255  #9cb2ff
   B0.5(V)   167 188 255  #a7bcff
     B1(V)   160 182 255  #a0b6ff
     B2(V)   160 180 255  #a0b4ff
     B3(V)   165 185 255  #a5b9ff
     B4(V)   164 184 255  #a4b8ff
     B5(V)   170 191 255  #aabfff
     B6(V)   172 189 255  #acbdff
     B7(V)   173 191 255  #adbfff
     B8(V)   177 195 255  #b1c3ff
     B9(V)   181 198 255  #b5c6ff
     A0(V)   185 201 255  #b9c9ff       0.00 White
     A1(V)   181 199 255  #b5c7ff
     A2(V)   187 203 255  #bbcbff
     A3(V)   191 207 255  #bfcfff
     A5(V)   202 215 255  #cad7ff
     A6(V)   199 212 255  #c7d4ff
     A7(V)   200 213 255  #c8d5ff
     A8(V)   213 222 255  #d5deff
     A9(V)   219 224 255  #dbe0ff
     F0(V)   224 229 255  #e0e5ff       0.31 yellowish
     F2(V)   236 239 255  #ecefff
     F4(V)   224 226 255  #e0e2ff
     F5(V)   248 247 255  #f8f7ff
     F6(V)   244 241 255  #f4f1ff
     F7(V)   246 243 255  #f6f3ff       0.50
     F8(V)   255 247 252  #fff7fc
     F9(V)   255 247 252  #fff7fc
     G0(V)   255 248 252  #fff8fc       0.59  Yellow
     G1(V)   255 247 248  #fff7f8
     G2(V)   255 245 242  #fff5f2
     G4(V)   255 241 229  #fff1e5
     G5(V)   255 244 234  #fff4ea
     G6(V)   255 244 235  #fff4eb
     G7(V)   255 244 235  #fff4eb
     G8(V)   255 237 222  #ffedde
     G9(V)   255 239 221  #ffefdd
     K0(V)   255 238 221  #ffeedd       0.82 Orange
     K1(V)   255 224 188  #ffe0bc
     K2(V)   255 227 196  #ffe3c4
     K3(V)   255 222 195  #ffdec3
     K4(V)   255 216 181  #ffd8b5
     K5(V)   255 210 161  #ffd2a1
     K7(V)   255 199 142  #ffc78e
     K8(V)   255 209 174  #ffd1ae
     M0(V)   255 195 139  #ffc38b       1.41 red
     M1(V)   255 204 142  #ffcc8e
     M2(V)   255 196 131  #ffc483
     M3(V)   255 206 129  #ffce81
     M4(V)   255 201 127  #ffc97f
     M5(V)   255 204 111  #ffcc6f
     M6(V)   255 195 112  #ffc370
     M8(V)   255 198 109  #ffc66d       2.00
  1. 在使用前,只需对缺失的 B-V 指标进行插值(线性或更好),
  2. 然后使用线性插值得到 RGB=f(B-V);
  3. 查找表中最接近的两条线,并在它们之间进行插值...

[edit1] 呵呵,刚巧遇到 这个(之前提到的原始信息)

[edit2] 这是我没有任何 XYZ 的近似值

BV to RGB

因此,BV 指标范围为 < -0.4 , 2.0 >

这是我的(C++)转换代码:

//---------------------------------------------------------------------------
void bv2rgb(double &r,double &g,double &b,double bv)    // RGB <0,1> <- BV <-0.4,+2.0> [-]
    {
    double t;  r=0.0; g=0.0; b=0.0; if (bv<-0.4) bv=-0.4; if (bv> 2.0) bv= 2.0;
         if ((bv>=-0.40)&&(bv<0.00)) { t=(bv+0.40)/(0.00+0.40); r=0.61+(0.11*t)+(0.1*t*t); }
    else if ((bv>= 0.00)&&(bv<0.40)) { t=(bv-0.00)/(0.40-0.00); r=0.83+(0.17*t)          ; }
    else if ((bv>= 0.40)&&(bv<2.10)) { t=(bv-0.40)/(2.10-0.40); r=1.00                   ; }
         if ((bv>=-0.40)&&(bv<0.00)) { t=(bv+0.40)/(0.00+0.40); g=0.70+(0.07*t)+(0.1*t*t); }
    else if ((bv>= 0.00)&&(bv<0.40)) { t=(bv-0.00)/(0.40-0.00); g=0.87+(0.11*t)          ; }
    else if ((bv>= 0.40)&&(bv<1.60)) { t=(bv-0.40)/(1.60-0.40); g=0.98-(0.16*t)          ; }
    else if ((bv>= 1.60)&&(bv<2.00)) { t=(bv-1.60)/(2.00-1.60); g=0.82         -(0.5*t*t); }
         if ((bv>=-0.40)&&(bv<0.40)) { t=(bv+0.40)/(0.40+0.40); b=1.00                   ; }
    else if ((bv>= 0.40)&&(bv<1.50)) { t=(bv-0.40)/(1.50-0.40); b=1.00-(0.47*t)+(0.1*t*t); }
    else if ((bv>= 1.50)&&(bv<1.94)) { t=(bv-1.50)/(1.94-1.50); b=0.63         -(0.6*t*t); }
    }
//---------------------------------------------------------------------------

[注]

这种BV颜色是定义温度照明的黑体颜色,因此它表示与星星相对视角下的星星颜色。为了得到视觉上正确的颜色,您需要考虑我们大气层中的大气散射效应和快速移动恒星的多普勒效应!!!例如,我们的太阳是“白色”的,但在光线散射后,颜色从红色(接近地平线)变为黄色(接近顶点...中午)。

如果您想要视觉上正确的颜色,这些常见问题解答可能会有所帮助:

如果您需要,这里有一些温度和BV之间的转换函数:

//---------------------------------------------------------------------------
float bv2temp_K(float bv)   //  BV <-0.4,+2.0> [-] -> temp [ºK]
    {
    return              4600.0 * ((1.0 / ((0.92 * bv) + 1.7)) +(1.0 / ((0.92 * bv) + 0.62)) );
    }
//---------------------------------------------------------------------------
float bv2temp_C(float bv)   //  BV <-0.4,+2.0> [-] -> temp [ºC]
    {
    return (-272.15) + (4600.0 * ((1.0 / ((0.92 * bv) + 1.7)) +(1.0 / ((0.92 * bv) + 0.62)) ));
    }
//---------------------------------------------------------------------------
float temp_K2bv(float t)    //  BV <-0.4,+2.0> [-] <- temp [ºK]
    {
    float a,b,c,D;
    a=(0.8464*t);
    b=(2.1344*t)-8464.0;
    c=(1.0540*t)-10672.0;
    D=(b*b)-(4.0*a*c);
    if (D<0.0) D=0.0; else D=sqrt(D);
    return (-b+D)/(2.0*a);
//  return (-b-D)/(2.0*a);
    }
//---------------------------------------------------------------------------
float temp_C2bv(float t)    //  BV <-0.4,+2.0> [-] <- temp [ºC]
    {
    float a,b,c,D;
    t+=-272.15;
    a=(0.8464*t);
    b=(2.1344*t)-8464.0;
    c=(1.0540*t)-10672.0;
    D=(b*b)-(4.0*a*c);
    if (D<0.0) D=0.0; else D=sqrt(D);
    return (-b+D)/(2.0*a);
//  return (-b-D)/(2.0*a);
    }
//---------------------------------------------------------------------------

以下是“BV=f(temp[K])”相关依赖关系的预览(来自我的测试应用程序的截图):

BV=f(temp[K])

另外,我还使用近似搜索方法,从RGB颜色中获取了BV和temp的值:

//---------------------------------------------------------------------------
typedef unsigned __int8  BYTE; // comment this out if you already have BYTEs
typedef unsigned __int32 DWORD; // comment this out if you already have DWORDs
const int _r=0; // channel order
const int _g=1;
const int _b=2;
const int _a=3;
union color
    {
    BYTE db[4]; // channel access
    DWORD dd;   // all 32 bit of color
//  TColor c;   // VCL/GDI color  (you can ignore this)
    };
//---------------------------------------------------------------------------
DWORD bv2rgb(float bv)      //  BV <-0.4,+2.0> [-] -> RGB(A) 32bit
    {
    color c;
    float r,g,b,t;
    r=0.0; g=0.0; b=0.0; if (bv<-0.3999999) bv=-0.3999999; if (bv> 2.0) bv= 2.0;
         if ((bv>=-0.40)&&(bv<0.00)) { t=(bv+0.40)/(0.00+0.40); r=0.61+(0.11*t)+(0.1*t*t); }
    else if ((bv>= 0.00)&&(bv<0.40)) { t=(bv-0.00)/(0.40-0.00); r=0.83+(0.17*t)          ; }
    else if ((bv>= 0.40)&&(bv<2.10)) { t=(bv-0.40)/(2.10-0.40); r=1.00                   ; }
         if ((bv>=-0.40)&&(bv<0.00)) { t=(bv+0.40)/(0.00+0.40); g=0.70+(0.07*t)+(0.1*t*t); }
    else if ((bv>= 0.00)&&(bv<0.40)) { t=(bv-0.00)/(0.40-0.00); g=0.87+(0.11*t)          ; }
    else if ((bv>= 0.40)&&(bv<1.60)) { t=(bv-0.40)/(1.60-0.40); g=0.98-(0.16*t)          ; }
    else if ((bv>= 1.60)&&(bv<2.00)) { t=(bv-1.60)/(2.00-1.60); g=0.82         -(0.5*t*t); }
         if ((bv>=-0.40)&&(bv<0.40)) { t=(bv+0.40)/(0.40+0.40); b=1.00                   ; }
    else if ((bv>= 0.40)&&(bv<1.50)) { t=(bv-0.40)/(1.50-0.40); b=1.00-(0.47*t)+(0.1*t*t); }
    else if ((bv>= 1.50)&&(bv<1.94)) { t=(bv-1.50)/(1.94-1.50); b=0.63         -(0.6*t*t); }
    r*=255.0; c.db[_r]=r;
    g*=255.0; c.db[_g]=g;
    b*=255.0; c.db[_b]=b;
              c.db[_a]=0;
    return c.dd;
    }
//---------------------------------------------------------------------------
float rgb2bv(DWORD rgb)     //  BV <-0.4,+2.0> [-] <- RGB(A) 32bit
    {
    int d,dd;
    union color c0,c1;
    approx bv; double e;
    c0.dd=rgb;
    for (bv.init(-0.4,2.0,0.1,3,&e);!bv.done;bv.step())
        {
        c1.dd=bv2rgb(bv.a);
        d=int(c0.db[_r])-int(c1.db[_r]); if (d<0) d=-d; dd =d;
        d=int(c0.db[_g])-int(c1.db[_g]); if (d<0) d=-d; dd+=d;
        d=int(c0.db[_b])-int(c1.db[_b]); if (d<0) d=-d; dd+=d;
        e=dd;
        }
    return bv.aa;
    }
//---------------------------------------------------------------------------

如果您的像素格式通道顺序不同,只需更改_r,_g,_b,_a常量。但是请注意,24bpp RGB颜色精度会导致临时范围边缘的误差高达约300K,中间范围 3169K .. 13000K 的误差高达约50K,因此为了获得更好的精度,您需要使用更好的色彩深度...

1
我正在尝试将您的C++代码翻译成Python,但我的C++水平不是很好。您能解释一下t是如何初始化的吗?如果我正确地阅读了这段代码,t首先会被初始化为在堆栈帧分配时该内存位置中的任何内容,然后您会检查该值是否在[-0.4,2.0]范围内,并在必要时将其放置在边界上。这对我来说毫无意义,为什么不像r、g、b一样将它设置为0.0呢? - John Nilsson
@JohnNilsson (+1) 我忘记重写了(很好的发现),第一行只是在bv超出范围时的情况,应该在if条件语句中使用bv而不是t,我已经修复了。 - Spektre

12

你要求一个算法,我来给你一个。

在使用Python3.5、Pyglet和MongoDB从HYG数据库中呈现数据时,我研究了这个主题。我对我的星图中的星星外观感到满意。这些颜色可以在此答案底部找到。

1. 颜色指数 (B-V) 转温度 (K)

这是我用于从列表中提取的 B-V(ci) 数据的函数,该列表来自HYG数据库。在此示例中,ci是我正在运行的列表中的一个 B-V 值。

    temp = 4600 * (1 / (0.92 * ci + 1.7) + 1 / (0.92 * ci + 0.62))

2. 获取一个大表格。

我选择了这个表格,建议您也这样做。选择温度列和 RGB 或 rgb 值列作为参考。

3. 预处理数据。

从 RGB 表格数据中,我生成了三个有序列表(n = 391)(我的方法是使用电子表格软件和一个能够同时拥有数百万光标的文本编辑器进行清理和选择,然后将结果导入到 mongoDB 中,以便通过 pymongo 封装器在 python 中轻松处理值的列表,而不会在脚本文件中产生太多混乱)。我要介绍的方法的好处是,您可以从其他可能使用 CMYK 或 HSV 的表格中提取颜色数据并进行相应的调整。甚至可以交叉参考。但是,您应该最终得到类似于我建议的 (s)RGB 表格的列表,如下所示;

    reds = [255, 255, ... , 155, 155]
    greens = [56, 71, ..., 188,188]
    blues = [0, 0, ..., 255, 255]

    """ this temps list is also (n=391) and corresponds to the table values."""
    temps = []
    for i in range(1000,40100,100):
        temps.append(i)

接下来,我对这些列表应用了一些高斯平滑(它有助于获得更好的多项式,因为它消除了一些波动),然后使用numpy包中的polyfit()方法(多项式回归)将温度值相对于R、G和B值进行拟合:

colors = [reds,greens,blues]

""" you can tweak the degree value to see if you can get better coeffs. """
def smoothListGaussian2(myarray, degree=3):
    myarray = np.pad(myarray, (degree-1,degree-1), mode='edge')
    window=degree*2-1
    weight=np.arange(-degree+1, degree)/window
    weight = np.exp(-(16*weight**2))
    weight /= sum(weight)
    smoothed = np.convolve(myarray, weight, mode='valid')
    return smoothed

i=0

for color in colors:

    color = smoothListGaussian2(color)
    x = np.array(temps)
    y = np.array(color)

    names = ["reds","greens","blues"]
    """ raise/lower the k value (third one) in c """
    z = np.polyfit(x, y, 20)
    f = np.poly1d(z)
    #plt.plot(x,f(x),str(names[i][0]+"-"))
    print("%sPoly = " % names[i], z)

    i += 1
plt.show()

这样可以为形式为enter image description here的多项式提供(n)个系数(a)。

现在想想看,您可能可以使用polyfit来生成系数以将CI直接转换为RGB…并跳过CI到温度转换步骤,但是通过先转换为温度,温度和所选颜色空间之间的关系更加清晰。

4. 实际算法:将温度值插入RGB多项式

正如我之前所说,您可以使用其他光谱数据和其他颜色空间来拟合多项式曲线,此步骤仍然相同(稍作修改)。

无论如何,这是我用的完整简单代码(还要注意,这是k=20多项式):

import numpy as np

redco = [ 1.62098281e-82, -5.03110845e-77, 6.66758278e-72, -4.71441850e-67, 1.66429493e-62, -1.50701672e-59, -2.42533006e-53, 8.42586475e-49, 7.94816523e-45, -1.68655179e-39, 7.25404556e-35, -1.85559350e-30, 3.23793430e-26, -4.00670131e-22, 3.53445102e-18, -2.19200432e-14, 9.27939743e-11, -2.56131914e-07,  4.29917840e-04, -3.88866019e-01, 3.97307766e+02]
greenco = [ 1.21775217e-82, -3.79265302e-77, 5.04300808e-72, -3.57741292e-67, 1.26763387e-62, -1.28724846e-59, -1.84618419e-53, 6.43113038e-49, 6.05135293e-45, -1.28642374e-39, 5.52273817e-35, -1.40682723e-30, 2.43659251e-26, -2.97762151e-22, 2.57295370e-18, -1.54137817e-14, 6.14141996e-11, -1.50922703e-07,  1.90667190e-04, -1.23973583e-02,-1.33464366e+01]
blueco = [ 2.17374683e-82, -6.82574350e-77, 9.17262316e-72, -6.60390151e-67, 2.40324203e-62, -5.77694976e-59, -3.42234361e-53, 1.26662864e-48, 8.75794575e-45, -2.45089758e-39, 1.10698770e-34, -2.95752654e-30, 5.41656027e-26, -7.10396545e-22, 6.74083578e-18, -4.59335728e-14, 2.20051751e-10, -7.14068799e-07,  1.46622559e-03, -1.60740964e+00, 6.85200095e+02]

redco = np.poly1d(redco)
greenco = np.poly1d(greenco)
blueco = np.poly1d(blueco)

def temp2rgb(temp):

    red = redco(temp)
    green = greenco(temp)
    blue = blueco(temp)

    if red > 255:
        red = 255
    elif red < 0:
        red = 0
    if green > 255:
        green = 255
    elif green < 0:
        green = 0
    if blue > 255:
        blue = 255
    elif blue < 0:
        blue = 0

    color = (int(red),
             int(green),
             int(blue))
    print(color)
    return color

另外还有一些注释和图像...

根据我的多项式函数,OBAFGKM黑体温度刻度:

enter image description here

RGB [0-255] 对温度 [0-40000K] 的绘图,

  • + : 表数据
  • 曲线 : 多项式拟合 enter image description here 最低保真度值的放大图: enter image description here

这是紫色

正如你所看到的,虽然有些偏差,但肉眼几乎不可察觉,如果你真的想改进它(我不想),你可以选择其他选项:

  1. 将绿色值最高的列表部分分开,并查看新左右列表的更好多项式函数。就像这样:

Corrective Measures.

  1. 编写异常规则(也许是简单的k=2或k=3多项式函数),针对保真度较低的窗口值。
  2. 在使用polyfit()之前尝试其他平滑算法。
  3. 尝试其他来源或颜色空间。

我的多项式函数的整体性能也让我很满意。当我在我的星图中加载大约120000个星体对象时,每个对象至少有18个彩色顶点,只需要几秒钟,这让我非常惊讶。然而,仍有改进的空间。为了获得更加逼真的效果(而不仅仅是黑体辐射光),我可以添加引力透镜、大气效应、相对论多普勒效应等...

哦,还有紫色,像承诺的那样。

一些其他有用的链接:


6

如果有人需要将@Spektre的方便的C++代码转换为Python,请参考以下内容。我已经删除了一些重复的部分(编译器无疑会修复)以及当bv>=2.01.94<bv<1.9509时g和b的不连续性。

def bv2rgb(bv):
  if bv < -0.4: bv = -0.4
  if bv > 2.0: bv = 2.0
  if bv >= -0.40 and bv < 0.00:
    t = (bv + 0.40) / (0.00 + 0.40)
    r = 0.61 + 0.11 * t + 0.1 * t * t
    g = 0.70 + 0.07 * t + 0.1 * t * t
    b = 1.0
  elif bv >= 0.00 and bv < 0.40:
    t = (bv - 0.00) / (0.40 - 0.00)
    r = 0.83 + (0.17 * t)
    g = 0.87 + (0.11 * t)
    b = 1.0
  elif bv >= 0.40 and bv < 1.60:
    t = (bv - 0.40) / (1.60 - 0.40)
    r = 1.0
    g = 0.98 - 0.16 * t
  else:
    t = (bv - 1.60) / (2.00 - 1.60)
    r = 1.0
    g = 0.82 - 0.5 * t * t
  if bv >= 0.40 and bv < 1.50:
    t = (bv - 0.40) / (1.50 - 0.40)
    b = 1.00 - 0.47 * t + 0.1 * t * t
  elif bv >= 1.50 and bv < 1.951:
    t = (bv - 1.50) / (1.94 - 1.50)
    b = 0.63 - 0.6 * t * t
  else:
    b = 0.0
  return (r, g, b)

5

对于@paddyg的代码纠正,该代码对我无效(特别是颜色bv< 0.4):这是@Spektre的C++代码的精确版本,用Python编写:

def bv2rgb(bv):
    if bv < -0.40: bv = -0.40
    if bv > 2.00: bv = 2.00

    r = 0.0
    g = 0.0
    b = 0.0

    if  -0.40 <= bv<0.00:
        t=(bv+0.40)/(0.00+0.40)
        r=0.61+(0.11*t)+(0.1*t*t)
    elif 0.00 <= bv<0.40:
        t=(bv-0.00)/(0.40-0.00)
        r=0.83+(0.17*t)
    elif 0.40 <= bv<2.10:
        t=(bv-0.40)/(2.10-0.40)
        r=1.00
    if  -0.40 <= bv<0.00:
        t=(bv+0.40)/(0.00+0.40)
        g=0.70+(0.07*t)+(0.1*t*t)
    elif 0.00 <= bv<0.40:
        t=(bv-0.00)/(0.40-0.00)
        g=0.87+(0.11*t)
    elif 0.40 <= bv<1.60:
        t=(bv-0.40)/(1.60-0.40)
        g=0.98-(0.16*t)
    elif 1.60 <= bv<2.00:
        t=(bv-1.60)/(2.00-1.60)
        g=0.82-(0.5*t*t)
    if  -0.40 <= bv<0.40:
        t=(bv+0.40)/(0.40+0.40)
        b=1.00
    elif 0.40 <= bv<1.50:
        t=(bv-0.40)/(1.50-0.40)
        b=1.00-(0.47*t)+(0.1*t*t)
    elif 1.50 <= bv<1.94:
        t=(bv-1.50)/(1.94-1.50)
        b=0.63-(0.6*t*t)

    return (r, g, b)

3

@Spektre在Swift 3.0中的回答:

private func bv2ToRGB(for bv: CGFloat, logging: Bool = false) -> Color {
    var bv = bv
    var t: CGFloat = 0
    var r: CGFloat = 0
    var g: CGFloat = 0
    var b: CGFloat = 0

    if bv < -0.4 { bv = -0.4}
    if bv > 2.0 { bv = 2.0}

    switch bv {
    case -0.4 ... 0.0:
        t = (bv+0.40)/(0.00+0.40)
        r = 0.61+(0.11*t)+(0.1*t*t)
    case 0.0 ... 0.4:
        t = (bv-0.00)/(0.40-0.00)
        r = 0.83+(0.17*t)
    case 0.4 ... 2.1:
        t = (bv-0.40)/(2.10-0.40)
        r = 1.00
    default: break
    }

    switch bv {
    case -0.4 ... 0.0:
        t = (bv+0.40)/(0.00+0.40)
        g = 0.70 + (0.07*t)+(0.1*t*t)
    case 0.0 ... 0.4:
        t = (bv-0.00)/(0.40-0.00)
        g = 0.87 + (0.11*t)
    case 0.4 ... 1.6:
        t = (bv-0.40)/(1.60-0.40)
        g = 0.98 - (0.16*t)
    case 1.6 ... 2.0:
        t = (bv-1.60)/(2.00-1.60)
        g = 0.82         - (0.5*t*t)
    default: break
    }

    switch bv {
    case -0.4 ... 0.4:
        t = (bv+0.40)/(0.40+0.40)
        b = 1.0
    case 0.4 ... 1.5:
        t = (bv-0.40)/(1.50-0.40)
        b = 1.00 - (0.47*t)+(0.1*t*t)
    case 1.5 ... 1.94:
        t = (bv-1.50)/(1.94-1.50)
        b = 0.63         - (0.6*t*t)
    default: break
    }

    #if os(OSX)
        return NSColor(calibratedRed: r, green: g, blue: b, alpha: 1.0)
    #else
        return UIColor(red: r, green: g, blue: b, alpha: 1.0)
    #endif
}

1
为什么没有紫色或深蓝色?无限的色温,在被大气层减少蓝色之前,其1931 CIE坐标为X = .240,y = .234。
无限色温下黑体的光谱功率分布,每单位波长带宽的功率与波长的四次方成反比。在700nm处,这只有400nm的10.7%。

0

根据列表(http://www.vendian.org/mncharity/dir3/blackbody/UnstableURLs/bbr_color.html),以下函数使用Kotlin基于2度比例尺获取温度颜色:

fun getColorForTemp(temp: Int) = when (temp) {
  in 0..1000 -> -52480
  in 1000..1100 -> -52480
  in 1100..1200 -> -47872
  in 1200..1300 -> -44544
  in 1300..1400 -> -41728
  in 1400..1500 -> -39424
  in 1500..1600 -> -37120
  in 1600..1700 -> -35328
  in 1700..1800 -> -33792
  in 1800..1900 -> -32256
  in 1900..2000 -> -30976
  in 2000..2100 -> -29429
  in 2100..2200 -> -28131
  in 2200..2300 -> -26583
  in 2300..2400 -> -25293
  in 2400..2500 -> -24004
  in 2500..2600 -> -22971
  in 2600..2700 -> -21939
  in 2700..2800 -> -20908
  in 2800..2900 -> -19877
  in 2900..3000 -> -18846
  in 3000..3100 -> -18071
  in 3100..3200 -> -17041
  in 3200..3300 -> -16266
  in 3300..3400 -> -15492
  in 3400..3500 -> -14718
  in 3500..3600 -> -13945
  in 3600..3700 -> -13427
  in 3700..3800 -> -12654
  in 3800..3900 -> -12137
  in 3900..4000 -> -11364
  in 4000..4100 -> -10847
  in 4100..4200 -> -10330
  in 4200..4300 -> -9813
  in 4300..4400 -> -9297
  in 4400..4500 -> -8780
  in 4500..4600 -> -8264
  in 4600..4700 -> -7748
  in 4700..4800 -> -7488
  in 4800..4900 -> -6972
  in 4900..5000 -> -6712
  in 5000..5100 -> -6196
  in 5100..5200 -> -5936
  in 5200..5300 -> -5421
  in 5300..5400 -> -5161
  in 5400..5500 -> -4646
  in 5500..5600 -> -4386
  in 5600..5700 -> -4127
  in 5700..5800 -> -3868
  in 5800..5900 -> -3609
  in 5900..6000 -> -3094
  in 6000..6100 -> -2835
  in 6100..6200 -> -2576
  in 6200..6300 -> -2317
  in 6300..6400 -> -2059
  in 6400..6500 -> -1800
  in 6500..6600 -> -1541
  in 6600..6700 -> -1539
  in 6700..6800 -> -66817
  in 6800..6900 -> -198401
  in 6900..7000 -> -329729
  in 7000..7100 -> -526849
  in 7100..7200 -> -658177
  in 7200..7300 -> -789505
  in 7300..7400 -> -921089
  in 7400..7500 -> -1052417
  in 7500..7600 -> -1118209
  in 7600..7700 -> -1249537
  in 7700..7800 -> -1380865
  in 7800..7900 -> -1446657
  in 7900..8000 -> -1578241
  in 8000..8100 -> -1709569
  in 8100..8200 -> -1775105
  in 8200..8300 -> -1840897
  in 8300..8400 -> -1972225
  in 8400..8500 -> -2038017
  in 8500..8600 -> -2103809
  in 8600..8700 -> -2235137
  in 8700..8800 -> -2300929
  in 8800..8900 -> -2366721
  in 8900..9000 -> -2432257
  in 9000..9100 -> -2498049
  in 9100..9200 -> -2563841
  in 9200..9300 -> -2629633
  in 9300..9400 -> -2695169
  in 9400..9500 -> -2760961
  in 9500..9600 -> -2826753
  in 9600..9700 -> -2892289
  in 9700..9800 -> -2958081
  in 9800..9900 -> -3023617
  in 9900..10000 -> -3089409
  in 10000..10200 -> -3155201
  in 10200..10300 -> -3220993
  in 10300..10400 -> -3286529
  in 10400..10600 -> -3352321
  in 10600..10700 -> -3418113
  in 10700..10800 -> -3483649
  in 10800..10900 -> -3483905
  in 10900..11000 -> -3549441
  in 11000..11200 -> -3615233
  in 11200..11300 -> -3681025
  in 11300..11500 -> -3746561
  in 11500..11700 -> -3812353
  in 11700..11900 -> -3878145
  in 11900..12000 -> -3943681
  in 12000..12100 -> -3943937
  in 12100..12200 -> -4009473
  in 12200..12300 -> -4009729
  in 12300..12500 -> -4075265
  in 12500..12700 -> -4141057
  in 12700..12800 -> -4206593
  in 12800..12900 -> -4206849
  in 12900..13200 -> -4272385
  in 13200..13400 -> -4338177
  in 13400..13500 -> -4403713
  in 13500..13700 -> -4403969
  in 13700..13900 -> -4469505
  in 13900..14000 -> -4469761
  in 14000..14300 -> -4535297
  in 14300..14600 -> -4601089
  in 14600..14700 -> -4666625
  in 14700..15000 -> -4666881
  in 15000..15200 -> -4732417
  in 15200..15300 -> -4732673
  in 15300..15700 -> -4798209
  in 15700..16100 -> -4864001
  in 16100..16200 -> -4929537
  in 16200..16500 -> -4929793
  in 16500..16800 -> -4995329
  in 16800..17000 -> -4995585
  in 17000..17400 -> -5061121
  in 17400..17500 -> -5061377
  in 17500..18000 -> -5126913
  in 18000..18100 -> -5192449
  in 18100..18600 -> -5192705
  in 18600..18800 -> -5258241
  in 18800..19200 -> -5258497
  in 19200..19700 -> -5324033
  in 19700..19900 -> -5324289
  in 19900..20600 -> -5389825
  in 20600..20700 -> -5390081
  in 20700..21500 -> -5455617
  in 21500..21700 -> -5521153
  in 21700..22400 -> -5521409
  in 22400..22800 -> -5586945
  in 22800..23400 -> -5587201
  in 23400..24200 -> -5652737
  in 24200..24500 -> -5652993
  in 24500..25700 -> -5718529
  in 25700..27100 -> -5784321
  in 27100..27400 -> -5849857
  in 27400..28700 -> -5850113
  in 28700..29500 -> -5915649
  in 29500..30600 -> -5915905
  in 30600..32000 -> -5981441
  in 32000..32700 -> -5981697
  in 32700..35000 -> -6047233
  in 35000..35200 -> -6047489
  in 35200..38300 -> -6113025
  in 38300..38600 -> -6178561
  in 38600..40000 -> -6178817
  else -> -6178817
}

这些值与BV <-> temp值不匹配(它们相似但不同),那么哪个是正确的?此外,链接包含2度和10度的值(如果我没记错,它是指颜色采取的某种色度特性,其“瞳孔”角度覆盖范围是什么?) - Spektre

0
回答为什么没有紫色的问题:我认为答案是星星本身就不是那种颜色。或者说,当我们拍摄它们时,它们并没有呈现出那种颜色。这个帖子中针对各种温度/B-V值产生的颜色对我来说似乎相当准确。看看我在天鹅座拍摄的Albireo的照片:https://www.flickr.com/photos/30974264@N02/6939409750/in/photolist-bB54th-bzdhKG Albireo A(左)是一颗K型恒星,其B-V值为1.074,而Alberio B(右)是一颗B型恒星,其B-V值为-0.06。从上面的图表中观察这些B-V值的颜色,我认为与图片有很强的相关性。 此外,不要忘记即使对于非常热的恒星,也仍然会在较长波长处产生一些输出,这将倾向于使“蓝色”变得不饱和。黑体辐射是广谱的。

1
欢迎来到 Stack Overflow!请注意,Stack Overflow 不是一个常规论坛 - 它是一个“有关实际编程问题的问答网站”(请参见[tour])。在我看来,这似乎是对之前回答的后续补充,而不是真正回答问题。 (但是您可以趁机浏览一下[astronomy.se]!) - Jongware
如果我没记错,BV只是黑体颜色,所以为了获得真实的感知颜色,我们还必须考虑大气散射对颜色的“轻微”影响,越靠近地平线看到的影响就越大... - Spektre

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